1use crate::ast::*;
6use crate::output::Digits;
7use crate::types::{BigInt, BigRat, Numeric};
8use chrono_tz::Tz;
9use std::iter::Peekable;
10use std::str::Chars;
11
12#[derive(Debug, Clone)]
13pub enum Token {
14 Newline,
15 Comment(usize),
16 Ident(String),
17 Decimal(String, Option<String>, Option<String>),
18 Hex(String),
19 Oct(String),
20 Bin(String),
21 Quote(String),
22 Slash,
23 Pipe,
24 Semicolon,
25 Equals,
26 Caret,
27 Eof,
28 LPar,
29 RPar,
30 Plus,
31 Minus,
32 Asterisk,
33 DashArrow,
34 Colon,
35 DoubleLAngle,
36 DoubleRAngle,
37 KeywordMod,
38 KeywordXor,
39 KeywordOr,
40 KeywordAnd,
41 Date(Vec<DateToken>),
42 Comma,
43 Degree(Degree),
44 Percent,
45 Error(String),
46}
47
48fn describe(token: &Token) -> String {
49 match *token {
50 Token::Newline | Token::Comment(_) => "\\n".to_owned(),
51 Token::Ident(_) => "ident".to_owned(),
52 Token::Decimal(_, _, _) => "number".to_owned(),
53 Token::Hex(_) => "hex".to_owned(),
54 Token::Oct(_) => "octal".to_owned(),
55 Token::Bin(_) => "binary".to_owned(),
56 Token::Quote(_) => "quote".to_owned(),
57 Token::Slash => "`/`".to_owned(),
58 Token::Pipe => "`|`".to_owned(),
59 Token::Semicolon => "`;`".to_owned(),
60 Token::Equals => "`=`".to_owned(),
61 Token::Caret => "`^`".to_owned(),
62 Token::Eof => "eof".to_owned(),
63 Token::LPar => "`(`".to_owned(),
64 Token::RPar => "`)`".to_owned(),
65 Token::Plus => "`+`".to_owned(),
66 Token::Minus => "`-`".to_owned(),
67 Token::Asterisk => "`*`".to_owned(),
68 Token::DashArrow => "`->`".to_owned(),
69 Token::Colon => "`:`".to_owned(),
70 Token::DoubleLAngle => "`<<`".to_owned(),
71 Token::DoubleRAngle => "`>>`".to_owned(),
72 Token::KeywordMod => "`mod`".to_owned(),
73 Token::KeywordXor => "`xor`".to_owned(),
74 Token::KeywordOr => "`or`".to_owned(),
75 Token::KeywordAnd => "`and`".to_owned(),
76 Token::Date(_) => "date literal".to_owned(),
77 Token::Comma => "`,`".to_owned(),
78 Token::Percent => "%".to_owned(),
79 Token::Degree(ref deg) => format!("`{}`", deg),
80 Token::Error(ref e) => format!("<{}>", e),
81 }
82}
83
84#[derive(Clone)]
85pub struct TokenIterator<'a>(Peekable<Chars<'a>>);
86
87impl<'a> TokenIterator<'a> {
88 pub fn new(input: &'a str) -> TokenIterator<'a> {
89 TokenIterator(input.chars().peekable())
90 }
91}
92
93impl<'a> Iterator for TokenIterator<'a> {
94 type Item = Token;
95
96 fn next(&mut self) -> Option<Token> {
97 if self.0.peek().is_none() {
98 return Some(Token::Eof);
99 }
100 let res = match self.0.next().unwrap() {
101 ' ' | '\t' => return self.next(),
102 '\n' => Token::Newline,
103 '(' => Token::LPar,
104 ')' => Token::RPar,
105 '+' => Token::Plus,
106 ';' => Token::Semicolon,
107 '%' => Token::Percent,
108 '=' => Token::Equals,
109 '^' => Token::Caret,
110 ',' => Token::Comma,
111 '|' | '\u{2215}' => Token::Pipe,
114 ':' => Token::Colon,
115 '→' => Token::DashArrow,
116 '<' if self.0.peek().cloned() == Some('<') => {
117 self.0.next();
118 Token::DoubleLAngle
119 }
120 '>' if self.0.peek().cloned() == Some('>') => {
121 self.0.next();
122 Token::DoubleRAngle
123 }
124 '*' => {
125 if self.0.peek().cloned() == Some('*') {
126 self.0.next();
127 Token::Caret
128 } else {
129 Token::Asterisk
130 }
131 }
132 '-' => match self.0.peek().cloned() {
133 Some('>') => {
134 self.0.next();
135 Token::DashArrow
136 }
137 _ => Token::Minus,
138 },
139 '\u{2212}' => Token::Minus,
140 '/' => match self.0.peek() {
141 Some(&'/') => loop {
142 match self.0.next() {
143 None | Some('\n') => return Some(Token::Comment(1)),
144 _ => (),
145 }
146 },
147 Some(&'*') => {
148 let mut lines = 0;
149 loop {
150 if let Some(&'\n') = self.0.peek() {
151 lines += 1;
152 }
153 if let Some('*') = self.0.next() {
154 if let Some(&'/') = self.0.peek() {
155 self.0.next();
156 return Some(Token::Comment(lines));
157 }
158 }
159 if self.0.peek() == None {
160 return Some(Token::Error("Expected `*/`, got EOF".to_string()));
161 }
162 }
163 }
164 _ => Token::Slash,
165 },
166 x @ '0'..='9' | x @ '.' => {
167 if x == '0' && self.0.peek() == Some(&'x') {
168 self.0.next();
169 let mut hex = String::new();
170
171 while let Some(c) = self.0.peek().cloned() {
172 match c {
173 '0'..='9' | 'a'..='f' | 'A'..='F' => hex.push(self.0.next().unwrap()),
174 '\u{2009}' | '_' => {
175 self.0.next();
176 }
177 _ => break,
178 }
179 }
180 if hex.is_empty() {
181 return Some(Token::Error(
182 "Malformed hexadecimal literal: No digits after 0x".to_owned(),
183 ));
184 }
185 return Some(Token::Hex(hex));
186 }
187
188 if x == '0' && self.0.peek() == Some(&'o') {
189 self.0.next();
190 let mut oct = String::new();
191
192 while let Some(c) = self.0.peek().cloned() {
193 match c {
194 '0'..='7' => oct.push(self.0.next().unwrap()),
195 '\u{2009}' | '_' => {
196 self.0.next();
197 }
198 _ => break,
199 }
200 }
201 if oct.is_empty() {
202 return Some(Token::Error(
203 "Malformed octal literal: No digits after 0o".to_owned(),
204 ));
205 }
206 return Some(Token::Oct(oct));
207 }
208
209 if x == '0' && self.0.peek() == Some(&'b') {
210 self.0.next();
211 let mut bin = String::new();
212
213 while let Some(c) = self.0.peek().cloned() {
214 match c {
215 '0' | '1' => bin.push(self.0.next().unwrap()),
216 '\u{2009}' | '_' => {
217 self.0.next();
218 }
219 _ => break,
220 }
221 }
222 if bin.is_empty() {
223 return Some(Token::Error(
224 "Malformed binary literal: No digits after 0b".to_owned(),
225 ));
226 }
227 return Some(Token::Bin(bin));
228 }
229
230 let mut integer = String::new();
231 let mut frac = None;
232 let mut exp = None;
233
234 if x != '.' {
236 integer.push(x);
237 while let Some(c) = self.0.peek().cloned() {
238 match c {
239 '0'..='9' => integer.push(self.0.next().unwrap()),
240 '\u{2009}' | '_' => {
241 self.0.next();
242 }
243 _ => break,
244 }
245 }
246 } else {
247 integer.push('0');
248 }
249 if x == '.' || Some('.') == self.0.peek().cloned() {
251 let mut buf = String::new();
252 if x != '.' {
253 self.0.next();
254 }
255 while let Some(c) = self.0.peek().cloned() {
256 match c {
257 '0'..='9' => buf.push(self.0.next().unwrap()),
258 '\u{2009}' | '_' => {
259 self.0.next();
260 }
261 _ => break,
262 }
263 }
264 if buf.is_empty() {
265 return Some(Token::Error(
266 "Malformed number literal: No digits after decimal point".to_owned(),
267 ));
268 }
269 frac = Some(buf)
270 }
271 if let Some('e') = self.0.peek().cloned().map(|x| x.to_ascii_lowercase()) {
273 let mut buf = String::new();
274 self.0.next();
275 if let Some('e') = self.0.peek().cloned().map(|x| x.to_ascii_lowercase()) {
276 self.0.next();
277 }
278 if let Some(c) = self.0.peek().cloned() {
279 match c {
280 '-' => {
281 buf.push(self.0.next().unwrap());
282 }
283 '+' => {
284 self.0.next();
285 }
286 _ => (),
287 }
288 }
289 while let Some(c) = self.0.peek().cloned() {
290 match c {
291 '0'..='9' => buf.push(self.0.next().unwrap()),
292 '\u{2009}' | '_' => {
293 self.0.next();
294 }
295 _ => break,
296 }
297 }
298 if buf.is_empty() {
299 return Some(Token::Error(
300 "Malformed number literal: No digits after exponent".to_owned(),
301 ));
302 }
303 exp = Some(buf)
304 }
305 Token::Decimal(integer, frac, exp)
306 }
307 '\\' => match self.0.next() {
308 Some('u') => {
309 let mut buf = String::new();
310 while let Some(c) = self.0.peek().cloned() {
311 if c.is_digit(16) {
312 buf.push(self.0.next().unwrap());
313 } else {
314 break;
315 }
316 }
317 let v = u32::from_str_radix(&*buf, 16).unwrap();
318 if let Some(c) = ::std::char::from_u32(v) {
319 let mut buf = String::new();
320 buf.push(c);
321 Token::Ident(buf)
322 } else {
323 Token::Error(format!("Invalid unicode scalar: {:x}", v))
324 }
325 }
326 _ => Token::Error("Unexpected \\".to_string()),
327 },
328 '\'' => {
329 let mut buf = String::new();
330 loop {
331 match self.0.next() {
332 None | Some('\n') => {
333 return Some(Token::Error("Unexpected newline or EOF".to_string()))
334 }
335 Some('\\') => match self.0.next() {
336 Some('\'') => buf.push('\''),
337 Some('n') => buf.push('\n'),
338 Some('t') => buf.push('\t'),
339 Some(c) => {
340 return Some(Token::Error(format!(
341 "Invalid escape sequence \\{}",
342 c
343 )))
344 }
345 None => return Some(Token::Error("Unexpected EOF".to_string())),
346 },
347 Some('\'') => break,
348 Some(c) => buf.push(c),
349 }
350 }
351 Token::Quote(buf)
352 }
353 '#' => {
354 let mut toks = vec![];
355 while self.0.peek().is_some() {
356 let res = match self.0.next().unwrap() {
357 '#' => break,
358 ':' => DateToken::Colon,
359 '-' => DateToken::Dash,
360 '+' => DateToken::Plus,
361 x if x.is_whitespace() => {
362 while self.0.peek().map(|c| c.is_whitespace()).unwrap_or(false) {
363 self.0.next();
364 }
365 DateToken::Space
366 }
367 x if x.is_digit(10) => {
368 let mut integer = String::new();
369 integer.push(x);
370 while let Some(c) = self.0.peek().cloned() {
371 if c.is_digit(10) {
372 self.0.next();
373 integer.push(c);
374 } else {
375 break;
376 }
377 }
378 let frac = if let Some('.') = self.0.peek().cloned() {
379 let mut frac = String::new();
380 self.0.next();
381 while let Some(c) = self.0.peek().cloned() {
382 if c.is_digit(10) {
383 self.0.next();
384 frac.push(c);
385 } else {
386 break;
387 }
388 }
389 Some(frac)
390 } else {
391 None
392 };
393 DateToken::Number(integer, frac)
394 }
395 x => {
396 let mut buf = String::new();
397 buf.push(x);
398 while let Some(c) = self.0.peek().cloned() {
399 if !"#:-+ ".contains(c) && !c.is_digit(10) {
400 self.0.next();
401 buf.push(c);
402 } else {
403 break;
404 }
405 }
406 DateToken::Literal(buf)
407 } };
409 toks.push(res);
410 }
411 if let Some(&DateToken::Space) = toks.first() {
412 toks.remove(0);
413 }
414 if let Some(&DateToken::Space) = toks.last() {
415 toks.pop();
416 }
417 Token::Date(toks)
418 }
419 '"' => {
420 let mut buf = String::new();
421 while let Some(c) = self.0.next() {
422 if c == '\\' {
423 if let Some(c) = self.0.next() {
424 buf.push(c);
425 }
426 } else if c == '"' {
427 break;
428 } else {
429 buf.push(c);
430 }
431 }
432 Token::Ident(buf)
433 }
434 x => {
435 let mut buf = String::new();
436 buf.push(x);
437 while let Some(c) = self.0.peek().cloned() {
438 if c.is_alphanumeric() || c == '_' || c == '$' {
439 buf.push(self.0.next().unwrap());
440 } else {
441 break;
442 }
443 }
444 match &*buf {
445 "degC" | "°C" | "celsius" | "℃" => Token::Degree(Degree::Celsius),
446 "degF" | "°F" | "fahrenheit" | "℉" => Token::Degree(Degree::Fahrenheit),
447 "degRé" | "°Ré" | "degRe" | "°Re" | "réaumur" | "reaumur" => {
448 Token::Degree(Degree::Reaumur)
449 }
450 "degRø" | "°Rø" | "degRo" | "°Ro" | "rømer" | "romer" => {
451 Token::Degree(Degree::Romer)
452 }
453 "degDe" | "°De" | "delisle" => Token::Degree(Degree::Delisle),
454 "degN" | "°N" | "degnewton" => Token::Degree(Degree::Newton),
455 "per" => Token::Slash,
456 "to" | "in" => Token::DashArrow,
457 "mod" => Token::KeywordMod,
458 "and" => Token::KeywordAnd,
459 "or" => Token::KeywordOr,
460 "xor" => Token::KeywordXor,
461 _ => Token::Ident(buf),
462 }
463 }
464 };
465 Some(res)
466 }
467}
468
469pub type Iter<'a> = Peekable<TokenIterator<'a>>;
470
471fn attr_from_name(name: &str) -> Option<&'static str> {
472 match name {
473 "int" | "international" => Some("int"),
474 "UKSJJ" => Some("UKSJJ"),
475 "UKB" => Some("UKB"),
476 "UKC" => Some("UKC"),
477 "UKK" => Some("UKK"),
478 "imperial" | "british" | "UK" => Some("br"),
479 "survey" | "geodetic" => Some("survey"),
480 "irish" => Some("irish"),
481 "aust" | "australian" => Some("aust"),
482 "roman" => Some("roman"),
483 "egyptian" => Some("egyptian"),
484 "greek" => Some("greek"),
485 "olympic" => Some("olympic"),
486 _ => None,
487 }
488}
489
490fn parse_function(iter: &mut Iter<'_>, func: Function) -> Expr {
491 let args = match iter.peek().cloned().unwrap() {
492 Token::LPar => {
493 iter.next();
494 let mut args = vec![];
495 loop {
496 if let Some(&Token::RPar) = iter.peek() {
497 iter.next();
498 break;
499 }
500 args.push(parse_expr(iter));
501 match iter.peek().cloned().unwrap() {
502 Token::Comma => {
503 iter.next();
504 }
505 Token::RPar => (),
506 x => {
507 return Expr::new_error(format!(
508 "Expected `,` or `)`, got {}",
509 describe(&x)
510 ))
511 }
512 }
513 }
514 args
515 }
516 _ => vec![parse_pow(iter)],
517 };
518 Expr::new_call(func, args)
519}
520
521fn parse_radix(num: &str, base: u32, description: &str) -> Expr {
522 BigInt::from_str_radix(num, base)
523 .map(|x| BigRat::ratio(&x, &BigInt::one()))
524 .map(Numeric::Rational)
525 .map(Expr::new_const)
526 .unwrap_or_else(|_| Expr::new_error(format!("Failed to parse {}", description)))
527}
528
529fn parse_term(iter: &mut Iter<'_>) -> Expr {
530 match iter.next().unwrap() {
531 Token::Ident(ref id) => {
532 if let Some(func) = Function::from_name(id) {
533 parse_function(iter, func)
534 } else if let Some(attr) = attr_from_name(id) {
535 match iter.peek().cloned().unwrap() {
536 Token::Ident(ref name) => {
537 iter.next();
538 Expr::new_unit(format!("{}{}", attr, name))
539 }
540 x => Expr::new_error(format!(
541 "Attribute must be followed by ident, got {}",
542 describe(&x)
543 )),
544 }
545 } else {
546 match iter.peek().cloned().unwrap() {
547 Token::Ident(ref s) if s == "of" => {
548 iter.next();
549 Expr::new_of(id, parse_juxt(iter))
550 }
551 _ => Expr::new_unit(id.to_string()),
552 }
553 }
554 }
555 Token::Quote(string) => Expr::Quote { string },
556 Token::Decimal(num, frac, exp) => crate::types::Number::from_parts(
557 &*num,
558 frac.as_ref().map(|x| &**x),
559 exp.as_ref().map(|x| &**x),
560 )
561 .map(Expr::new_const)
562 .unwrap_or_else(Expr::new_error),
563 Token::Hex(num) => parse_radix(&*num, 16, "hex"),
564 Token::Oct(num) => parse_radix(&*num, 8, "octal"),
565 Token::Bin(num) => parse_radix(&*num, 2, "binary"),
566 Token::Plus => Expr::new_plus(parse_term(iter)),
567 Token::Minus => Expr::new_negate(parse_term(iter)),
568 Token::LPar => {
569 let res = parse_expr(iter);
570 match iter.next().unwrap() {
571 Token::RPar => res,
572 x => Expr::new_error(format!("Expected `)`, got {}", describe(&x))),
573 }
574 }
575 Token::Percent => Expr::new_unit("percent".to_owned()),
576 Token::Date(tokens) => Expr::Date { tokens },
577 Token::Comment(_) => parse_term(iter),
578 x => Expr::new_error(format!("Expected term, got {}", describe(&x))),
579 }
580}
581
582fn parse_suffix(iter: &mut Iter<'_>) -> Expr {
583 let left = parse_term(iter);
584 match *iter.peek().unwrap() {
585 Token::Percent => {
586 let mut left = left;
587 while let Some(&Token::Percent) = iter.peek() {
588 iter.next();
589 left = Expr::new_mul(vec![left, Expr::new_unit("percent".to_owned())]);
590 }
591 left
592 }
593 _ => left,
594 }
595}
596
597fn parse_pow(iter: &mut Iter<'_>) -> Expr {
598 let left = parse_suffix(iter);
599 match *iter.peek().unwrap() {
600 Token::Caret => {
601 iter.next();
602 let right = parse_pow(iter);
603 Expr::new_pow(left, right)
604 }
605 _ => left,
606 }
607}
608
609fn parse_frac(iter: &mut Iter<'_>) -> Expr {
610 let left = parse_pow(iter);
611 match *iter.peek().unwrap() {
612 Token::Pipe => {
613 iter.next();
614 let right = parse_pow(iter);
615 Expr::new_frac(left, right)
616 }
617 _ => left,
618 }
619}
620
621fn parse_juxt(iter: &mut Iter<'_>) -> Expr {
622 let mut terms = vec![parse_frac(iter)];
623 loop {
624 match iter.peek().cloned().unwrap() {
625 Token::Asterisk
626 | Token::Slash
627 | Token::Comma
628 | Token::Equals
629 | Token::Plus
630 | Token::Minus
631 | Token::DashArrow
632 | Token::RPar
633 | Token::Newline
634 | Token::DoubleLAngle
635 | Token::DoubleRAngle
636 | Token::KeywordMod
637 | Token::KeywordAnd
638 | Token::KeywordOr
639 | Token::KeywordXor
640 | Token::Comment(_)
641 | Token::Eof => break,
642 Token::Degree(deg) => {
643 iter.next();
644 terms = vec![Expr::new_suffix(deg, Expr::new_mul(terms))]
645 }
646 _ => terms.push(parse_frac(iter)),
647 }
648 }
649 if terms.len() == 1 {
650 terms.pop().unwrap()
651 } else {
652 Expr::new_mul(terms)
653 }
654}
655
656fn parse_div(iter: &mut Iter<'_>) -> Expr {
657 let mut terms = vec![parse_juxt(iter)];
658 loop {
659 match iter.peek().cloned().unwrap() {
660 Token::Slash => {
661 iter.next();
662 let left = Expr::new_mul(terms.drain(..).collect());
663 terms = vec![Expr::new_frac(left, parse_juxt(iter))];
664 }
665 Token::Asterisk => {
666 iter.next();
667 terms.push(parse_juxt(iter));
668 }
669 Token::DoubleLAngle => {
670 iter.next();
671 let left = Expr::new_mul(terms.drain(..).collect());
672 terms = vec![Expr::new_bin(BinOpType::ShiftL, left, parse_juxt(iter))];
673 }
674 Token::DoubleRAngle => {
675 iter.next();
676 let left = Expr::new_mul(terms.drain(..).collect());
677 terms = vec![Expr::new_bin(BinOpType::ShiftR, left, parse_juxt(iter))];
678 }
679 Token::KeywordMod => {
680 iter.next();
681 let left = Expr::new_mul(terms.drain(..).collect());
682 terms = vec![Expr::new_bin(BinOpType::Mod, left, parse_juxt(iter))];
683 }
684 Token::KeywordAnd => {
685 iter.next();
686 let left = Expr::new_mul(terms.drain(..).collect());
687 terms = vec![Expr::new_bin(BinOpType::And, left, parse_juxt(iter))];
688 }
689 Token::KeywordOr => {
690 iter.next();
691 let left = Expr::new_mul(terms.drain(..).collect());
692 terms = vec![Expr::new_bin(BinOpType::Or, left, parse_juxt(iter))];
693 }
694 Token::KeywordXor => {
695 iter.next();
696 let left = Expr::new_mul(terms.drain(..).collect());
697 terms = vec![Expr::new_bin(BinOpType::Xor, left, parse_juxt(iter))];
698 }
699 _ => break,
700 }
701 }
702 if terms.len() == 1 {
703 terms.pop().unwrap()
704 } else {
705 Expr::new_mul(terms)
706 }
707}
708
709fn parse_add(iter: &mut Iter<'_>) -> Expr {
710 let mut left = parse_div(iter);
711 loop {
712 match *iter.peek().unwrap() {
713 Token::Plus => {
714 iter.next();
715 let right = parse_div(iter);
716 left = Expr::new_add(left, right)
717 }
718 Token::Minus => {
719 iter.next();
720 let right = parse_div(iter);
721 left = Expr::new_sub(left, right)
722 }
723 _ => return left,
724 }
725 }
726}
727
728fn parse_eq(iter: &mut Iter<'_>) -> Expr {
729 let left = parse_add(iter);
730 match iter.peek().cloned().unwrap() {
731 Token::Equals => {
732 iter.next();
733 let right = parse_add(iter);
734 Expr::new_equals(left, right)
735 }
736 _ => left,
737 }
738}
739
740pub fn parse_expr(iter: &mut Iter<'_>) -> Expr {
741 parse_eq(iter)
742}
743
744pub fn parse_unitlist(iter: &mut Iter<'_>) -> Option<Vec<String>> {
745 let mut expecting_term = true;
746 let mut res = vec![];
747 loop {
748 match iter.next().unwrap() {
749 Token::Ident(ref ident) if expecting_term => {
750 res.push(ident.clone());
751 expecting_term = false;
752 }
753 Token::Comma | Token::Semicolon if !expecting_term => {
754 expecting_term = true;
755 }
756 Token::Eof | Token::Newline | Token::Comment(_) if !expecting_term => break,
757 _ => return None,
758 }
759 }
760 if res.len() > 1 {
761 Some(res)
762 } else {
763 None
764 }
765}
766
767pub fn parse_offset(iter: &mut Iter<'_>) -> Option<i64> {
768 use std::str::FromStr;
769
770 let sign = match iter.next().unwrap() {
771 Token::Plus => 1,
772 Token::Minus => -1,
773 _ => return None,
774 };
775 let hour = match iter.next().unwrap() {
776 Token::Decimal(ref i, None, None) if i.len() == 2 => i.clone(),
777 _ => return None,
778 };
779 match iter.next().unwrap() {
780 Token::Colon => (),
781 _ => return None,
782 }
783 let min = match iter.next().unwrap() {
784 Token::Decimal(ref i, None, None) if i.len() == 2 => i.clone(),
785 _ => return None,
786 };
787 Some(sign * (i64::from_str(&*hour).unwrap() * 3600 + i64::from_str(&*min).unwrap() * 60))
788}
789
790pub fn parse_query(iter: &mut Iter<'_>) -> Query {
791 match iter.peek().cloned() {
792 Some(Token::Ident(ref s)) if s == "factorize" => {
793 iter.next();
794 return Query::Factorize(parse_eq(iter));
795 }
796 Some(Token::Ident(ref s)) if s == "units" => {
797 iter.next();
798 if let Some(Token::Ident(ref s)) = iter.peek().cloned() {
799 if s == "for" || s == "of" {
800 iter.next();
801 }
802 }
803 return Query::UnitsFor(parse_eq(iter));
804 }
805 Some(Token::Ident(ref s)) if s == "search" => {
806 iter.next();
807 if let Some(Token::Ident(ref s)) = iter.peek().cloned() {
808 return Query::Search(s.clone());
809 }
810 }
811 _ => (),
812 }
813 let left = parse_eq(iter);
814 match iter.peek().cloned().unwrap() {
815 Token::DashArrow => {
816 use std::str::FromStr;
817 iter.next();
818 let mut copy = iter.clone();
819 if let Some(res) = parse_unitlist(&mut copy) {
820 *iter = copy;
821 return Query::Convert(left, Conversion::List(res), None, Digits::Default);
822 }
823 let digits = match iter.peek().cloned().unwrap() {
824 Token::Ident(ref s) if s == "digits" => {
825 iter.next();
826 match iter.peek().cloned() {
827 Some(Token::Decimal(int, None, None)) => {
828 iter.next();
829 match u64::from_str_radix(&*int, 10) {
830 Ok(v) => Digits::Digits(v),
831 Err(e) => {
832 return Query::Error(format!("Failed to parse digits: {}", e))
833 }
834 }
835 }
836 _ => Digits::FullInt,
837 }
838 }
839 _ => Digits::Default,
840 };
841 let base = match iter.peek().cloned().unwrap() {
842 Token::Ident(ref s) if s == "base" => {
843 iter.next();
844 match iter.next() {
845 Some(Token::Decimal(int, None, None)) => {
846 match u64::from_str_radix(&*int, 10) {
847 Ok(v @ 2..=36) => Some(v as u8),
848 Ok(v) => {
849 return Query::Error(format!(
850 "Unsupported base {}, must be from 2 to 36",
851 v
852 ))
853 }
854 Err(e) => {
855 return Query::Error(format!("Failed to parse base: {}", e))
856 }
857 }
858 }
859 Some(x) => {
860 return Query::Error(format!(
861 "Expected decimal base, got {}",
862 describe(&x)
863 ))
864 }
865 None => return Query::Error("Expected decimal base, got eof".to_string()),
866 }
867 }
868 Token::Ident(ref s) if s == "hex" || s == "hexadecimal" || s == "base16" => {
869 iter.next();
870 Some(16)
871 }
872 Token::Ident(ref s) if s == "oct" || s == "octal" || s == "base8" => {
873 iter.next();
874 Some(8)
875 }
876 Token::Ident(ref s) if s == "bin" || s == "binary" || s == "base2" => {
877 iter.next();
878 Some(2)
879 }
880 _ => None,
881 };
882 let right = match iter.peek().cloned().unwrap() {
883 Token::Eof => Conversion::None,
884 Token::Degree(deg) => Conversion::Degree(deg),
885 Token::Plus | Token::Minus => {
886 let mut old = iter.clone();
887 if let Some(off) = parse_offset(iter) {
888 Conversion::Offset(off)
889 } else {
890 Conversion::Expr(parse_eq(&mut old))
891 }
892 }
893 Token::Ident(ref s) if is_valid_timezone(s) => Conversion::Timezone(
894 Tz::from_str(s).expect("Running from_str a second time failed"),
895 ),
896 _ => Conversion::Expr(parse_eq(iter)),
897 };
898 Query::Convert(left, right, base, digits)
899 }
900 _ => Query::Expr(left),
901 }
902}
903
904fn is_valid_timezone(s: &String) -> bool {
905 use std::str::FromStr;
906 s != "GB" && Tz::from_str(s).is_ok()
907}
908
909#[cfg(test)]
910mod test {
911 use super::*;
912
913 fn parse(input: &str) -> String {
914 parse_expr(&mut TokenIterator::new(input).peekable()).to_string()
915 }
916
917 #[test]
918 fn add_assoc() {
919 assert_eq!(parse("a + b - c + d - e"), "(((a + b) - c) + d) - e");
920 }
921
922 #[test]
923 fn sub_crash_regression() {
924 assert_eq!(parse("-"), "-<error: Expected term, got eof>");
925 }
926
927 #[test]
928 fn mul_assoc() {
929 assert_eq!(
930 parse("a b * c / d / e f * g h"),
931 "(((a b) c / d) / e f) (g h)"
932 );
933 assert_eq!(parse("a|b c / g e|f"), "(a / b) c / g (e / f)");
934 assert_eq!(parse("a / b / c"), "(a / b) / c");
935 }
936
937 #[test]
938 fn parse_extra_ops() {
939 assert_eq!(parse("a b mod c d"), "a b mod c d");
940 assert_eq!(parse("a b << c d"), "a b << c d");
941 assert_eq!(parse("a b >> c d"), "a b >> c d");
942 assert_eq!(parse("a b and c d"), "a b and c d");
943 assert_eq!(parse("a b or c d"), "a b or c d");
944 assert_eq!(parse("a b xor c d"), "a b xor c d");
945 assert_eq!(parse("a / b c mod d e / f"), "((a / b c) mod d e) / f");
946 }
947
948 #[test]
949 fn suffix_prec() {
950 assert_eq!(parse("a b °C + x y °F"), "a b °C + x y °F");
951 assert_eq!(parse("a b °C c"), "(a b °C) c");
952 assert_eq!(parse("a °C / x"), "a °C / x");
953 assert_eq!(parse("a °C * x"), "(a °C) x");
954 }
955
956 #[test]
957 fn number_lex() {
958 assert_eq!(
959 parse("1e"),
960 "<error: Expected term, got <Malformed number literal: No digits after exponent>>"
961 );
962 assert_eq!(
963 parse("1."),
964 "<error: Expected term, got <Malformed number literal: No digits after decimal point>>"
965 );
966 }
967
968 #[test]
969 fn mono_unit_list() {
970 use crate::ast::*;
971 match parse_query(&mut TokenIterator::new("foo -> bar").peekable()) {
972 Query::Convert(_, Conversion::Expr(_), _, _) => (),
973 x => panic!("Expected Convert(_, Expr(_), _), got {:?}", x),
974 }
975 }
976
977 #[test]
978 fn test_of() {
979 assert_eq!(parse("foo of 1 abc def / 12"), "(foo of 1 abc def) / 12");
980 }
981}