1#[cfg(not(feature = "std"))]
2use alloc::{boxed::Box, format, string::{String, ToString}, vec::Vec};
3
4use crate::error::BopError;
5use crate::lexer::{SpannedToken, StringPart, Token};
6
7#[derive(Debug, Clone)]
10pub struct Expr {
11 pub kind: ExprKind,
12 pub line: u32,
13}
14
15#[derive(Debug, Clone)]
16pub enum ExprKind {
17 Number(f64),
18 Str(String),
19 StringInterp(Vec<StringPart>),
20 Bool(bool),
21 None,
22 Ident(String),
23 BinaryOp {
24 left: Box<Expr>,
25 op: BinOp,
26 right: Box<Expr>,
27 },
28 UnaryOp {
29 op: UnaryOp,
30 expr: Box<Expr>,
31 },
32 Call {
33 callee: Box<Expr>,
34 args: Vec<Expr>,
35 },
36 MethodCall {
37 object: Box<Expr>,
38 method: String,
39 args: Vec<Expr>,
40 },
41 Index {
42 object: Box<Expr>,
43 index: Box<Expr>,
44 },
45 Array(Vec<Expr>),
46 Dict(Vec<(String, Expr)>),
47 IfExpr {
48 condition: Box<Expr>,
49 then_expr: Box<Expr>,
50 else_expr: Box<Expr>,
51 },
52}
53
54#[derive(Debug, Clone, Copy)]
55pub enum BinOp {
56 Add,
57 Sub,
58 Mul,
59 Div,
60 Mod,
61 Eq,
62 NotEq,
63 Lt,
64 Gt,
65 LtEq,
66 GtEq,
67 And,
68 Or,
69}
70
71#[derive(Debug, Clone, Copy)]
72pub enum UnaryOp {
73 Neg,
74 Not,
75}
76
77#[derive(Debug, Clone)]
78pub struct Stmt {
79 pub kind: StmtKind,
80 pub line: u32,
81}
82
83#[derive(Debug, Clone)]
84pub enum StmtKind {
85 Let {
86 name: String,
87 value: Expr,
88 },
89 Assign {
90 target: AssignTarget,
91 op: AssignOp,
92 value: Expr,
93 },
94 If {
95 condition: Expr,
96 body: Vec<Stmt>,
97 else_ifs: Vec<(Expr, Vec<Stmt>)>,
98 else_body: Option<Vec<Stmt>>,
99 },
100 While {
101 condition: Expr,
102 body: Vec<Stmt>,
103 },
104 Repeat {
105 count: Expr,
106 body: Vec<Stmt>,
107 },
108 ForIn {
109 var: String,
110 iterable: Expr,
111 body: Vec<Stmt>,
112 },
113 FnDecl {
114 name: String,
115 params: Vec<String>,
116 body: Vec<Stmt>,
117 },
118 Return {
119 value: Option<Expr>,
120 },
121 Break,
122 Continue,
123 ExprStmt(Expr),
124}
125
126#[derive(Debug, Clone)]
127pub enum AssignTarget {
128 Variable(String),
129 Index { object: Expr, index: Expr },
130}
131
132#[derive(Debug, Clone, Copy)]
133pub enum AssignOp {
134 Eq,
135 AddEq,
136 SubEq,
137 MulEq,
138 DivEq,
139 ModEq,
140}
141
142const MAX_PARSE_DEPTH: usize = 128;
145
146pub fn parse(tokens: Vec<SpannedToken>) -> Result<Vec<Stmt>, BopError> {
147 let mut parser = Parser::new(tokens);
148 parser.parse_program()
149}
150
151struct Parser {
152 tokens: Vec<SpannedToken>,
153 pos: usize,
154 depth: usize,
155}
156
157impl Parser {
158 fn new(tokens: Vec<SpannedToken>) -> Self {
159 Self {
160 tokens,
161 pos: 0,
162 depth: 0,
163 }
164 }
165
166 fn enter(&mut self) -> Result<(), BopError> {
167 self.depth += 1;
168 if self.depth > MAX_PARSE_DEPTH {
169 Err(self.error(self.peek_line(), "Code is nested too deeply"))
170 } else {
171 Ok(())
172 }
173 }
174
175 fn leave(&mut self) {
176 self.depth -= 1;
177 }
178
179 fn peek(&self) -> &Token {
180 self.tokens
181 .get(self.pos)
182 .map(|t| &t.token)
183 .unwrap_or(&Token::Eof)
184 }
185
186 fn peek_line(&self) -> u32 {
187 self.tokens.get(self.pos).map(|t| t.line).unwrap_or(0)
188 }
189
190 fn advance(&mut self) -> &Token {
191 let tok = self
192 .tokens
193 .get(self.pos)
194 .map(|t| &t.token)
195 .unwrap_or(&Token::Eof);
196 if self.pos < self.tokens.len() {
197 self.pos += 1;
198 }
199 tok
200 }
201
202 fn is_at_end(&self) -> bool {
203 matches!(self.peek(), Token::Eof)
204 }
205
206 fn expect(&mut self, expected: &Token) -> Result<u32, BopError> {
207 let line = self.peek_line();
208 if self.peek() == expected {
209 self.advance();
210 Ok(line)
211 } else {
212 Err(self.error(
213 line,
214 format!(
215 "Expected `{}` but found `{}`",
216 fmt_token(expected),
217 fmt_token(self.peek())
218 ),
219 ))
220 }
221 }
222
223 fn expect_ident(&mut self) -> Result<(String, u32), BopError> {
224 let line = self.peek_line();
225 if let Token::Ident(name) = self.peek().clone() {
226 self.advance();
227 Ok((name, line))
228 } else {
229 Err(self.error(
230 line,
231 format!("Expected a name but found `{}`", fmt_token(self.peek())),
232 ))
233 }
234 }
235
236 fn skip_semicolons(&mut self) {
237 while matches!(self.peek(), Token::Semicolon) {
238 self.advance();
239 }
240 }
241
242 fn error(&self, line: u32, message: impl Into<String>) -> BopError {
243 BopError {
244 line: Some(line),
245 column: None,
246 message: message.into(),
247 friendly_hint: None,
248 }
249 }
250
251 fn parse_program(&mut self) -> Result<Vec<Stmt>, BopError> {
254 let mut stmts = Vec::new();
255 self.skip_semicolons();
256 while !self.is_at_end() {
257 stmts.push(self.parse_statement()?);
258 self.skip_semicolons();
259 }
260 Ok(stmts)
261 }
262
263 fn parse_block(&mut self) -> Result<Vec<Stmt>, BopError> {
264 self.enter()?;
265 self.expect(&Token::LBrace)?;
266 let mut stmts = Vec::new();
267 self.skip_semicolons();
268 while !matches!(self.peek(), Token::RBrace | Token::Eof) {
269 stmts.push(self.parse_statement()?);
270 self.skip_semicolons();
271 }
272 self.expect(&Token::RBrace)?;
273 self.leave();
274 Ok(stmts)
275 }
276
277 fn parse_statement(&mut self) -> Result<Stmt, BopError> {
280 let line = self.peek_line();
281 match self.peek() {
282 Token::Let => self.parse_let(),
283 Token::If => self.parse_if_stmt(),
284 Token::While => self.parse_while(),
285 Token::For => self.parse_for(),
286 Token::Repeat => self.parse_repeat(),
287 Token::Fn => self.parse_fn_decl(),
288 Token::Return => self.parse_return(),
289 Token::Break => {
290 self.advance();
291 Ok(Stmt {
292 kind: StmtKind::Break,
293 line,
294 })
295 }
296 Token::Continue => {
297 self.advance();
298 Ok(Stmt {
299 kind: StmtKind::Continue,
300 line,
301 })
302 }
303 _ => self.parse_expr_or_assign(),
304 }
305 }
306
307 fn parse_let(&mut self) -> Result<Stmt, BopError> {
308 let line = self.peek_line();
309 self.advance(); let (name, _) = self.expect_ident()?;
311 self.expect(&Token::Eq)?;
312 let value = self.parse_expr()?;
313 Ok(Stmt {
314 kind: StmtKind::Let { name, value },
315 line,
316 })
317 }
318
319 fn parse_if_stmt(&mut self) -> Result<Stmt, BopError> {
320 let line = self.peek_line();
321 self.advance(); let condition = self.parse_expr()?;
323 let body = self.parse_block()?;
324
325 let mut else_ifs = Vec::new();
326 let mut else_body = None;
327
328 while matches!(self.peek(), Token::Else) {
329 self.advance(); if matches!(self.peek(), Token::If) {
331 self.advance(); let cond = self.parse_expr()?;
333 let block = self.parse_block()?;
334 else_ifs.push((cond, block));
335 } else {
336 else_body = Some(self.parse_block()?);
337 break;
338 }
339 }
340
341 Ok(Stmt {
342 kind: StmtKind::If {
343 condition,
344 body,
345 else_ifs,
346 else_body,
347 },
348 line,
349 })
350 }
351
352 fn parse_while(&mut self) -> Result<Stmt, BopError> {
353 let line = self.peek_line();
354 self.advance(); let condition = self.parse_expr()?;
356 let body = self.parse_block()?;
357 Ok(Stmt {
358 kind: StmtKind::While { condition, body },
359 line,
360 })
361 }
362
363 fn parse_for(&mut self) -> Result<Stmt, BopError> {
364 let line = self.peek_line();
365 self.advance(); let (var, _) = self.expect_ident()?;
367 self.expect(&Token::In)?;
368 let iterable = self.parse_expr()?;
369 let body = self.parse_block()?;
370 Ok(Stmt {
371 kind: StmtKind::ForIn {
372 var,
373 iterable,
374 body,
375 },
376 line,
377 })
378 }
379
380 fn parse_repeat(&mut self) -> Result<Stmt, BopError> {
381 let line = self.peek_line();
382 self.advance(); let count = self.parse_expr()?;
384 let body = self.parse_block()?;
385 Ok(Stmt {
386 kind: StmtKind::Repeat { count, body },
387 line,
388 })
389 }
390
391 fn parse_fn_decl(&mut self) -> Result<Stmt, BopError> {
392 let line = self.peek_line();
393 self.advance(); let (name, _) = self.expect_ident()?;
395 self.expect(&Token::LParen)?;
396
397 let mut params = Vec::new();
398 if !matches!(self.peek(), Token::RParen) {
399 let (p, _) = self.expect_ident()?;
400 params.push(p);
401 while matches!(self.peek(), Token::Comma) {
402 self.advance();
403 let (p, _) = self.expect_ident()?;
404 params.push(p);
405 }
406 }
407 self.expect(&Token::RParen)?;
408 let body = self.parse_block()?;
409 Ok(Stmt {
410 kind: StmtKind::FnDecl { name, params, body },
411 line,
412 })
413 }
414
415 fn parse_return(&mut self) -> Result<Stmt, BopError> {
416 let line = self.peek_line();
417 self.advance(); let value = if matches!(self.peek(), Token::Semicolon | Token::RBrace | Token::Eof) {
419 None
420 } else {
421 Some(self.parse_expr()?)
422 };
423 Ok(Stmt {
424 kind: StmtKind::Return { value },
425 line,
426 })
427 }
428
429 fn parse_expr_or_assign(&mut self) -> Result<Stmt, BopError> {
430 let line = self.peek_line();
431 let expr = self.parse_expr()?;
432
433 let op = match self.peek() {
434 Token::Eq => Some(AssignOp::Eq),
435 Token::PlusEq => Some(AssignOp::AddEq),
436 Token::MinusEq => Some(AssignOp::SubEq),
437 Token::StarEq => Some(AssignOp::MulEq),
438 Token::SlashEq => Some(AssignOp::DivEq),
439 Token::PercentEq => Some(AssignOp::ModEq),
440 _ => None,
441 };
442
443 if let Some(op) = op {
444 self.advance(); let target = expr_to_assign_target(expr, line)?;
446 let value = self.parse_expr()?;
447 Ok(Stmt {
448 kind: StmtKind::Assign { target, op, value },
449 line,
450 })
451 } else {
452 Ok(Stmt {
453 kind: StmtKind::ExprStmt(expr),
454 line,
455 })
456 }
457 }
458
459 fn parse_expr(&mut self) -> Result<Expr, BopError> {
462 self.parse_or()
463 }
464
465 fn parse_or(&mut self) -> Result<Expr, BopError> {
466 let mut left = self.parse_and()?;
467 while matches!(self.peek(), Token::PipePipe) {
468 let line = self.peek_line();
469 self.advance();
470 let right = self.parse_and()?;
471 left = Expr {
472 kind: ExprKind::BinaryOp {
473 left: Box::new(left),
474 op: BinOp::Or,
475 right: Box::new(right),
476 },
477 line,
478 };
479 }
480 Ok(left)
481 }
482
483 fn parse_and(&mut self) -> Result<Expr, BopError> {
484 let mut left = self.parse_equality()?;
485 while matches!(self.peek(), Token::AmpAmp) {
486 let line = self.peek_line();
487 self.advance();
488 let right = self.parse_equality()?;
489 left = Expr {
490 kind: ExprKind::BinaryOp {
491 left: Box::new(left),
492 op: BinOp::And,
493 right: Box::new(right),
494 },
495 line,
496 };
497 }
498 Ok(left)
499 }
500
501 fn parse_equality(&mut self) -> Result<Expr, BopError> {
502 let mut left = self.parse_comparison()?;
503 while matches!(self.peek(), Token::EqEq | Token::BangEq) {
504 let line = self.peek_line();
505 let op = if matches!(self.peek(), Token::EqEq) {
506 BinOp::Eq
507 } else {
508 BinOp::NotEq
509 };
510 self.advance();
511 let right = self.parse_comparison()?;
512 left = Expr {
513 kind: ExprKind::BinaryOp {
514 left: Box::new(left),
515 op,
516 right: Box::new(right),
517 },
518 line,
519 };
520 }
521 Ok(left)
522 }
523
524 fn parse_comparison(&mut self) -> Result<Expr, BopError> {
525 let mut left = self.parse_addition()?;
526 while matches!(
527 self.peek(),
528 Token::Lt | Token::Gt | Token::LtEq | Token::GtEq
529 ) {
530 let line = self.peek_line();
531 let op = match self.peek() {
532 Token::Lt => BinOp::Lt,
533 Token::Gt => BinOp::Gt,
534 Token::LtEq => BinOp::LtEq,
535 _ => BinOp::GtEq,
536 };
537 self.advance();
538 let right = self.parse_addition()?;
539 left = Expr {
540 kind: ExprKind::BinaryOp {
541 left: Box::new(left),
542 op,
543 right: Box::new(right),
544 },
545 line,
546 };
547 }
548 Ok(left)
549 }
550
551 fn parse_addition(&mut self) -> Result<Expr, BopError> {
552 let mut left = self.parse_multiply()?;
553 while matches!(self.peek(), Token::Plus | Token::Minus) {
554 let line = self.peek_line();
555 let op = if matches!(self.peek(), Token::Plus) {
556 BinOp::Add
557 } else {
558 BinOp::Sub
559 };
560 self.advance();
561 let right = self.parse_multiply()?;
562 left = Expr {
563 kind: ExprKind::BinaryOp {
564 left: Box::new(left),
565 op,
566 right: Box::new(right),
567 },
568 line,
569 };
570 }
571 Ok(left)
572 }
573
574 fn parse_multiply(&mut self) -> Result<Expr, BopError> {
575 let mut left = self.parse_unary()?;
576 while matches!(self.peek(), Token::Star | Token::Slash | Token::Percent) {
577 let line = self.peek_line();
578 let op = match self.peek() {
579 Token::Star => BinOp::Mul,
580 Token::Slash => BinOp::Div,
581 _ => BinOp::Mod,
582 };
583 self.advance();
584 let right = self.parse_unary()?;
585 left = Expr {
586 kind: ExprKind::BinaryOp {
587 left: Box::new(left),
588 op,
589 right: Box::new(right),
590 },
591 line,
592 };
593 }
594 Ok(left)
595 }
596
597 fn parse_unary(&mut self) -> Result<Expr, BopError> {
598 self.enter()?;
599 let line = self.peek_line();
600 let result = match self.peek() {
601 Token::Bang => {
602 self.advance();
603 let expr = self.parse_unary()?;
604 Ok(Expr {
605 kind: ExprKind::UnaryOp {
606 op: UnaryOp::Not,
607 expr: Box::new(expr),
608 },
609 line,
610 })
611 }
612 Token::Minus => {
613 self.advance();
614 let expr = self.parse_unary()?;
615 Ok(Expr {
616 kind: ExprKind::UnaryOp {
617 op: UnaryOp::Neg,
618 expr: Box::new(expr),
619 },
620 line,
621 })
622 }
623 _ => self.parse_postfix(),
624 };
625 self.leave();
626 result
627 }
628
629 fn parse_postfix(&mut self) -> Result<Expr, BopError> {
630 let mut expr = self.parse_primary()?;
631
632 loop {
633 match self.peek() {
634 Token::LParen => {
635 let line = self.peek_line();
636 self.advance();
637 let args = self.parse_args()?;
638 self.expect(&Token::RParen)?;
639 expr = Expr {
640 kind: ExprKind::Call {
641 callee: Box::new(expr),
642 args,
643 },
644 line,
645 };
646 }
647 Token::LBracket => {
648 let line = self.peek_line();
649 self.advance();
650 let index = self.parse_expr()?;
651 self.expect(&Token::RBracket)?;
652 expr = Expr {
653 kind: ExprKind::Index {
654 object: Box::new(expr),
655 index: Box::new(index),
656 },
657 line,
658 };
659 }
660 Token::Dot => {
661 let line = self.peek_line();
662 self.advance();
663 let (method, _) = self.expect_ident()?;
664 self.expect(&Token::LParen)?;
665 let args = self.parse_args()?;
666 self.expect(&Token::RParen)?;
667 expr = Expr {
668 kind: ExprKind::MethodCall {
669 object: Box::new(expr),
670 method,
671 args,
672 },
673 line,
674 };
675 }
676 _ => break,
677 }
678 }
679
680 Ok(expr)
681 }
682
683 fn parse_args(&mut self) -> Result<Vec<Expr>, BopError> {
684 let mut args = Vec::new();
685 if !matches!(self.peek(), Token::RParen) {
686 args.push(self.parse_expr()?);
687 while matches!(self.peek(), Token::Comma) {
688 self.advance();
689 args.push(self.parse_expr()?);
690 }
691 }
692 Ok(args)
693 }
694
695 fn parse_primary(&mut self) -> Result<Expr, BopError> {
696 let line = self.peek_line();
697
698 match self.peek().clone() {
699 Token::Number(n) => {
700 self.advance();
701 Ok(Expr {
702 kind: ExprKind::Number(n),
703 line,
704 })
705 }
706 Token::Str(s) => {
707 self.advance();
708 Ok(Expr {
709 kind: ExprKind::Str(s),
710 line,
711 })
712 }
713 Token::StringInterp(parts) => {
714 self.advance();
715 Ok(Expr {
716 kind: ExprKind::StringInterp(parts),
717 line,
718 })
719 }
720 Token::True => {
721 self.advance();
722 Ok(Expr {
723 kind: ExprKind::Bool(true),
724 line,
725 })
726 }
727 Token::False => {
728 self.advance();
729 Ok(Expr {
730 kind: ExprKind::Bool(false),
731 line,
732 })
733 }
734 Token::None => {
735 self.advance();
736 Ok(Expr {
737 kind: ExprKind::None,
738 line,
739 })
740 }
741 Token::Ident(name) => {
742 self.advance();
743 Ok(Expr {
744 kind: ExprKind::Ident(name),
745 line,
746 })
747 }
748 Token::LParen => {
749 self.enter()?;
750 self.advance();
751 let expr = self.parse_expr()?;
752 self.expect(&Token::RParen)?;
753 self.leave();
754 Ok(expr)
755 }
756 Token::LBracket => self.parse_array_literal(),
757 Token::LBrace => self.parse_dict_literal(),
758 Token::If => self.parse_if_expr(),
759 _ => Err(self.error(
760 line,
761 format!("I didn't expect `{}` here", fmt_token(self.peek())),
762 )),
763 }
764 }
765
766 fn parse_array_literal(&mut self) -> Result<Expr, BopError> {
767 let line = self.peek_line();
768 self.advance(); let mut elements = Vec::new();
770 if !matches!(self.peek(), Token::RBracket) {
771 elements.push(self.parse_expr()?);
772 while matches!(self.peek(), Token::Comma) {
773 self.advance();
774 if matches!(self.peek(), Token::RBracket) {
775 break; }
777 elements.push(self.parse_expr()?);
778 }
779 }
780 self.expect(&Token::RBracket)?;
781 Ok(Expr {
782 kind: ExprKind::Array(elements),
783 line,
784 })
785 }
786
787 fn parse_dict_literal(&mut self) -> Result<Expr, BopError> {
788 let line = self.peek_line();
789 self.advance(); let mut entries = Vec::new();
791 if !matches!(self.peek(), Token::RBrace) {
792 let key = self.expect_string_key()?;
793 self.expect(&Token::Colon)?;
794 let value = self.parse_expr()?;
795 entries.push((key, value));
796 while matches!(self.peek(), Token::Comma) {
797 self.advance();
798 if matches!(self.peek(), Token::RBrace) {
799 break; }
801 let key = self.expect_string_key()?;
802 self.expect(&Token::Colon)?;
803 let value = self.parse_expr()?;
804 entries.push((key, value));
805 }
806 }
807 self.expect(&Token::RBrace)?;
808 Ok(Expr {
809 kind: ExprKind::Dict(entries),
810 line,
811 })
812 }
813
814 fn expect_string_key(&mut self) -> Result<String, BopError> {
815 let line = self.peek_line();
816 match self.peek().clone() {
817 Token::Str(s) => {
818 self.advance();
819 Ok(s)
820 }
821 _ => Err(self.error(line, "Dict keys must be strings (in quotes)")),
822 }
823 }
824
825 fn parse_if_expr(&mut self) -> Result<Expr, BopError> {
826 let line = self.peek_line();
827 self.advance(); let condition = self.parse_expr()?;
829 self.expect(&Token::LBrace)?;
830 let then_expr = self.parse_expr()?;
831 self.expect(&Token::RBrace)?;
832 self.expect(&Token::Else)?;
833 self.expect(&Token::LBrace)?;
834 let else_expr = self.parse_expr()?;
835 self.expect(&Token::RBrace)?;
836 Ok(Expr {
837 kind: ExprKind::IfExpr {
838 condition: Box::new(condition),
839 then_expr: Box::new(then_expr),
840 else_expr: Box::new(else_expr),
841 },
842 line,
843 })
844 }
845}
846
847pub fn count_instructions(stmts: &[Stmt]) -> u32 {
855 let mut count = 0u32;
856 for stmt in stmts {
857 count += 1; match &stmt.kind {
859 StmtKind::If {
860 body,
861 else_ifs,
862 else_body,
863 ..
864 } => {
865 count += count_instructions(body);
866 for (_, branch_body) in else_ifs {
867 count += count_instructions(branch_body);
868 }
869 if let Some(eb) = else_body {
870 count += count_instructions(eb);
871 }
872 }
873 StmtKind::While { body, .. }
874 | StmtKind::Repeat { body, .. }
875 | StmtKind::ForIn { body, .. } => {
876 count += count_instructions(body);
877 }
878 StmtKind::FnDecl { .. } => {
879 }
881 _ => {}
882 }
883 }
884 count
885}
886
887fn expr_to_assign_target(expr: Expr, line: u32) -> Result<AssignTarget, BopError> {
890 match expr.kind {
891 ExprKind::Ident(name) => Ok(AssignTarget::Variable(name)),
892 ExprKind::Index { object, index } => Ok(AssignTarget::Index {
893 object: *object,
894 index: *index,
895 }),
896 _ => Err(BopError {
897 line: Some(line),
898 column: None,
899 message: "You can only assign to a variable or an index (like `arr[0]`)".to_string(),
900 friendly_hint: None,
901 }),
902 }
903}
904
905pub fn fmt_token(token: &Token) -> &'static str {
906 match token {
907 Token::Number(_) => "a number",
908 Token::Str(_) | Token::StringInterp(_) => "a string",
909 Token::True => "true",
910 Token::False => "false",
911 Token::None => "none",
912 Token::Ident(_) => "a name",
913 Token::Let => "let",
914 Token::Fn => "fn",
915 Token::Return => "return",
916 Token::If => "if",
917 Token::Else => "else",
918 Token::While => "while",
919 Token::For => "for",
920 Token::In => "in",
921 Token::Repeat => "repeat",
922 Token::Break => "break",
923 Token::Continue => "continue",
924 Token::Plus => "+",
925 Token::Minus => "-",
926 Token::Star => "*",
927 Token::Slash => "/",
928 Token::Percent => "%",
929 Token::EqEq => "==",
930 Token::BangEq => "!=",
931 Token::Lt => "<",
932 Token::Gt => ">",
933 Token::LtEq => "<=",
934 Token::GtEq => ">=",
935 Token::AmpAmp => "&&",
936 Token::PipePipe => "||",
937 Token::Bang => "!",
938 Token::Eq => "=",
939 Token::PlusEq => "+=",
940 Token::MinusEq => "-=",
941 Token::StarEq => "*=",
942 Token::SlashEq => "/=",
943 Token::PercentEq => "%=",
944 Token::LParen => "(",
945 Token::RParen => ")",
946 Token::LBracket => "[",
947 Token::RBracket => "]",
948 Token::LBrace => "{",
949 Token::RBrace => "}",
950 Token::Comma => ",",
951 Token::Colon => ":",
952 Token::Dot => ".",
953 Token::Semicolon => ";",
954 Token::Newline => "newline",
955 Token::Eof => "end of code",
956 }
957}