1use crate::ast::*;
6use crate::types::Numeric;
7use std::collections::BTreeMap;
8use std::iter::Peekable;
9use std::rc::Rc;
10use std::str::Chars;
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum Token {
14 Eof,
15 Newline,
16 Doc(String),
17 Ident(String),
18 Number(String, Option<String>, Option<String>),
19 LPar,
20 RPar,
21 Bang,
22 Slash,
23 Pipe,
24 Caret,
25 Plus,
26 Dash,
27 Asterisk,
28 Question,
29 LeftBrace,
30 RightBrace,
31 Error(String),
32}
33
34#[derive(Clone)]
35pub struct TokenIterator<'a>(Peekable<Chars<'a>>);
36
37impl<'a> TokenIterator<'a> {
38 pub fn new(input: &'a str) -> TokenIterator<'a> {
39 TokenIterator(input.chars().peekable())
40 }
41}
42
43fn is_ident(c: char) -> bool {
44 match c {
45 ' ' | '\t' | '\n' | '\r' | '(' | ')' | '/' | '|' | '^' | '+' | '*' | '\\' | '#' => false,
48 _ => true,
49 }
50}
51
52impl<'a> Iterator for TokenIterator<'a> {
53 type Item = Token;
54
55 fn next(&mut self) -> Option<Token> {
56 if self.0.peek().is_none() {
57 return Some(Token::Eof);
58 }
59 let res = match self.0.next().unwrap() {
60 ' ' | '\t' => return self.next(),
61 '\r' => {
62 if self.0.peek() == Some(&'\n') {
63 self.0.next();
64 Token::Newline
65 } else {
66 Token::Newline
67 }
68 }
69 '\n' => Token::Newline,
70 '!' => Token::Bang,
71 '(' => Token::LPar,
72 ')' => Token::RPar,
73 '/' => Token::Slash,
74 '|' => Token::Pipe,
75 '^' => Token::Caret,
76 '-' => Token::Dash,
77 '+' => Token::Plus,
78 '*' => Token::Asterisk,
79 '{' => Token::LeftBrace,
80 '}' => Token::RightBrace,
81 '?' => {
82 if self.0.peek() == Some(&'?') {
83 self.0.next();
84 let mut out = String::new();
85 loop {
86 match self.0.next() {
87 Some('\n') | None => break,
88 Some(x) => out.push(x),
89 }
90 }
91 Token::Doc(out)
92 } else {
93 Token::Question
94 }
95 }
96 '\\' => match self.0.next() {
97 Some('\r') => match self.0.next() {
98 Some('\n') => self.next().unwrap(),
99 _ => Token::Error("Expected LF or CRLF line endings".to_string()),
100 },
101 Some('\n') => self.next().unwrap(),
102 Some(x) => Token::Error(format!("Invalid escape: \\{}", x)),
103 None => Token::Error("Unexpected EOF".to_string()),
104 },
105 '#' => {
106 for c in self.0.by_ref() {
107 if c == '\n' {
108 break;
109 }
110 }
111 Token::Newline
112 }
113 x @ '0'..='9' | x @ '.' => {
114 let mut integer = String::new();
115 let mut frac = None;
116 let mut exp = None;
117
118 if x != '.' {
120 integer.push(x);
121 while let Some('0'..='9') = self.0.peek().cloned() {
122 integer.push(self.0.next().unwrap());
123 }
124 } else {
125 integer.push('0');
126 }
127 if x == '.' || Some('.') == self.0.peek().cloned() {
129 let mut buf = String::new();
130 if x != '.' {
131 self.0.next();
132 }
133 while let Some('0'..='9') = self.0.peek().cloned() {
134 buf.push(self.0.next().unwrap());
135 }
136 if !buf.is_empty() {
137 frac = Some(buf)
138 }
139 }
140 if let Some('e') = self.0.peek().cloned().map(|x| x.to_ascii_lowercase()) {
142 let mut buf = String::new();
143 self.0.next();
144 if let Some(c) = self.0.peek().cloned() {
145 match c {
146 '-' => {
147 buf.push(self.0.next().unwrap());
148 }
149 '+' => {
150 self.0.next();
151 }
152 _ => (),
153 }
154 }
155 while let Some('0'..='9') = self.0.peek().cloned() {
156 buf.push(self.0.next().unwrap());
157 }
158 if !buf.is_empty() {
159 exp = Some(buf)
160 }
161 }
162 Token::Number(integer, frac, exp)
163 }
164 '"' => {
165 let mut buf = String::new();
166 while let Some(c) = self.0.next() {
167 if c == '\\' {
168 if let Some(c) = self.0.next() {
169 buf.push(c);
170 }
171 } else if c == '"' {
172 break;
173 } else {
174 buf.push(c);
175 }
176 }
177 Token::Ident(buf)
178 }
179 x => {
180 assert!(is_ident(x));
184 let mut buf = String::new();
185 buf.push(x);
186 while let Some(c) = self.0.peek().cloned() {
187 if is_ident(c) || c.is_numeric() {
188 buf.push(self.0.next().unwrap());
189 } else {
190 break;
191 }
192 }
193 Token::Ident(buf)
194 }
195 };
196 Some(res)
197 }
198}
199
200pub type Iter<'a> = Peekable<TokenIterator<'a>>;
201
202fn parse_term(iter: &mut Iter<'_>) -> Expr {
203 match iter.next().unwrap() {
204 Token::Ident(name) => match iter.peek().cloned().unwrap() {
205 Token::Ident(ref s) if s == "of" => {
206 iter.next();
207 Expr::Of {
208 property: name,
209 expr: Box::new(parse_mul(iter)),
210 }
211 }
212 _ => Expr::new_unit(name),
213 },
214 Token::Number(num, frac, exp) => Numeric::from_parts(
215 &*num,
216 frac.as_ref().map(|x| &**x),
217 exp.as_ref().map(|x| &**x),
218 )
219 .map(Expr::new_const)
220 .unwrap_or_else(Expr::new_error),
221 Token::Plus => Expr::new_plus(parse_term(iter)),
222 Token::Dash => Expr::new_negate(parse_term(iter)),
223 Token::Slash => Expr::new_frac(Expr::new_const(Numeric::one()), parse_term(iter)),
224 Token::LPar => {
225 let res = parse_expr(iter);
226 match iter.next().unwrap() {
227 Token::RPar => res,
228 x => Expr::new_error(format!("Expected ), got {:?}", x)),
229 }
230 }
231 x => Expr::new_error(format!("Expected term, got {:?}", x)),
232 }
233}
234
235fn parse_pow(iter: &mut Iter<'_>) -> Expr {
236 let left = parse_term(iter);
237 match *iter.peek().unwrap() {
238 Token::Caret => {
239 iter.next();
240 let right = parse_pow(iter);
241 Expr::BinOp(BinOpExpr {
242 op: BinOpType::Pow,
243 left: Box::new(left),
244 right: Box::new(right),
245 })
246 }
247 Token::Pipe => {
248 iter.next();
249 let right = parse_pow(iter);
250 Expr::BinOp(BinOpExpr {
251 op: BinOpType::Frac,
252 left: Box::new(left),
253 right: Box::new(right),
254 })
255 }
256 _ => left,
257 }
258}
259
260fn parse_mul(iter: &mut Iter<'_>) -> Expr {
261 let mut terms = vec![parse_pow(iter)];
262 loop {
263 match iter.peek().cloned().unwrap() {
264 Token::Slash
265 | Token::Plus
266 | Token::Dash
267 | Token::RPar
268 | Token::Newline
269 | Token::Eof => break,
270 Token::Asterisk => {
271 iter.next();
272 }
273 _ => terms.push(parse_pow(iter)),
274 }
275 }
276 if terms.len() == 1 {
277 terms.pop().unwrap()
278 } else {
279 Expr::new_mul(terms)
280 }
281}
282
283fn parse_div(iter: &mut Iter<'_>) -> Expr {
284 let mut left = parse_mul(iter);
285 while let Token::Slash = *iter.peek().unwrap() {
286 iter.next();
287 let right = parse_mul(iter);
288 left = Expr::new_frac(left, right);
289 }
290 left
291}
292
293fn parse_add(iter: &mut Iter<'_>) -> Expr {
294 let left = parse_div(iter);
295 match *iter.peek().unwrap() {
296 Token::Plus => {
297 iter.next();
298 let right = parse_add(iter);
299 Expr::new_add(left, right)
300 }
301 Token::Dash => {
302 iter.next();
303 let right = parse_add(iter);
304 Expr::new_sub(left, right)
305 }
306 _ => left,
307 }
308}
309
310pub fn parse_expr(iter: &mut Iter<'_>) -> Expr {
311 parse_add(iter)
312}
313
314pub fn parse(iter: &mut Iter<'_>) -> (Defs, Vec<String>) {
315 let mut map = vec![];
316 let mut line = 1;
317 let mut doc: Option<String> = None;
318 let mut category: Option<String> = None;
319 let mut symbols = BTreeMap::new();
320 let mut errors = vec![];
321 loop {
322 match iter.next().unwrap() {
323 Token::Newline => line += 1,
324 Token::Eof => break,
325 Token::Bang => match iter.next().unwrap() {
326 Token::Ident(ref s) if s == "category" => {
327 match (iter.next().unwrap(), iter.next().unwrap()) {
328 (Token::Ident(short), Token::Ident(display_name)) => {
329 map.push(DefEntry {
330 name: short.clone(),
331 def: Rc::new(Def::Category { display_name }),
332 doc: None,
333 category: None,
334 });
335 category = Some(short);
336 }
337 _ => errors.push(format!("Malformed category directive")),
338 }
339 }
340 Token::Ident(ref s) if s == "endcategory" => {
341 if category.is_none() {
342 errors.push(format!("Stray endcategory directive"));
343 }
344 category = None
345 }
346 Token::Ident(ref s) if s == "symbol" => {
347 match (iter.next().unwrap(), iter.next().unwrap()) {
348 (Token::Ident(subst), Token::Ident(sym)) => {
349 symbols.insert(subst, sym);
350 }
351 _ => errors.push(format!("Malformed symbol directive")),
352 }
353 }
354 Token::Ident(ref s) if s == "dependency" => {
355 let name = if let Some(Token::Ident(ref name)) = iter.next() {
356 name.clone()
357 } else {
358 errors.push(format!("Expected ident after `!dependency`"));
359 continue;
360 };
361
362 map.push(DefEntry {
363 name: name.clone(),
364 def: Rc::new(Def::Dependency { name }),
365 doc: doc.take(),
366 category: category.clone(),
367 });
368 }
369 Token::Ident(ref s) => {
370 errors.push(format!("Unknown directive !{s}"));
371 loop {
372 match iter.peek().cloned().unwrap() {
373 Token::Newline | Token::Eof => break,
374 _ => {
375 iter.next();
376 }
377 }
378 }
379 }
380 _ => {
381 errors.push(format!("syntax error: expected ident after !"));
382 loop {
383 match iter.peek().cloned().unwrap() {
384 Token::Newline | Token::Eof => break,
385 _ => {
386 iter.next();
387 }
388 }
389 }
390 }
391 },
392 Token::Doc(line) => {
393 doc = match doc.take() {
394 None => Some(line.trim().to_owned()),
395 Some(old) => Some(format!("{} {}", old.trim(), line.trim())),
396 };
397 }
398 Token::Ident(name) => {
399 if name.ends_with('-') {
400 let expr = parse_expr(iter);
402 let mut name = name;
403 name.pop();
404 if name.ends_with('-') {
405 name.pop();
406 map.push(DefEntry {
407 name,
408 def: Rc::new(Def::Prefix {
409 expr: ExprString(expr),
410 is_long: false,
411 }),
412 doc: doc.take(),
413 category: category.clone(),
414 });
415 } else {
416 map.push(DefEntry {
417 name,
418 def: Rc::new(Def::Prefix {
419 expr: ExprString(expr),
420 is_long: true,
421 }),
422 doc: doc.take(),
423 category: category.clone(),
424 });
425 }
426 } else {
427 if let Some(&Token::Bang) = iter.peek() {
429 iter.next();
431
432 let long_name = if let Some(Token::Ident(ref long)) = iter.peek().cloned() {
433 iter.next();
434 Some(long.clone())
435 } else {
436 None
437 };
438
439 map.push(DefEntry {
440 name: name.clone(),
441 def: Rc::new(Def::BaseUnit { long_name }),
442 doc: doc.take(),
443 category: category.clone(),
444 });
445 } else if let Some(&Token::Question) = iter.peek() {
446 iter.next();
448 let expr = parse_expr(iter);
449 map.push(DefEntry {
450 name,
451 def: Rc::new(Def::Quantity {
452 expr: ExprString(expr),
453 }),
454 doc: doc.take(),
455 category: category.clone(),
456 });
457 } else if let Some(&Token::LeftBrace) = iter.peek() {
458 iter.next();
460 let mut props = vec![];
461 let mut prop_doc = None;
462 loop {
463 let name = match iter.next().unwrap() {
464 Token::Ident(name) => name,
465 Token::Newline => {
466 line += 1;
467 continue;
468 }
469 Token::Eof => break,
470 Token::Doc(line) => {
471 prop_doc = match prop_doc.take() {
472 None => Some(line.trim().to_owned()),
473 Some(old) => {
474 Some(format!("{} {}", old.trim(), line.trim()))
475 }
476 };
477 continue;
478 }
479 Token::RightBrace => break,
480 x => {
481 errors.push(format!("Expected property, got {:?}", x));
482 break;
483 }
484 };
485 let output_name = match iter.next().unwrap() {
486 Token::Ident(ref s) if s == "const" => {
487 let input_name = match iter.next().unwrap() {
488 Token::Ident(name) => name,
489 x => {
490 errors.push(format!(
491 "Expected property input \
492 name, got {:?}",
493 x
494 ));
495 break;
496 }
497 };
498 let output = parse_div(iter);
499 props.push(Property {
500 output_name: name.clone(),
501 name,
502 input: ExprString(Expr::new_const(Numeric::one())),
503 input_name,
504 output: ExprString(output),
505 doc: prop_doc.take(),
506 });
507 continue;
508 }
509 Token::Ident(name) => name,
510 x => {
511 errors
512 .push(format!("Expected property input name, got {:?}", x));
513 break;
514 }
515 };
516 let output = parse_mul(iter);
517 match iter.next().unwrap() {
518 Token::Slash => (),
519 x => {
520 errors.push(format!("Expected /, got {:?}", x));
521 break;
522 }
523 }
524 let input_name = match iter.next().unwrap() {
525 Token::Ident(name) => name,
526 x => {
527 errors
528 .push(format!("Expected property input name, got {:?}", x));
529 break;
530 }
531 };
532 let input = parse_mul(iter);
533 props.push(Property {
534 name,
535 input: ExprString(input),
536 input_name,
537 output: ExprString(output),
538 output_name,
539 doc: prop_doc.take(),
540 });
541 }
542 map.push(DefEntry {
543 name,
544 def: Rc::new(Def::Substance {
545 symbol: None,
546 properties: props,
547 }),
548 doc: doc.take(),
549 category: category.clone(),
550 });
551 } else {
552 let expr = parse_expr(iter);
554 map.push(DefEntry {
555 name,
556 def: Rc::new(Def::Unit {
557 expr: ExprString(expr),
558 }),
559 doc: doc.take(),
560 category: category.clone(),
561 });
562 }
563 }
564 }
565 x => errors.push(format!("Expected definition on line {}, got {:?}", line, x)),
566 };
567 }
568
569 for entry in map.iter_mut() {
570 if let Def::Substance { ref mut symbol, .. } = *Rc::get_mut(&mut entry.def).unwrap() {
571 *symbol = symbols.get(&entry.name).map(|x| x.to_owned())
572 }
573 }
574
575 (Defs { defs: map }, errors)
576}
577
578pub fn parse_str(input: &str) -> Defs {
579 let mut iter = TokenIterator::new(&*input).peekable();
580 let (defs, errors) = parse(&mut iter);
581 for error in errors {
582 println!("{}", error);
583 }
584 defs
585}
586
587pub fn tokens(iter: &mut Iter<'_>) -> Vec<Token> {
588 let mut out = vec![];
589 loop {
590 match iter.next().unwrap() {
591 Token::Eof => break,
592 x => out.push(x),
593 }
594 }
595 out
596}