|
1 | | -use crate::exp::Exp; |
| 1 | +use crate::exp::{str_to_principal, Exp}; |
| 2 | +use crate::token::{Token, Tokenizer}; |
2 | 3 | use ansi_term::Color; |
3 | 4 | use candid::{ |
4 | 5 | check_prog, |
@@ -145,52 +146,62 @@ enum Partial { |
145 | 146 |
|
146 | 147 | fn partial_parse(line: &str, pos: usize, helper: &MyHelper) -> Option<(usize, Partial)> { |
147 | 148 | let (start, _) = extract_word(line, pos, None, b" "); |
148 | | - let prev = &line[..start].trim_end(); |
149 | | - let (_, prev) = extract_word(prev, prev.len(), None, b" "); |
150 | | - let is_call = matches!(prev, "call" | "encode"); |
151 | | - if is_call { |
152 | | - let pos_tail = line[start..pos] |
153 | | - .rfind('.') |
154 | | - .map(|v| start + v) |
155 | | - .unwrap_or(pos); |
156 | | - let tail = if pos_tail < pos { |
157 | | - line[pos_tail + 1..pos].to_string() |
| 149 | + let iter = Tokenizer::new(&line[start..pos]); |
| 150 | + let mut tokens = Vec::new(); |
| 151 | + let mut pos_start = 0; |
| 152 | + for v in iter { |
| 153 | + let v = v.ok()?; |
| 154 | + if pos_start == 0 |
| 155 | + && matches!( |
| 156 | + v.1, |
| 157 | + Token::Equals | Token::TestEqual | Token::SubEqual | Token::NotEqual |
| 158 | + ) |
| 159 | + { |
| 160 | + pos_start = v.2; |
| 161 | + } |
| 162 | + let tok = if let Token::Text(id) = v.1 { |
| 163 | + Token::Id(id) |
158 | 164 | } else { |
159 | | - String::new() |
| 165 | + v.1 |
160 | 166 | }; |
161 | | - let id = &line[start..pos_tail]; |
162 | | - if id.starts_with('"') { |
163 | | - if id.len() >= 7 { |
164 | | - let id = Principal::from_text(&id[1..id.len() - 1]).ok()?; |
165 | | - Some((pos_tail, Partial::Call(id, tail))) |
166 | | - } else { |
167 | | - None |
168 | | - } |
169 | | - } else { |
170 | | - match helper.env.0.get(id)? { |
171 | | - IDLValue::Principal(id) => Some((pos_tail, Partial::Call(id.clone(), tail))), |
172 | | - _ => None, |
| 167 | + tokens.push((v.0, tok)); |
| 168 | + } |
| 169 | + match tokens.as_slice() { |
| 170 | + [(_, Token::Id(id))] => match str_to_principal(id, helper) { |
| 171 | + Ok(id) => Some((pos, Partial::Call(id, "".to_string()))), |
| 172 | + Err(_) => parse_value(&line[..pos], start, pos, helper), |
| 173 | + }, |
| 174 | + [(_, Token::Id(id)), (pos_tail, Token::Dot)] |
| 175 | + | [(_, Token::Id(id)), (pos_tail, Token::Dot), (_, _)] => { |
| 176 | + match str_to_principal(id, helper) { |
| 177 | + Ok(id) => Some(( |
| 178 | + start + pos_tail, |
| 179 | + Partial::Call(id, line[start + pos_tail + 1..pos].to_string()), |
| 180 | + )), |
| 181 | + Err(_) => parse_value(&line[..pos], start + pos_start, start + pos_tail, helper), |
173 | 182 | } |
174 | 183 | } |
175 | | - } else { |
176 | | - let pos_tail = if line[..pos].ends_with(']') { |
177 | | - pos |
178 | | - } else { |
179 | | - line[start..pos] |
180 | | - .rfind(|c| c == '.' || c == '[' || c == ']') |
181 | | - .map(|v| start + v) |
182 | | - .unwrap_or(pos) |
183 | | - }; |
184 | | - let v = line[start..pos_tail].parse::<Exp>().ok()?; |
185 | | - let v = v.eval(helper).ok()?; |
186 | | - let tail = if pos_tail < pos { |
187 | | - line[pos_tail..pos].to_string() |
188 | | - } else { |
189 | | - String::new() |
190 | | - }; |
191 | | - Some((pos_tail, Partial::Val(v, tail))) |
| 184 | + [.., (_, Token::RSquare)] | [.., (_, Token::Question)] => { |
| 185 | + parse_value(&line[..pos], start + pos_start, pos, helper) |
| 186 | + } |
| 187 | + [.., (pos_tail, Token::Dot)] |
| 188 | + | [.., (pos_tail, Token::Dot), (_, _)] |
| 189 | + | [.., (pos_tail, Token::LSquare)] |
| 190 | + | [.., (pos_tail, Token::LSquare), (_, Token::Decimal(_))] => { |
| 191 | + parse_value(&line[..pos], start + pos_start, start + pos_tail, helper) |
| 192 | + } |
| 193 | + _ => None, |
192 | 194 | } |
193 | 195 | } |
| 196 | +fn parse_value( |
| 197 | + line: &str, |
| 198 | + start: usize, |
| 199 | + end: usize, |
| 200 | + helper: &MyHelper, |
| 201 | +) -> Option<(usize, Partial)> { |
| 202 | + let v = line[start..end].parse::<Exp>().ok()?.eval(helper).ok()?; |
| 203 | + Some((end, Partial::Val(v, line[end..].to_string()))) |
| 204 | +} |
194 | 205 | fn match_selector(v: &IDLValue, prefix: &str) -> Vec<Pair> { |
195 | 206 | match v { |
196 | 207 | IDLValue::Opt(_) => vec![Pair { |
@@ -399,7 +410,7 @@ fn test_partial_parse() -> anyhow::Result<()> { |
399 | 410 | .env |
400 | 411 | .0 |
401 | 412 | .insert("ic0".to_string(), IDLValue::Principal(ic0.clone())); |
402 | | - assert_eq!(partial_parse("call a", 6, &helper), None); |
| 413 | + assert_eq!(partial_parse("call x", 6, &helper), None); |
403 | 414 | assert_eq!( |
404 | 415 | partial_parse("let id = call \"aaaaa-aa\"", 24, &helper).unwrap(), |
405 | 416 | (24, Partial::Call(ic0.clone(), "".to_string())) |
@@ -437,19 +448,19 @@ fn test_partial_parse() -> anyhow::Result<()> { |
437 | 448 | ); |
438 | 449 | assert_eq!(partial_parse("let id = a.f1.", 14, &helper), None); |
439 | 450 | assert_eq!( |
440 | | - partial_parse("let id = a?", 11, &helper).unwrap(), |
| 451 | + partial_parse("let id =a?", 10, &helper).unwrap(), |
441 | 452 | ( |
442 | | - 11, |
| 453 | + 10, |
443 | 454 | Partial::Val( |
444 | 455 | "record { variant {b=vec{1;2;3}}; 42; f1=42;42=35;a1=30}".parse::<IDLValue>()?, |
445 | 456 | "".to_string() |
446 | 457 | ) |
447 | 458 | ) |
448 | 459 | ); |
449 | 460 | assert_eq!( |
450 | | - partial_parse("let id = a?.", 12, &helper).unwrap(), |
| 461 | + partial_parse("let id=a?.", 10, &helper).unwrap(), |
451 | 462 | ( |
452 | | - 11, |
| 463 | + 9, |
453 | 464 | Partial::Val( |
454 | 465 | "record { variant {b=vec{1;2;3}}; 42; f1=42;42=35;a1=30}".parse::<IDLValue>()?, |
455 | 466 | ".".to_string() |
|
0 commit comments