lox/
main.rs

1//! A parser and interpreter for the Lox language from
2//! [`Crafting Interpreters`].
3//!
4//! [Crafting Interpreters]: https://craftinginterpreters.com
5
6use 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}