1use std::cell::Cell;
7
8use flexi_parse::group;
9use flexi_parse::group::Braces;
10use flexi_parse::group::Group;
11use flexi_parse::group::Parentheses;
12use flexi_parse::parse_repeated;
13use flexi_parse::parse_string;
14use flexi_parse::peek2_any;
15use flexi_parse::pretty_unwrap;
16use flexi_parse::punctuated::Punctuated;
17use flexi_parse::token::Ident;
18use flexi_parse::token::LitFloat;
19use flexi_parse::token::LitInt;
20use flexi_parse::token::LitStrDoubleQuote as LitStr;
21use flexi_parse::Parse;
22use flexi_parse::ParseStream;
23use flexi_parse::Parser;
24use flexi_parse::Punct;
25use flexi_parse::Result;
26
27mod interpreter;
28mod resolver;
29
30mod error_codes {
31 pub const INVALID_ASSIGN: u16 = 0;
32 pub const TOO_MANY_ARGS: u16 = 1;
33 pub const TYPE_ERROR: u16 = 2;
34 pub const UNDEFINED_NAME: u16 = 3;
35 pub const INCORRECT_ARITY: u16 = 4;
36 pub const INVALID_INITIALISER: u16 = 5;
37 pub const SHADOW: u16 = 6;
38 pub const RETURN_OUTSIDE_FUNCTION: u16 = 7;
39 pub const THIS_OUTSIDE_CLASS: u16 = 8;
40 pub const CYCLICAL_INHERITANCE: u16 = 9;
41 pub const INHERIT_FROM_VALUE: u16 = 10;
42 pub const INVALID_SUPER: u16 = 11;
43}
44
45mod kw {
46 flexi_parse::keywords![
47 and, class, else as kw_else, false as kw_false, for as kw_for, fun, if as kw_if, nil, or,
48 print, return as kw_return, super as kw_super, this, true as kw_true, var, while as kw_while,
49 ];
50}
51
52#[derive(Debug, Clone, PartialEq)]
53enum Binary {
54 Mul(Expr, Punct!["*"], Expr),
55 Div(Expr, Punct!["/"], Expr),
56
57 Add(Expr, Punct!["+"], Expr),
58 Sub(Expr, Punct!["-"], Expr),
59
60 Equal(Expr, Punct!["=="], Expr),
61 NotEqual(Expr, Punct!["!="], Expr),
62
63 Greater(Expr, Punct![">"], Expr),
64 GreaterEqual(Expr, Punct![">="], Expr),
65 Less(Expr, Punct!["<"], Expr),
66 LessEqual(Expr, Punct!["<="], Expr),
67}
68
69impl Binary {
70 const fn left(&self) -> &Expr {
71 match self {
72 Binary::Mul(left, _, _)
73 | Binary::Div(left, _, _)
74 | Binary::Add(left, _, _)
75 | Binary::Sub(left, _, _)
76 | Binary::Equal(left, _, _)
77 | Binary::NotEqual(left, _, _)
78 | Binary::Greater(left, _, _)
79 | Binary::GreaterEqual(left, _, _)
80 | Binary::Less(left, _, _)
81 | Binary::LessEqual(left, _, _) => left,
82 }
83 }
84
85 const fn right(&self) -> &Expr {
86 match self {
87 Binary::Mul(_, _, right)
88 | Binary::Div(_, _, right)
89 | Binary::Add(_, _, right)
90 | Binary::Sub(_, _, right)
91 | Binary::Equal(_, _, right)
92 | Binary::NotEqual(_, _, right)
93 | Binary::Greater(_, _, right)
94 | Binary::GreaterEqual(_, _, right)
95 | Binary::Less(_, _, right)
96 | Binary::LessEqual(_, _, right) => right,
97 }
98 }
99}
100
101#[derive(Debug, Clone, PartialEq)]
102enum Literal {
103 False(kw::kw_false),
104 Float(LitFloat),
105 Int(LitInt),
106 Nil(kw::nil),
107 String(LitStr),
108 True(kw::kw_true),
109}
110
111#[derive(Debug, Clone, PartialEq)]
112enum Logical {
113 And(Expr, kw::and, Expr),
114 Or(Expr, kw::or, Expr),
115}
116
117impl Logical {
118 const fn left(&self) -> &Expr {
119 match self {
120 Logical::And(left, _, _) | Logical::Or(left, _, _) => left,
121 }
122 }
123
124 const fn right(&self) -> &Expr {
125 match self {
126 Logical::And(_, _, right) | Logical::Or(_, _, right) => right,
127 }
128 }
129}
130
131#[derive(Debug, Clone, PartialEq)]
132enum Unary {
133 Neg(Punct!["-"], Expr),
134 Not(Punct!["!"], Expr),
135}
136
137impl Unary {
138 const fn right(&self) -> &Expr {
139 match self {
140 Unary::Neg(_, right) | Unary::Not(_, right) => right,
141 }
142 }
143}
144
145#[derive(Debug, Clone, PartialEq)]
146enum Expr {
147 Assign {
148 name: Ident,
149 value: Box<Expr>,
150 distance: Cell<Option<usize>>,
151 },
152 Binary(Box<Binary>),
153 Call {
154 callee: Box<Expr>,
155 paren: Parentheses,
156 arguments: Vec<Expr>,
157 },
158 Get {
159 object: Box<Expr>,
160 name: Ident,
161 },
162 Group(Box<Expr>),
163 Literal(Literal),
164 Logical(Box<Logical>),
165 Set {
166 object: Box<Expr>,
167 name: Ident,
168 value: Box<Expr>,
169 },
170 Super {
171 keyword: kw::kw_super,
172 distance: Cell<Option<usize>>,
173 dot: Punct!["."],
174 method: Ident,
175 },
176 This {
177 keyword: kw::this,
178 distance: Cell<Option<usize>>,
179 },
180 Unary(Box<Unary>),
181 Variable {
182 name: Ident,
183 distance: Cell<Option<usize>>,
184 },
185}
186
187impl Expr {
188 fn binary(binary: Binary) -> Self {
189 Expr::Binary(Box::new(binary))
190 }
191
192 fn assignment(input: ParseStream) -> Result<Self> {
193 let expr = Expr::or(input)?;
194
195 if input.peek(Punct!["="]) {
196 let equals: Punct!["="] = input.parse()?;
197 let value = Box::new(Expr::assignment(input)?);
198
199 if let Expr::Variable { name, .. } = expr {
200 return Ok(Expr::Assign {
201 name,
202 value,
203 distance: Cell::new(None),
204 });
205 } else if let Expr::Get { object, name } = expr {
206 return Ok(Expr::Set {
207 object,
208 name,
209 value,
210 });
211 }
212
213 input.add_error(input.new_error(
214 "Invalid assignment target".to_string(),
215 &equals,
216 error_codes::INVALID_ASSIGN,
217 ));
218 }
219
220 Ok(expr)
221 }
222
223 fn or(input: ParseStream) -> Result<Self> {
224 let mut expr = Expr::and(input)?;
225
226 while input.peek(kw::or) {
227 expr = Expr::Logical(Box::new(Logical::Or(
228 expr,
229 input.parse()?,
230 Expr::and(input)?,
231 )));
232 }
233
234 Ok(expr)
235 }
236
237 fn and(input: ParseStream) -> Result<Self> {
238 let mut expr = Expr::equality(input)?;
239
240 while input.peek(kw::and) {
241 expr = Expr::Logical(Box::new(Logical::And(
242 expr,
243 input.parse()?,
244 Expr::equality(input)?,
245 )));
246 }
247
248 Ok(expr)
249 }
250
251 fn equality(input: ParseStream) -> Result<Self> {
252 let mut expr = Expr::comparison(input)?;
253
254 loop {
255 if input.peek(Punct!["=="]) {
256 expr = Expr::binary(Binary::Equal(
257 expr,
258 input.parse()?,
259 Expr::comparison(input)?,
260 ));
261 } else if input.peek(Punct!["!="]) {
262 expr = Expr::binary(Binary::NotEqual(
263 expr,
264 input.parse()?,
265 Expr::comparison(input)?,
266 ));
267 } else {
268 break Ok(expr);
269 }
270 }
271 }
272
273 fn comparison(input: ParseStream) -> Result<Self> {
274 let mut expr = Expr::term(input)?;
275
276 loop {
277 if input.peek(Punct![">"]) {
278 expr = Expr::binary(Binary::Greater(expr, input.parse()?, Expr::term(input)?));
279 } else if input.peek(Punct![">="]) {
280 expr = Expr::binary(Binary::GreaterEqual(
281 expr,
282 input.parse()?,
283 Expr::term(input)?,
284 ));
285 } else if input.peek(Punct!["<"]) {
286 expr = Expr::binary(Binary::Less(expr, input.parse()?, Expr::term(input)?));
287 } else if input.peek(Punct!["<="]) {
288 expr = Expr::binary(Binary::LessEqual(expr, input.parse()?, Expr::term(input)?));
289 } else {
290 break Ok(expr);
291 }
292 }
293 }
294
295 fn term(input: ParseStream) -> Result<Self> {
296 let mut expr = Expr::factor(input)?;
297
298 loop {
299 if input.peek(Punct!["+"]) {
300 expr = Expr::binary(Binary::Add(expr, input.parse()?, Expr::factor(input)?));
301 } else if input.peek(Punct!["-"]) {
302 expr = Expr::binary(Binary::Sub(expr, input.parse()?, Expr::factor(input)?));
303 } else {
304 break Ok(expr);
305 }
306 }
307 }
308
309 fn factor(input: ParseStream) -> Result<Self> {
310 let mut expr = Expr::unary(input)?;
311
312 loop {
313 if input.peek(Punct!["*"]) {
314 expr = Expr::binary(Binary::Mul(expr, input.parse()?, Expr::unary(input)?));
315 } else if input.peek(Punct!["/"]) {
316 expr = Expr::binary(Binary::Div(expr, input.parse()?, Expr::unary(input)?));
317 } else {
318 break Ok(expr);
319 }
320 }
321 }
322
323 fn unary(input: ParseStream) -> Result<Self> {
324 if input.peek(Punct!["-"]) {
325 Ok(Expr::Unary(Box::new(Unary::Neg(
326 input.parse()?,
327 Expr::unary(input)?,
328 ))))
329 } else if input.peek(Punct!["!"]) {
330 Ok(Expr::Unary(Box::new(Unary::Not(
331 input.parse()?,
332 Expr::unary(input)?,
333 ))))
334 } else {
335 Expr::call(input)
336 }
337 }
338
339 fn call(input: ParseStream) -> Result<Self> {
340 let mut expr = Expr::primary(input)?;
341
342 loop {
343 if input.peek(Punct!["("]) {
344 expr = Expr::finish_call(input, expr)?;
345 } else if input.peek(Punct!["."]) {
346 let _: Punct!["."] = input.parse()?;
347 let name: Ident = input.parse()?;
348 expr = Expr::Get {
349 object: Box::new(expr),
350 name,
351 };
352 } else {
353 break Ok(expr);
354 }
355 }
356 }
357
358 fn finish_call(input: ParseStream<'_>, callee: Expr) -> Result<Self> {
359 let content;
360 let paren: Parentheses = group!(content in input);
361 let arguments: Punctuated<Expr, Punct![","]> =
362 Punctuated::parse_separated_trailing(&content)?;
363 let arguments: Vec<_> = arguments.into_iter().collect();
364 if arguments.len() >= 255 {
365 input.add_error(input.new_error(
366 "Can't have more than 254 arguments".to_string(),
367 paren.0.clone(),
368 error_codes::TOO_MANY_ARGS,
369 ));
370 }
371 Ok(Expr::Call {
372 callee: Box::new(callee),
373 paren,
374 arguments,
375 })
376 }
377
378 fn primary(input: ParseStream) -> Result<Self> {
379 let lookahead = input.lookahead();
380 if lookahead.peek(kw::kw_false) {
381 Ok(Expr::Literal(Literal::False(input.parse()?)))
382 } else if lookahead.peek(kw::kw_true) {
383 Ok(Expr::Literal(Literal::True(input.parse()?)))
384 } else if lookahead.peek(kw::nil) {
385 Ok(Expr::Literal(Literal::Nil(input.parse()?)))
386 } else if lookahead.peek(LitFloat) {
387 Ok(Expr::Literal(Literal::Float(input.parse()?)))
388 } else if lookahead.peek(LitInt) {
389 Ok(Expr::Literal(Literal::Int(input.parse()?)))
390 } else if lookahead.peek(LitStr) {
391 Ok(Expr::Literal(Literal::String(input.parse()?)))
392 } else if input.peek(kw::kw_super) {
393 Ok(Expr::Super {
394 keyword: input.parse()?,
395 distance: Cell::new(None),
396 dot: input.parse()?,
397 method: kw::ident(input)?,
398 })
399 } else if input.peek(kw::this) {
400 Ok(Expr::This {
401 keyword: input.parse()?,
402 distance: Cell::new(None),
403 })
404 } else if lookahead.peek(Ident) {
405 Ok(Expr::Variable {
406 name: kw::ident(input)?,
407 distance: Cell::new(None),
408 })
409 } else if lookahead.peek(Punct!["("]) {
410 let content;
411 let _: Parentheses = group!(content in input);
412 Ok(Expr::Group(Box::new(content.parse()?)))
413 } else {
414 Err(lookahead.error())
415 }
416 }
417}
418
419impl Parse for Expr {
420 fn parse(input: ParseStream) -> Result<Self> {
421 Expr::assignment(input)
422 }
423}
424
425#[derive(Debug, Clone, PartialEq)]
426struct Function {
427 name: Ident,
428 params: Vec<Ident>,
429 body: Vec<Stmt>,
430}
431
432impl Parse for Function {
433 fn parse(input: ParseStream) -> Result<Self> {
434 let name: Ident = input.parse()?;
435 let mut contents: Group<Parentheses> = input.parse()?;
436 contents.remove_whitespace();
437 let Parentheses(span) = contents.delimiters();
438 let tokens = contents.into_token_stream();
439 let params: Vec<Ident> = if tokens.is_empty() {
440 vec![]
441 } else {
442 let params: Punctuated<Ident, Punct![","]> =
443 Punctuated::parse_separated.parse(tokens)?;
444 params.into_iter().collect()
445 };
446 if params.len() >= 255 {
447 input.add_error(input.new_error(
448 "Can't have more than 254 parameters".to_string(),
449 span,
450 error_codes::TOO_MANY_ARGS,
451 ));
452 }
453 let mut contents: Group<Braces> = input.parse()?;
454 contents.remove_whitespace();
455 let body = block.parse(contents.into_token_stream())?;
456 Ok(Function { name, params, body })
457 }
458}
459
460#[derive(Debug, Clone, PartialEq)]
461enum Stmt {
462 Block(Vec<Stmt>),
463 Class {
464 name: Ident,
465 superclass: Option<Ident>,
466 superclass_distance: Cell<Option<usize>>,
467 methods: Vec<Function>,
468 },
469 Expr(Expr),
470 Function(Function),
471 If {
472 condition: Expr,
473 then_branch: Box<Stmt>,
474 else_branch: Option<Box<Stmt>>,
475 },
476 Print(Expr),
477 Return {
478 keyword: kw::kw_return,
479 value: Option<Expr>,
480 },
481 Variable {
482 name: Ident,
483 initialiser: Option<Expr>,
484 },
485 While {
486 condition: Expr,
487 body: Box<Stmt>,
488 },
489}
490
491fn block(input: ParseStream) -> Result<Vec<Stmt>> {
492 let mut statements = vec![];
493
494 while !input.is_empty() {
495 statements.push(Stmt::declaration(input)?);
496 }
497
498 Ok(statements)
499}
500
501impl Stmt {
502 fn declaration(input: ParseStream) -> Result<Self> {
503 if input.peek(kw::class) {
504 Stmt::class_declaration(input)
505 } else if input.peek(kw::fun) {
506 let _: kw::fun = input.parse()?;
507 Ok(Stmt::Function(Function::parse(input)?))
508 } else if input.peek(kw::var) {
509 Stmt::var_declaration(input)
510 } else {
511 Stmt::statement(input)
512 }
513 }
514
515 fn class_declaration(input: ParseStream) -> Result<Self> {
516 let _: kw::class = input.parse()?;
517 let name: Ident = input.parse()?;
518
519 let superclass = if input.peek(Punct!["<"]) {
520 let _: Punct!["<"] = input.parse()?;
521 Some(input.parse()?)
522 } else {
523 None
524 };
525
526 let content;
527 let _: Braces = group!(content in input);
528 let methods = parse_repeated(&content)?;
529
530 Ok(Stmt::Class {
531 name,
532 superclass,
533 superclass_distance: Cell::new(None),
534 methods,
535 })
536 }
537
538 fn var_declaration(input: ParseStream) -> Result<Self> {
539 let _: kw::var = input.parse()?;
540
541 let name = kw::ident(input)?;
542
543 let initialiser = if input.peek(Punct!["="]) {
544 let _: Punct!["="] = input.parse()?;
545 Some(input.parse()?)
546 } else {
547 None
548 };
549
550 let _: Punct![";"] = input.parse()?;
551 Ok(Stmt::Variable { name, initialiser })
552 }
553
554 fn statement(input: ParseStream) -> Result<Self> {
555 if input.peek(kw::kw_if) {
556 Stmt::if_statement(input)
557 } else if input.peek(kw::kw_for) {
558 Stmt::for_statement(input)
559 } else if input.peek(kw::print) {
560 Stmt::print_statement(input)
561 } else if input.peek(kw::kw_return) {
562 Stmt::return_statement(input)
563 } else if input.peek(kw::kw_while) {
564 Stmt::while_statement(input)
565 } else if input.peek(Punct!["{"]) {
566 let content;
567 let _: Braces = group!(content in input);
568 Ok(Stmt::Block(block(&content)?))
569 } else {
570 Stmt::expression_statement(input)
571 }
572 }
573
574 fn for_statement(input: ParseStream) -> Result<Self> {
575 let _: kw::kw_for = input.parse()?;
576
577 let content;
578 let _: Parentheses = group!(content in input);
579
580 let initialiser = if content.peek(Punct![";"]) {
581 let _: Punct![";"] = content.parse()?;
582 None
583 } else if content.peek(kw::var) {
584 Some(Stmt::var_declaration(&content)?)
585 } else {
586 Some(Stmt::expression_statement(&content)?)
587 };
588
589 let condition = if content.peek(Punct![";"]) {
590 Expr::Literal(Literal::True(kw::kw_true::new(&content)))
591 } else {
592 content.parse()?
593 };
594 let _: Punct![";"] = content.parse()?;
595
596 let increment = if content.is_empty() {
597 None
598 } else {
599 Some(content.parse()?)
600 };
601
602 let mut body = Stmt::statement(input)?;
603
604 if let Some(increment) = increment {
605 body = Stmt::Block(vec![body, Stmt::Expr(increment)]);
606 }
607
608 body = Stmt::While {
609 condition,
610 body: Box::new(body),
611 };
612
613 if let Some(initialiser) = initialiser {
614 body = Stmt::Block(vec![initialiser, body]);
615 }
616
617 Ok(body)
618 }
619
620 fn if_statement(input: ParseStream) -> Result<Self> {
621 let _: kw::kw_if = input.parse()?;
622 let content;
623 let _: Parentheses = group!(content in input);
624 let condition = content.parse()?;
625
626 let then_branch = Box::new(Stmt::statement(input)?);
627 let else_branch = if input.peek(kw::kw_else) {
628 Some(Box::new(Stmt::statement(input)?))
629 } else {
630 None
631 };
632
633 Ok(Stmt::If {
634 condition,
635 then_branch,
636 else_branch,
637 })
638 }
639
640 fn print_statement(input: ParseStream) -> Result<Self> {
641 let _: kw::print = input.parse()?;
642 let value = input.parse()?;
643 let _: Punct![";"] = input.parse()?;
644 Ok(Self::Print(value))
645 }
646
647 fn return_statement(input: ParseStream) -> Result<Self> {
648 let keyword: kw::kw_return = input.parse()?;
649 let value = if input.peek(Punct![";"]) {
650 None
651 } else {
652 Some(input.parse()?)
653 };
654 let _: Punct![";"] = input.parse()?;
655 Ok(Stmt::Return { keyword, value })
656 }
657
658 fn while_statement(input: ParseStream) -> Result<Self> {
659 let _: kw::kw_while = input.parse()?;
660 let content;
661 let _: Parentheses = group!(content in input);
662 let condition = content.parse()?;
663 let body = Box::new(Stmt::statement(input)?);
664
665 Ok(Stmt::While { condition, body })
666 }
667
668 fn expression_statement(input: ParseStream) -> Result<Self> {
669 let expr = input.parse()?;
670 let _: Punct![";"] = input.parse()?;
671 Ok(Self::Expr(expr))
672 }
673}
674
675impl Parse for Stmt {
676 fn parse(input: ParseStream) -> Result<Self> {
677 Stmt::declaration(input)
678 }
679}
680
681struct Ast(Vec<Stmt>);
682
683impl Ast {
684 #[allow(clippy::wildcard_imports)]
685 fn synchronise(input: ParseStream) {
686 input.synchronise(|input| {
687 use kw::*;
688 input.peek(Punct![";"]) && !input.peek2(Punct!["}"])
689 || peek2_any!(input, class, kw_for, fun, kw_if, print, kw_return, var, kw_while)
690 });
691 }
692}
693
694impl Parse for Ast {
695 fn parse(input: ParseStream) -> Result<Self> {
696 let mut stmts = vec![];
697
698 while !input.is_empty() {
699 match input.parse() {
700 Ok(stmt) => stmts.push(stmt),
701 Err(err) => {
702 Ast::synchronise(input);
703 input.add_error(err);
704 }
705 }
706 }
707
708 input.get_error().map_or(Ok(Ast(stmts)), Err)
709 }
710}
711
712fn main() {
713 let ast: Ast = pretty_unwrap(parse_string(
714 r#"
715 var x = 5;
716 var y = "hello";
717 x = 6;
718 y = 4.0;
719
720 fun add(x, y) {
721 return x + y;
722 }
723
724 print(add(x, y));
725
726 class Cake {
727 init(flavour) {
728 this.flavour = flavour;
729 }
730
731 taste() {
732 var adjective = "delicious";
733 print "The " + this.flavour + " cake is " + adjective + "!";
734 }
735 }
736
737 class ChocolateCake < Cake {
738 init() {
739 this.flavour = "Chocolate";
740 }
741
742 taste() {
743 super.taste();
744 print "Mmm, chocolatey!";
745 }
746 }
747
748 var cake = ChocolateCake();
749 cake.taste();
750 "#
751 .to_string(),
752 ));
753 pretty_unwrap(resolver::resolve(&ast));
754 pretty_unwrap(interpreter::interpret(ast));
755}