From c4a32895df39d64c099d2d7f9cb0acbfd12e92e2 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 21 Jan 2024 05:32:18 -0600 Subject: [PATCH] conlang 0.3.0: Total grammar overhaul - Rewrote the grammar - Rewrote the AST - Rewrote the Parser - Removed pretty printer (now handled by ast::ast_impl::Pretty, a Writer wrapper) - Added items, and new keywords to go with them - Syntax is ~maybe temporary, based on Rust syntax --- Cargo.toml | 2 +- cl-frontend/src/lib.rs | 233 ++-- grammar.ebnf | 178 ++- libconlang/src/ast.rs | 1309 +++++++----------- libconlang/src/ast/ast_impl.rs | 744 +++++++++++ libconlang/src/interpreter.rs | 839 +++++++----- libconlang/src/interpreter/tests.rs | 33 +- libconlang/src/lib.rs | 2 - libconlang/src/parser.rs | 1920 ++++++++++++++++----------- libconlang/src/pretty_printer.rs | 460 ------- libconlang/src/resolver.rs | 714 +++++----- libconlang/src/token/token_type.rs | 12 + 12 files changed, 3541 insertions(+), 2905 deletions(-) create mode 100644 libconlang/src/ast/ast_impl.rs delete mode 100644 libconlang/src/pretty_printer.rs diff --git a/Cargo.toml b/Cargo.toml index 1db2e31..2e6a538 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ resolver = "2" [workspace.package] repository = "https://git.soft.fish/j/Conlang" -version = "0.0.2" +version = "0.0.3" authors = ["John Breaux "] edition = "2021" license = "MIT" diff --git a/cl-frontend/src/lib.rs b/cl-frontend/src/lib.rs index ad9399e..506b096 100644 --- a/cl-frontend/src/lib.rs +++ b/cl-frontend/src/lib.rs @@ -1,4 +1,8 @@ //! Utilities for cl-frontend +//! +//! # TODO +//! - [ ] Readline-like line editing +//! - [ ] Raw mode? pub mod args { use crate::cli::Mode; @@ -14,7 +18,7 @@ pub mod args { pub repl: bool, // defaults true if stdin is terminal pub mode: Mode, // defaults Interpret } - const HELP: &str = "[( --repl | --no-repl )] [( -f | --file ) ]"; + const HELP: &str = "[( --repl | --no-repl )] [--mode (tokens | pretty | type | run)] [( -f | --file ) ]"; impl Args { pub fn new() -> Self { @@ -65,109 +69,132 @@ pub mod args { } pub mod program { - use std::io::{Result as IOResult, Write}; + use std::{fmt::Display, io::Write}; use conlang::{ - ast::preamble::{expression::Expr, *}, - interpreter::{env::Environment, error::IResult}, + ast::{self, ast_impl::format::Pretty}, + interpreter::{ + env::Environment, error::IResult, interpret::Interpret, temp_type_impl::ConValue, + }, + // pretty_printer::{PrettyPrintable, Printer}, lexer::Lexer, parser::{error::PResult, Parser}, - pretty_printer::{PrettyPrintable, Printer}, - resolver::{error::TyResult, Resolve, Resolver}, - token::Token, + resolver::{error::TyResult, Resolver}, }; - pub struct Tokenized { - tokens: Vec, - } + pub struct Parsable; pub enum Parsed { - Program(Start), - Expr(Expr), + File(ast::File), + Stmt(ast::Stmt), + Expr(ast::Expr), } - impl TryFrom for Parsed { - type Error = conlang::parser::error::Error; - fn try_from(value: Tokenized) -> Result { - let mut parser = Parser::new(value.tokens); - let ast = parser.parse()?; - //if let Ok(ast) = ast { - //return - Ok(Self::Program(ast)) - //} - - //Ok(Self::Expr(parser.reset().parse_expr()?)) - } - } - - pub struct Program { + pub struct Program<'t, Variant> { + text: &'t str, data: Variant, } - - impl Program { - pub fn new(input: &str) -> Result> { - let mut tokens = vec![]; - let mut errors = vec![]; - for token in Lexer::new(input) { - match token { - Ok(token) => tokens.push(token), - Err(error) => errors.push(error), - } - } - if errors.is_empty() { - Ok(Self { data: Tokenized { tokens } }) - } else { - Err(errors) - } - } - pub fn tokens(&self) -> &[Token] { - &self.data.tokens - } - pub fn parse(self) -> PResult> { - Ok(Program { data: Parsed::try_from(self.data)? }) + impl<'t, V> Program<'t, V> { + pub fn lex(&self) -> Lexer { + Lexer::new(self.text) } } - impl Program { - pub fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<()> { - match &mut self.data { - Parsed::Program(start) => start.resolve(resolver), - Parsed::Expr(expr) => expr.resolve(resolver), - } - .map(|ty| println!("{ty}")) + impl<'t> Program<'t, Parsable> { + pub fn new(text: &'t str) -> Self { + Self { text, data: Parsable } } - /// Runs the [Program] in the specified [Environment] - pub fn run(&self, env: &mut Environment) -> IResult<()> { - println!( - "{}", - match &self.data { - Parsed::Program(start) => env.eval(start)?, - Parsed::Expr(expr) => env.eval(expr)?, - } - ); - Ok(()) + pub fn parse(self) -> PResult> { + self.parse_file().or_else(|_| self.parse_stmt()) + } + pub fn parse_expr(&self) -> PResult> { + Ok(Program { data: Parsed::Expr(Parser::new(self.lex()).expr()?), text: self.text }) + } + pub fn parse_stmt(&self) -> PResult> { + Ok(Program { data: Parsed::Stmt(Parser::new(self.lex()).stmt()?), text: self.text }) + } + pub fn parse_file(&self) -> PResult> { + Ok(Program { data: Parsed::File(Parser::new(self.lex()).file()?), text: self.text }) } } - impl PrettyPrintable for Program { - fn visit(&self, p: &mut Printer) -> IOResult<()> { + impl<'t> Program<'t, Parsed> { + pub fn debug(&self) { match &self.data { - Parsed::Program(value) => value.visit(p), - Parsed::Expr(value) => value.visit(p), + Parsed::File(v) => eprintln!("{v:?}"), + Parsed::Stmt(v) => eprintln!("{v:?}"), + Parsed::Expr(v) => eprintln!("{v:?}"), + } + } + pub fn print(&self) { + let mut f = std::io::stdout().pretty(); + let _ = match &self.data { + Parsed::File(v) => writeln!(f, "{v}"), + Parsed::Stmt(v) => writeln!(f, "{v}"), + Parsed::Expr(v) => writeln!(f, "{v}"), + }; + // println!("{self}") + } + + pub fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<()> { + todo!("Program::resolve(\n{self},\n{resolver:?}\n)") + } + + pub fn run(&self, env: &mut Environment) -> IResult { + match &self.data { + Parsed::File(v) => v.interpret(env), + Parsed::Stmt(v) => v.interpret(env), + Parsed::Expr(v) => v.interpret(env), + } + } + + // pub fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<()> { + // match &mut self.data { + // Parsed::Program(start) => start.resolve(resolver), + // Parsed::Expr(expr) => expr.resolve(resolver), + // } + // .map(|ty| println!("{ty}")) + // } + + // /// Runs the [Program] in the specified [Environment] + // pub fn run(&self, env: &mut Environment) -> IResult<()> { + // println!( + // "{}", + // match &self.data { + // Parsed::Program(start) => env.eval(start)?, + // Parsed::Expr(expr) => env.eval(expr)?, + // } + // ); + // Ok(()) + // } + } + + impl<'t> Display for Program<'t, Parsed> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.data { + Parsed::File(v) => write!(f, "{v}"), + Parsed::Stmt(v) => write!(f, "{v}"), + Parsed::Expr(v) => write!(f, "{v}"), } } } + + // impl PrettyPrintable for Program { + // fn visit(&self, p: &mut Printer) -> IOResult<()> { + // match &self.data { + // Parsed::Program(value) => value.visit(p), + // Parsed::Expr(value) => value.visit(p), + // } + // } + // } } pub mod cli { - use conlang::{ - interpreter::env::Environment, pretty_printer::PrettyPrintable, resolver::Resolver, - token::Token, - }; + use conlang::{interpreter::env::Environment, resolver::Resolver, token::Token}; use crate::{ args::Args, - program::{Parsed, Program, Tokenized}, + program::{Parsable, Parsed, Program}, }; use std::{ convert::Infallible, @@ -220,35 +247,30 @@ pub mod cli { } fn no_repl(mode: Mode, path: Option<&Path>, code: &str) { let program = Program::new(code); - match (mode, program) { - (Mode::Tokenize, Ok(program)) => { - for token in program.tokens() { + match mode { + Mode::Tokenize => { + for token in program.lex() { if let Some(path) = path { print!("{}:", path.display()); } - print_token(token) - } - } - (Mode::Beautify, Ok(program)) => Self::beautify(program), - (Mode::Resolve, Ok(program)) => Self::resolve(program, Default::default()), - (Mode::Interpret, Ok(program)) => Self::interpret(program, Environment::new()), - (_, Err(errors)) => { - for error in errors { - if let Some(path) = path { - eprint!("{}:", path.display()); + match token { + Ok(token) => print_token(&token), + Err(e) => println!("{e}"), } - eprintln!("{error}") } } + Mode::Beautify => Self::beautify(program), + Mode::Resolve => Self::resolve(program, Default::default()), + Mode::Interpret => Self::interpret(program, Environment::new()), } } - fn beautify(program: Program) { + fn beautify(program: Program) { match program.parse() { Ok(program) => program.print(), Err(e) => eprintln!("{e}"), }; } - fn resolve(program: Program, mut resolver: Resolver) { + fn resolve(program: Program, mut resolver: Resolver) { let mut program = match program.parse() { Ok(program) => program, Err(e) => { @@ -260,7 +282,7 @@ pub mod cli { eprintln!("{e}"); } } - fn interpret(program: Program, mut interpreter: Environment) { + fn interpret(program: Program, mut interpreter: Environment) { let program = match program.parse() { Ok(program) => program, Err(e) => { @@ -301,10 +323,10 @@ pub mod cli { type Err = Infallible; fn from_str(s: &str) -> Result { Ok(match s { - "i" | "interpret" => Mode::Interpret, + "i" | "interpret" | "run" => Mode::Interpret, "b" | "beautify" | "p" | "pretty" => Mode::Beautify, - "r" | "resolve" | "typecheck" => Mode::Resolve, - "t" | "tokenize" => Mode::Tokenize, + "r" | "resolve" | "typecheck" | "type" => Mode::Resolve, + "t" | "tokenize" | "tokens" => Mode::Tokenize, _ => Mode::Interpret, }) } @@ -386,12 +408,12 @@ pub mod cli { continue; } // Lex the buffer, or reset and output the error - let code = match Program::new(&buf) { - Ok(code) => code, - Err(e) => { - for error in e { - eprintln!("{error}"); - } + let code = Program::new(&buf); + match code.lex().into_iter().find(|l| l.is_err()) { + None => (), + Some(Ok(_)) => unreachable!(), + Some(Err(error)) => { + eprintln!("{error}"); self.reprompt(&mut buf); continue; } @@ -451,9 +473,12 @@ pub mod cli { Mode::Interpret => self.interpret(code), } } - fn tokenize(&mut self, code: &Program) { - for token in code.tokens() { - print_token(token); + fn tokenize(&mut self, code: &Program) { + for token in code.lex() { + match token { + Ok(token) => print_token(&token), + Err(e) => println!("{e}"), + } } } fn interpret(&mut self, code: &Program) { diff --git a/grammar.ebnf b/grammar.ebnf index de51666..010c5c9 100644 --- a/grammar.ebnf +++ b/grammar.ebnf @@ -1,84 +1,130 @@ (* Conlang Expression Grammar *) -Start = Program ; -Program = Stmt* EOI ; -(* TODO: -- Replace Program with Module - Module = Decl* EOI ; -- Move Fn and Let into "Decl": - Decl = Fn | Let ; -- allow Decl | ExprStmt in Stmt: - Stmt = Decl | Expr ';' ; -*) -(* literal *) -Literal = STRING | CHARACTER | FLOAT | INTEGER | Bool ; -Bool = "true" | "false" ; -Identifier = IDENTIFIER ; +Start = File ; + +Mutability = "mut"? ; +Visibility = "pub"? ; + + +File = Item* EOI ; + + +Item = Visibility ( + Const | Static | Module + | Function | Struct | Enum + | Impl + ) ; + + +(* item *) +Const = "const" Identifier ':' Type = Expr ';' ; + +Static = "static" Mutability Identifier ':' Type = Expr ';' ; + +Module = "mod" Identifier '{' (Item)* '}' ; + +Function = "fn" Identifier '(' (Param ',')* Param? ')' ( '->' Type) Block ; +Param = Identifier ':' Type ; + +Struct = "struct" Identifier (TupleStruct | StructStruct)?; +StructStruct= '{' (Identifier ':' Type),* '}' ; +TupleStruct = TyTuple ; + +Enum = "enum" Identifier (TupleEnum | StructEnum)? ; +TupleEnum = TyTuple; +StructEnum = '{' (Identifier ':' Type)* '}' ; + -(* # Statements *) (* statement *) -Stmt = Fn | Let | Expr ';' ; -Let = "let" Name ('=' Expr)? ';' ; -Fn = "fn" Identifier '(' Params? ')' Block ; -(* TODO: Type system *) -Params = (Name ',')* Name? ; -Name = "mut"? Identifier (':' Type )? ; +Stmt = ';' | (Let | Item | Expr ';'?) ; +Let = "let" Mutability Identifier (':' Ty)? ('=' Expr)? ; +(* TODO: Closure syntax *) +Closure = "cl" '(' Param* ')' Block ; -(* # Type Expressions *) -(* types *) -TypeExpr = Never | Empty | TypeTuple | PathExpr ; + +(* type *) +Ty = Never | Empty | TyTuple | Path | TyRef | TyFn ; Never = '!' ; Empty = '(' ')' ; -TypeTuple = '(' (TypeExpr ',')* TypeExpr? ')' ; - -PathExpr = '::'? PathPart ; -PathPart = "super" | Identifier ; +TyTuple = '(' (Ty ',')* Ty? ')' ; +TyRef = ('&' | '&&')* Path ; +TyFn = "fn" TyTuple (-> Ty)? ; -(* # Expressions *) -(* expression *) +(* path *) +Path = '::'? PathPart ('::' PathPart)* ; +PathPart = "super" | "self" | Identifier ; +Identifier = IDENTIFIER ; + + +(* literal *) +Bool = "true" | "false" ; + + +(* expr *) +ExprKind = Assign | Compare | Range | Logic | Bitwise | Shift + | Factor | Term | Unary | Member | Call | Index + | Path | Literal | Array | ArrayRep | AddrOf + | Block | Group + | While | If | For | Break | Return | Continue ; + Expr = Assign ; -Block = '{' Stmt* Expr? '}' ; -Primary = Identifier | Literal - | Block | Group | Branch ; -(* expression::call *) -Call = FnCall | Primary ; -FnCall = Primary ('(' Tuple? ')')? ; +Assign = Path (AssignOp Assign ) | Compare ; -(* expression::tuple *) -Group = '(' Tuple? ')' ; -Tuple = Expr (',' Expr)* ; +Binary = Compare | Range | Logic | Bitwise | Shift | Factor | Term ; +Compare = Range (CompareOp Range )* ; +Range = Logic (RangeOp Logic )* ; +Logic = Bitwise (LogicOp Bitwise)* ; +Bitwise = Shift (BitwiseOp Shift )* ; +Shift = Factor (ShiftOp Factor )* ; +Factor = Term (FactorOp Term )* ; +Term = Unary (FactorOp Unary )* ; -(* expression::math *) -Assign = Identifier (AssignOp Assign) | Compare ; -Compare = Range (CompareOp Range )* ; -Range = Logic (RangeOp Logic )* ; -Logic = Bitwise (LogicOp Bitwise)* ; -Bitwise = Shift (BitwiseOp Shift )* ; -Shift = Term (ShiftOp Term )* ; -Term = Factor (TermOp Factor )* ; -Factor = Unary (FactorOp Unary )* ; -Unary = (UnaryOp)* Call ; +Unary = (UnaryOp)* Member ; -(* expression::math::operator *) -AssignOp = '=' | "+=" | "-=" | "*=" | "/=" | - "&=" | "|=" | "^=" |"<<=" |">>=" ; -CompareOp = '<' | "<=" | "==" | "!=" | ">=" | '>' ; -RangeOp = ".." | "..=" ; -LogicOp = "&&" | "||" | "^^" ; +Member = Call ('.' Call)* ; -BitwiseOp = '&' | '|' | '^' ; -ShiftOp = "<<" | ">>"; -TermOp = '+' | '-' ; -FactorOp = '*' | '/' | '%' ; -UnaryOp = '*' | '&' | '-' | '!' ; +Call = Index ('(' Tuple? ')')* ; -(* expression::control *) -Branch = While | If | For | Break | Return | Continue ; -If = "if" Expr Block (Else)? ; -While = "while" Expr Block (Else)? ; -For = "for" Identifier "in" Expr Block (Else)? ; -Else = "else" Expr ; +Index = Primary ('[' Indices ']')* ; +Indices = (Expr ',')* Expr? ; + +Primary = Literal | Path | Array | ArrayRep | AddrOf + | Block | Group + | If | While | For | Break | Return | Continue; + +Literal = STRING | CHARACTER | FLOAT | INTEGER | Bool ; + +Array = '[' (Expr ',')* Expr? ']' ; +ArrayRep = '[' Expr ';' Expr ']' ; + +AddrOf = ('&' | '&&')* Expr ; + +Block = '{' Stmt* '}'; + +Group = '(' (Empty | Expr | Tuple) ')' ; +Tuple = (Expr ',')* Expr? ; +Empty = ; + +While = "while" Expr Block Else? ; +If = "if" Expr Block Else? ; +For = "for" Identifier "in" Expr Block Else? ; +Else = "else" Expr ; Break = "break" Expr ; Return = "return" Expr ; Continue = "continue" ; + +AssignKind = '=' | '+=' | '-=' | '*=' | '/=' | + '&=' | '|=' | '^=' |'<<=' |'>>=' ; + +BinaryKind = CompareOp | RangeOp | LogicOp | BitwiseOp + | ShiftOp | TermOp | FactorOp ; +CompareOp = '<' | '<=' | '==' | '!=' | '>=' | '>' ; +RangeOp = '..' | '..=' ; +LogicOp = '&&' | '||' | '^^' ; +BitwiseOp = '&' | '|' | '^' ; +ShiftOp = '<<' | '>>'; +TermOp = '+' | '-' ; +FactorOp = '*' | '/' | '%' ; + +UnaryKind = '*' | '-' | '!' | '@' | '#' | '~' ; diff --git a/libconlang/src/ast.rs b/libconlang/src/ast.rs index 24614b5..2873578 100644 --- a/libconlang/src/ast.rs +++ b/libconlang/src/ast.rs @@ -1,830 +1,519 @@ //! # The Abstract Syntax Tree //! Contains definitions of AST Nodes, to be derived by a [parser](super::parser). //! -//! ## Syntax -//! [`Start`]` := `[`Program`] \ -//! [`Program`]` := `[`statement::Stmt`]`* EOI` \ -//! [`Identifier`]` := `[`IDENTIFIER`](crate::token::token_type::Type::Identifier) +//! # Notable nodes +//! - [Item] and [ItemKind]: Top-level constructs +//! - [Stmt] and [StmtKind]: Statements +//! - [Expr] and [ExprKind]: Expressions +//! - [Assign], [Binary], and [Unary] expressions +//! - [AssignKind], [BinaryKind], and [UnaryKind] operators +//! - [Ty] and [TyKind]: Type qualifiers +//! - [Path]: Path expressions //! -//! See [statement], [literal], and [expression] for more information. -#![deprecated] -pub mod preamble { - #![allow(deprecated)] - //! Common imports for working with the [ast](super) - pub use super::{ - expression::{call::*, control::*, math::*, tuple::*, *}, - literal::*, - path::*, - statement::*, - types::*, - *, - }; +//! # Notable structures +//! - [struct@Span]: Stores the start and end [struct@Loc] of a notable AST node +//! - [struct@Loc]: Stores the line/column of a notable AST node +#![allow(non_snake_case)] + +pub mod ast_impl; + +// Universal data types + +/// Stores the start and end [locations](struct@Loc) within the token stream +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Span { + pub head: Loc, + pub tail: Loc, +} +pub fn Span(head: Loc, tail: Loc) -> Span { + Span { head, tail } } -/// Marks the root of a tree -/// # Syntax -/// [`Start`]` := `[`Program`] -#[derive(Clone, Debug)] -pub struct Start(pub Program); - -/// Contains an entire Conlang program -/// # Syntax -/// [`Program`]` := `[`statement::Stmt`]`* EOI` -#[derive(Clone, Debug)] -pub struct Program(pub Vec); - -/// An Identifier stores the name of an item -/// # Syntax -/// [`Identifier`]` := `[`IDENTIFIER`](crate::token::token_type::Type::Identifier) -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Identifier { - pub name: String, - pub index: Option, +/// Stores a read-only (line, column) location in a token stream +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Loc { + line: u32, + col: u32, } - -pub mod literal { - //! # Literal Expressions - //! Evaluate to the literal they contain - //! # Syntax - //! ```ignore - //! Literal := String | Char | Float | Int - //! String := STRING - //! Float := FLOAT - //! Char := CHARACTER - //! Bool := TRUE | FALSE - //! Int := INTEGER - //! ``` - - /// Represents a literal value - /// # Syntax - /// [`Literal`]` := `[`String`]` | `[`char`]` | `[`bool`]` | `[`Float`]` | `[`u128`] - #[derive(Clone, Debug)] - pub enum Literal { - /// Represents a literal string value - /// # Syntax - /// [`Literal::String`]` := `[`STRING`](crate::token::token_type::Type::String) - String(String), - /// Represents a literal [char] value - /// # Syntax - /// [`Literal::Char`]` := `[`CHARACTER`](crate::token::token_type::Type::Character) - Char(char), - /// Represents a literal [bool] value - /// # Syntax - /// [`Literal::Bool`] := - /// [`TRUE`](crate::token::token_type::Keyword::True) - /// | [`FALSE`](crate::token::token_type::Keyword::False) - Bool(bool), - /// Represents a literal float value - /// # Syntax - /// [`Float`]` := `[`FLOAT`](crate::token::token_type::Type::Float) - Float(Float), - /// Represents a literal integer value - /// # Syntax - /// [`u128`]` := `[`INTEGER`](crate::token::token_type::Type::Integer) - Int(u128), +pub fn Loc(line: u32, col: u32) -> Loc { + Loc { line, col } +} +impl Loc { + pub fn line(self) -> u32 { + self.line } - - /// Represents a literal float value - /// # Syntax - /// [`Float`]` := `[`FLOAT`](crate::token::token_type::Type::Float) - #[derive(Clone, Debug)] - pub struct Float { - pub sign: bool, - pub exponent: i32, - pub mantissa: u64, + pub fn col(self) -> u32 { + self.col } } -pub mod statement { - //! # Statements - //! A statement is an expression which evaluates to Empty - //! - //! # Syntax - //! [`Stmt`]` := `[`Let`](Stmt::Let)` | `[`Expr`](Stmt::Expr) - //! [`Let`](Stmt::Let)` := "let"` [`Identifier`] (`:` `Type`)? (`=` [`Expr`])? `;` - //! [`Expr`](Stmt::Expr)` := `[`Expr`] `;` - - use super::{ - expression::{Block, Expr}, - types::TypeExpr, - Identifier, - }; - - /// Contains a statement - /// # Syntax - /// [`Stmt`]` := `[`Let`](Stmt::Let)` | `[`Expr`](Stmt::Expr) - #[derive(Clone, Debug)] - pub enum Stmt { - /// Contains a variable declaration - /// # Syntax - /// [`Let`](Stmt::Let) := `"let"` [`Identifier`] (`:` `Type`)? (`=` [`Expr`])? `;` - Let(Let), - /// Contains a function declaration - /// # Syntax - /// [`Fn`](Stmt::Fn) := `"fn"` [`Identifier`] `'('` `Args...` `')'` [`Block`] - Fn(FnDecl), - /// Contains a module declaration - /// # Syntax - /// [`Mod`](Stmt::Mod) := `"mod"` [`Identifier`] `'{'` - /// - /// `'}'` - /// Contains an expression statement - /// # Syntax - /// [`Expr`](Stmt::Expr) := [`Expr`] `;` - Expr(Expr), - } - - /// Contains the declarations allowed in a module - /// - /// # Syntax - /// [Mod](Module::Mod) := "mod" [Identifier] '{' [Module] '}' - /// [`Let`](Module::Let) := `"let"` [`Identifier`] (`:` `Type`)? (`=` [`Expr`])? `;` - #[derive(Clone, Debug)] - pub enum Module { - Struct(StructDecl), - Mod(ModuleDecl), - Let(Let), - Fn(FnDecl), - } - - /// Contains a variable declaration - /// # Syntax - /// [`Let`] := `let` [`Identifier`] (`:`) `Type`)? (`=` [`Expr`])? `;` - #[derive(Clone, Debug)] - pub struct Let { - pub name: Name, - pub init: Option, - } - - /// Contains a function declaration - /// # Syntax - /// [`FnDecl`] := `"fn"` [`Identifier`] `'('` `Args...` `')'` - #[derive(Clone, Debug)] - pub struct FnDecl { - pub name: Name, - pub args: Vec, - pub body: Block, - // TODO: Store type information - } - - /// Contains the name, mutability, and type information for a [Let] or [FnDecl] - /// # Syntax - #[derive(Clone, Debug)] - pub struct Name { - pub symbol: Identifier, - /// The mutability of the [Name]. Functions are never mutable. - pub mutable: bool, - /// The [type](TypeExpr) - pub ty: Option, - } - - /// Contains the name and declaration - #[derive(Clone, Debug)] - pub struct ModuleDecl {} - - // TODO: Create closure, transmute fndecl into a name and closure - /// Contains the name and field information for a struct - /// - /// # Syntax - /// [`StructDecl`]` := "struct" `[`Identifier`]` '{' - /// (`[`Identifier`]` ':' `[`TypeExpr`]`),* - /// '}'` - #[derive(Clone, Debug)] - pub struct StructDecl { - pub name: Identifier, - pub data: Vec<(Identifier, TypeExpr)>, - } +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] +pub enum Mutability { + #[default] + Not, + Mut, } -pub mod path { - //! Paths - //! - //! A Path Expression refers to an item, either local or module-scoped. - - use super::Identifier; - - /// A path to an item in a module - /// # Syntax - /// [`Path`]` := "::"? `[`PathPart`]` ("::" `[`PathPart`]`)*` - #[derive(Clone, Debug)] - pub struct Path { - pub absolute: bool, - pub parts: Vec, - } - - /// A component of a [`Path`] - /// # Syntax - /// [`PathPart`]` := "super" | `[`Identifier`] - #[derive(Clone, Debug)] - pub enum PathPart { - PathSuper, - PathSelf, - PathIdent(Identifier), - } +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] +pub enum Visibility { + #[default] + Private, + Public, } -pub mod types { - //! # Types - //! - //! The [Type Expresson](TypeExpr) powers Conlang's type checker. - //! - //! # Syntax - //! [`TypeExpr`]` := `[`TupleType`]` | `[`TypePath`]` | `[`Never`] - - pub use super::path::Path as TypePath; - - /// Contains a [Type Expression](self) - /// - /// # Syntax - /// [`TypeExpr`]` := `[`TupleType`]` | `[`TypePath`]` | `[`Empty`]` | `[`Never`] - #[derive(Clone, Debug)] - pub enum TypeExpr { - TupleType(TupleType), - TypePath(TypePath), - Empty(Empty), - Never(Never), - } - - /// A [TupleType] represents the [TypeExpr] of a Tuple value - #[derive(Clone, Debug)] - pub struct TupleType { - pub types: Vec, - } - - /// The empty type. You get nothing! You lose! - /// # Syntax - /// [`Empty`]` := '(' ')'` - #[derive(Clone, Copy, Debug, Default)] - pub struct Empty; - - /// The never type. This type can never be constructed, and can only appear if a block of code - /// doesn't terminate - /// # Syntax - /// [`Never`]` := '!'` - #[derive(Clone, Copy, Debug, Default)] - pub struct Never; +#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] +pub struct File { + pub items: Vec, } -pub mod expression { - //! # Expressions - //! - //! The [expression] is the backbone of Conlang: almost everything is an expression. - //! - //! ## Grammar - //! Higher number = higher precedence. - //! - //! | # | Node | Function - //! |---|------------------:|:---------------------------------------------- - //! | 0 | [`Expr`] | Contains an expression - //! | 1 | [`Assign`](math) | Assignment - //! | 2 | [`Compare`](math) | Value Comparison - //! | 3 | [`Logic`](math) | Boolean And, Or, Xor - //! | 4 | [`Bitwise`](math) | Bitwise And, Or, Xor - //! | 5 | [`Shift`](math) | Shift Left/Right - //! | 6 | [`Term`](math) | Add, Subtract - //! | 7 | [`Factor`](math) | Multiply, Divide, Remainder - //! | 8 | [`Unary`](math) | Unary Dereference, Reference, Negate, Not - //! | 9 | [`control::Flow`] | Branch expressions (`if`, `while`, `for`, `return`, `break`, `continue`) - //! | 9 | [`Group`] | Group expressions `(` [Expr]? `)` /* Can evaluate to Empty! */ - //! | 9 | [`Block`] | Block expressions `{` [Expr] `}` - //! | 9 | [`Primary`] | Contains an [Identifier], [Literal], [Block], [Group], or [Flow] - //! - //! ## Syntax - //! [`Expr`]` := `[`math::Operation`] \ - //! [`Block`]` := '{' `[`Expr`]` '}'` \ - //! [`Group`]` := '(' `[`Expr`]`? ')'` \ - //! [`Primary`]` := `[`Identifier`]` | `[`Literal`]` | `[`Block`]` | - //! `[`Group`]` | `[`Flow`] - //! - //! See [control] and [math] for their respective production rules. - use super::{literal::Literal, statement::Stmt, *}; - use control::Flow; - use tuple::Group; - - /// Contains an expression - /// - /// # Syntax - /// [`Expr`]` := `[`math::Operation`] - #[derive(Clone, Debug)] - pub struct Expr(pub math::Operation); - - /// A [Primary] Expression is the expression with the highest precedence (i.e. the deepest - /// derivation) - /// # Syntax - /// [`Primary`]` := `[`Identifier`]` - /// | `[`Literal`]` - /// | `[`Block`]` - /// | `[`Group`]` - /// | `[`Branch`](Flow) - #[derive(Clone, Debug)] - pub enum Primary { - Identifier(Identifier), - Literal(Literal), - Block(Block), - Group(Group), - Branch(Flow), - } - - /// Contains a Block Expression - /// # Syntax - /// [`Block`] := `'{'` [`Expr`] `'}'` - #[derive(Clone, Debug)] - pub struct Block { - pub let_count: Option, - pub statements: Vec, - pub expr: Option>, - } - - pub mod call { - //! [Function](FnCall) and [Method](todo) Call Expressions - //! - //! # Syntax - //! [`Call`]` := `[`FnCall`]` | `[`Primary`] - //! - //! [`FnCall`]` := `[`Primary`]` (`[`Tuple`]`)*` - use super::{tuple::Tuple, Primary}; - #[derive(Clone, Debug)] - pub enum Call { - /// Contains a [Function Call Expression](FnCall) - FnCall(FnCall), - /// Contains only a [Primary] expression - Primary(Primary), - } - - /// Contains a Function Call Expression - #[derive(Clone, Debug)] - pub struct FnCall { - pub callee: Box, - pub args: Vec, - } - #[allow(non_snake_case)] - pub fn FnCall(callee: Box, args: Vec) -> FnCall { - FnCall { callee, args } - } - } - - pub mod tuple { - //! A [Tuple] expression contains an arbitrary number of sub-expressions - use super::Expr; - /// Contains a [Tuple], [`(Expr)`](Group::Single), - /// or [Empty](Group::Empty) - /// # Syntax - /// [`Group`]`:= '('(`[`Expr`]` | `[`Tuple`]`)?')'` - #[derive(Clone, Debug)] - pub enum Group { - /// Contains a variety of elements - /// # Syntax - /// [`Group::Tuple`]`:= '('`[`Tuple`]`')'` - Tuple(Tuple), - /// Contains a single element - /// # Syntax - /// [`Group::Single`]`:= '('`[`Expr`]`')'` - Single(Box), - /// Contains no elements - /// # Syntax - /// [`Group::Empty`]`:= '(' ')'` - Empty, - } - - /// Contains a heterogeneous collection of sub-expressions - /// # Syntax - #[derive(Clone, Debug)] - pub struct Tuple { - pub elements: Vec, - } - } - - pub mod math { - //! # Arithmetic and Logical Expressions - //! - //! ## Precedence Order - //! Operator associativity is always left-to-right among members of the same group - //! - //! | # | Name | Operators | Associativity - //! |---|-----------:|:----------------------------------------|--------------- - // | | TODO: Try | `?` | - //! | 1 | [Unary][1]| [`*` `&` `-` `!`][4] | Right - //! | 2 | [Factor][2]| [`*` `/` `%`][5] | Left to Right - //! | 3 | [Term][2]| [`+` `-`][5] | Left to Right - //! | 4 | [Shift][2]| [`<<` `>>`][5] | Left to Right - //! | 5 |[Bitwise][2]| [`&` |][4] | Left to Right - //! | 6 | [Logic][2]| [`&&` || `^^`][5]| Left to Right - //! | 7 |[Compare][2]| [`<` `<=` `==` `!=` `>=` `>`][5] | Left to Right - #![doc = concat!( //| | - r" | 8 | [Assign][3]| [`*=`, `/=`, `%=`, `+=`, `-=`, ", //| - /* | | |*/ r"`&=`, |=, ", //| - /* | | |*/ r"`^=`, `<<=`, `>>=`][6]", r"| Left to Right")] - //! - //! - //! - //! ## Syntax - //! All precedence levels other than [Unary][1] fold into [Binary][2] - //! - //! [`Assign`][3]` := `[`Compare`][2]` (`[`AssignOp`][6]` `[`Compare`][2]`)*` \ - //! [`Compare`][2]` := `[`Logic`][2]` (`[`CompareOp`][5]` `[`Logic`][2]` )*` \ - //! [`Logic`][2]` := `[`Bitwise`][2]` (`[`LogicOp`][5]` `[`Bitwise`][2]`)*` \ - //! [`Bitwise`][2]` := `[`Shift`][2]` (`[`BitwiseOp`][5]` `[`Shift`][2]` )*` \ - //! [`Shift`][2]` := `[`Term`][2]` (`[`ShiftOp`][5]` `[`Term`][2]` )*` \ - //! [`Term`][2]` := `[`Factor`][2]` (`[`TermOp`][5]` `[`Factor`][2]` )*` \ - //! [`Factor`][2]` := `[`Unary`][1]` (`[`FactorOp`][5]` `[`Unary`][1]` )*` \ - //! [`Unary`][1]` := (`[`UnaryOp`][4]`)* `[`Call`] - //! - //! [1]: Operation::Unary - //! [2]: Operation::Binary - //! [3]: Operation::Assign - //! [4]: operator::Unary - //! [5]: operator::Binary - //! [6]: operator::Assign - use super::{call::Call, *}; - - /// An Operation is a tree of [operands](Primary) and [operators](operator). - #[derive(Clone, Debug)] - pub enum Operation { - /// [`Assign`](Operation::Assign) := - /// [`Identifier`] [`operator::Assign`] [`Operation`] | [`Operation`] - Assign(Assign), - /// [`Binary`](Operation::Binary) := - /// [`Operation`] ([`operator::Binary`] [`Operation`])* - Binary(Binary), - /// [`Unary`](Operation::Unary) := ([`operator::Unary`])* - /// [`Call`](Operation::Call) - Unary(Unary), - /// [`Call`](Operation::Call) := [`expression::call::Call`] - Call(Call), - } - - /// [`Assign`] := [`Identifier`] [`operator::Assign`] [`Operation`] | [`Operation`] - #[derive(Clone, Debug)] - pub struct Assign { - pub target: Identifier, - pub operator: operator::Assign, - pub init: Box, - } - - /// [`Binary`] := [`Operation`] ([`operator::Binary`] [`Operation`])* - #[derive(Clone, Debug)] - pub struct Binary { - pub first: Box, - pub other: Vec<(operator::Binary, Operation)>, - } - - /// [`Unary`] := ([`operator::Unary`])* [`Call`](Operation::Call) - #[derive(Clone, Debug)] - pub struct Unary { - pub operators: Vec, - pub operand: Box, - } - - pub mod operator { - //! # [Unary], [Binary], and [Assign] operators - //! - //! An Operator represents the action taken during an [operation](super::Operation) - - /// # Operators which take a single argument - /// - /// (`*`, `&`, `-`, `!`, `@`, `#`, `~`) - #[derive(Clone, Copy, Debug, PartialEq, Eq)] - pub enum Unary { - /// `&&`: Take a reference, twice - RefRef, - /// `&`: Take a reference - Ref, - /// `*`: Dereference - Deref, - /// `-`: Arithmetic negation - Neg, - /// `!`: Binary/Boolean negation - Not, - /// `@`: Undefined - At, - /// `#`: Undefined - Hash, - /// `~`: Undefined - Tilde, - } - /// # Operators which take two arguments - /// ## Term operators: - /// [`*`](Binary::Mul), [`/`](Binary::Div), [`%`](Binary::Rem) - /// ## Factor operators - /// [`+`](Binary::Add), [`-`](Binary::Sub) - /// ## Shift operators - /// [`<<`](Binary::Lsh), [`>>`](Binary::Rsh) - /// ## Bitwise operators - /// [`&`](Binary::BitAnd), [`|`](Binary::BitOr), [`^`](Binary::BitXor) - /// ## Logic operators - /// [`&&`](Binary::LogAnd), [`||`](Binary::LogOr), [`^^`](Binary::LogXor) - /// ## Range operators - /// [`..`](Binary::RangeExc), [`..=`](Binary::RangeInc) - /// ## Comparison operators - /// [`<`](Binary::Less), [`<=`](Binary::LessEq), [`==`](Binary::Equal), - /// [`!=`](Binary::NotEq), [`>=`](Binary::GreaterEq), [`>`](Binary::Greater), - #[derive(Clone, Copy, Debug, PartialEq, Eq)] - pub enum Binary { - /// `*`: Multiplication - Mul, - /// `/`: Division - Div, - /// `%`: Remainder - Rem, - /// `+`: Addition - Add, - /// `-`: Subtraction - Sub, - /// `<<`: Left Shift - Lsh, - /// `>>`: Right Shift - Rsh, - /// `&`: Bitwise AND - BitAnd, - /// `|`: Bitwise OR - BitOr, - /// `^`: Bitwise XOR - BitXor, - /// `&&`: Short-circuiting logical AND - LogAnd, - /// `||`: Short-circuiting logical OR - LogOr, - /// `^^`: **Non-short-circuiting** logical XOR - LogXor, - /// `..`: Exclusive range - RangeExc, - /// `..=`: Inclusive range - RangeInc, - /// `<`: Less-than Comparison - Less, - /// `<=`: Less-than or Equal Comparison - LessEq, - /// `==`: Equal Comparison - Equal, - /// `!=`: Not Equal Comparison - NotEq, - /// `>=`: Greater-than or Equal Comparison - GreaterEq, - /// `>`: Greater-than Comparison - Greater, - } - - /// # Assignment operators - /// [`=`](Assign::Assign), [`+=`](Assign::AddAssign), [`-=`](Assign::SubAssign), - /// [`*=`](Assign::MulAssign), [`/=`](Assign::DivAssign), [`%=`](Assign::RemAssign), - /// [`&=`](Assign::BitAndAssign), [`|=`](Assign::BitOrAssign), - /// [`^=`](Assign::BitXorAssign) [`<<=`](Assign::ShlAssign), - /// [`>>=`](Assign::ShrAssign) - #[derive(Clone, Copy, Debug, PartialEq, Eq)] - pub enum Assign { - /// `=`: Assignment - Assign, - /// `+=`: Additive In-place Assignment - AddAssign, - /// `-=`: Subtractive In-place Assignment - SubAssign, - /// `*=`: Multiplicative In-place Assignment - MulAssign, - /// `/=`: Divisive In-place Assignment - DivAssign, - /// `%=`: Remainder In-place Assignment - RemAssign, - /// `&=`: Bitwise-AND In-place Assignment - BitAndAssign, - /// `|=`: Bitwise-OR In-place Assignment - BitOrAssign, - /// `^=`: Bitwise-XOR In-place Assignment - BitXorAssign, - /// `<<=`: Left Shift In-place Assignment - ShlAssign, - /// `>>=`: Right Shift In-place Assignment - ShrAssign, - } - } - } - - pub mod control { - //! # Control Flow Expressions - //! ## Conditional Branch Expressions - //! [`if` expressions][1] split a program's control flow based on a boolean - //! condition. \ - //! It is equivalent to a [`while` expression][2] that runs at most once. - //! - //! [`while` expressions][2] repeat a block of code (the loop body) until either - //! - a boolean condition fails - //! - a value is returned from the loop with a [`break` expression][5] - //! - //! [`for` expressions][3] repeat a block of code (the loop body) until either - //! - an iterable expression fails to return a value - //! - a value is returned from the loop with a [`break` expression][5] - //! - //! [`else` expressions][4] are evaluated when the body of a - //! conditional branch expression does not return a value: - //! - If the body was never run (`if false`, `while false`) - //! - If the loop exited without encountering a [`break` expression][5] - //! ## Unconditional Branch Expressions - //! [`break` expressions][5] return a value from within a loop - //! - //! [`return` expressions][6] return a value from within a function - //! - //! [`continue` expressions][7] skip to the next iteration of a loop - //! # Syntax - //! [`Flow`]`  := `[`While`]` | `[`If`]` | `[`For`]` | - //! `[`Break`]` | `[`Return`]` | `[`Continue`] \ - //! - //! [`While`]` := "while" `[`Expr`]` `[`Block`]` `[`Else`]`?` \ - //! [`If`]` := "if" `[`Expr`]` `[`Block`]` `[`Else`]`?` \ - //! [`For`]` := "for" `[`Identifier`]` "in" `[`Expr`]` `[`Block`]` `[`Else`]`?` \ - //! [`Else`]` := "else" `[`Expr`] \ - //! - //! [`Break`]`  := "break" `[`Expr`] \ - //! [`Return`]`  := "return" `[`Expr`] \ - //! [`Continue`]` := "continue"` - //! - //! [1]: If - //! [2]: While - //! [3]: For - //! [4]: Else - //! [5]: Break - //! [6]: Return - //! [7]: Continue - use super::*; - - /// Contains a [Control Flow Expression](control). - /// - /// See the module-level documentation for more information. - /// - /// [While], [If], [For], [Continue], [Return], or [Break] - #[derive(Clone, Debug)] - pub enum Flow { - /// Represents a [`while` expression](While) - While(While), - /// Represents a [`if` expression](If) - If(If), - /// Represents a [`for` expression](For) - For(For), - /// Represents a [`continue` expression](Continue) - Continue(Continue), - /// Represents a [`return` expression](Return) - Return(Return), - /// Represents a [`break` expression](Break) - Break(Break), - } - - /// Represents a [`while` loop](control). - /// - /// A [`while` expression](While) contains a [loop condition expression](Expr), - /// a [block expression, (the loop body,)](Block) and - /// an optional¹ [else expression](Else). - /// - /// ¹ A value can be returned from within the body using a - /// [`break` expression](Break) \ - /// If a `break` expression is used in this way, the `else` block is mandatory. - /// - /// # Examples - /// ```rust,ignore - /// let var = while boolean_variable { - /// break true - /// } else { - /// false - /// } - /// ``` - /// # Syntax - /// [`While`] := `"while"` [`Expr`] [`Block`] [`Else`]`?` - #[derive(Clone, Debug)] - pub struct While { - pub cond: Box, - pub body: Block, - pub else_: Option, - } - - /// Represents an [`if`-`else` control flow structure](control). - /// - /// An [`if` expression](If) contains a [condition expression](Expr), - /// a [block expression](Block) to be executed, - /// and an optional¹ [`else` block](Else). - /// - /// ¹ If the body evaluates to anything other than the Empty type, - /// the `else` block is mandatory. - /// # Syntax - /// [`If`] := `"if"` [`Expr`] [`Block`] [`Else`]`?` - #[derive(Clone, Debug)] - pub struct If { - pub cond: Box, - pub body: Block, - pub else_: Option, - } - - /// Represents a [`for` loop](control). - /// - /// A [`for` expression](For) contains a [loop variable](Identifier), - /// an [iterable expression, (TBD,)](Expr), - /// a [block expression(the loop body)](Block), - /// and an optional¹ [`else` block](Else) - /// - /// - /// ¹ A value can be returned from within the body using a - /// [`break` expression](Break) \ - /// If a `break` expression is used in this way, the `else` block is mandatory. - /// # Syntax - /// [`For`] := `"for"` [`Identifier`] `"in"` [`Expr`]² [`Block`] [`Else`]`?` - /// - /// ² [`Expr`] returns something Iterable - #[derive(Clone, Debug)] - pub struct For { - pub var: Identifier, - pub iter: Box, - pub body: Block, - pub else_: Option, - } - - /// Represents an [`else` block](control). - /// - /// An [`else` expression](Else) contains instructions to be executed if - /// the corresponding body refused to produce a value. In the case of - /// [`if` expressions](If), this happens if the condition fails. - /// In the case of loop ([`while`](While), [`for`](For))expressions, - /// this executes when the loop does *not* [`break`](Break). - /// - /// If one of the aforementioned control flow expressions evaluates - /// to something other than the Empty type, this block is mandatory. - /// - /// # Syntax - /// [`Else`] := `"else"` [`Expr`] - #[derive(Clone, Debug)] - pub struct Else { - pub expr: Box, - } - - /// Represents a [`continue` expression][control] - /// - /// # Syntax - /// [`Continue`] := `"continue"` - #[derive(Clone, Debug)] - pub struct Continue; - - /// Represents a [`break` expression][control]. - /// - /// # Syntax - /// [`Break`] := `"break"` [`Expr`] - #[derive(Clone, Debug)] - pub struct Break { - pub expr: Box, - } - /// Represents a [`return` expression][control]. - /// - /// # Syntax - /// [`Return`] := `"return"` [`Expr`] - #[derive(Clone, Debug)] - pub struct Return { - pub expr: Box, - } - } +// Items +/// Holds an abstract Item and associated metadata +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Item { + pub extents: Span, + pub vis: Visibility, + pub kind: ItemKind, } -pub mod todo { - //! temporary storage for pending expression work. \ - //! when an item is in progress, remove it from todo. - //! - //! # General TODOs: - //! - [x] REMOVE VISITOR TRAIT - //! - [x] Implement support for storing items in the AST - //! - [ ] Keep track of the source location of each node - //! - [ ] Implement paths - //! - [x] Implement functions - //! - [ ] Implement structs - //! - [ ] Implement enums - //! - [ ] Implement implementation - //! - [ ] Store token spans in AST - pub mod path { - //! Path support - //! - [ ] Add namespace syntax (i.e. `::crate::foo::bar` | `foo::bar::Baz` | `foo::bar::*`) - //! - //! Path resolution will be vital to the implementation of structs, enums, impl blocks, - //! traits, modules, etc. - } - - pub mod module { - //! Module support - //! - [ ] Add Module Declaration type : ModDecl = "mod" Identifier '{' Module '}' ; - //! - [ ] Change Program to Module : Module = (ModDecl | FnDecl | Let)* - //! - [ ] Implementer's note: Modules must be traversed breadth-first, with no - //! alpha-renaming - //! - [ ] Blocks should probably also be traversed breadth-first, and Let declarations - //! hoisted up, leaving initialization assignments in-place - } - - pub mod structure { - //! Struct support - //! - [ ] Add struct declaration expression (returns a struct declaration) - //! - [ ] Add struct value expression (returns a struct value) - //! - [ ] Add struct update syntax (yippee!!) - } - - pub mod enumeration { - //! Enum support - //! - [ ] Add enum declaration expression (returns an enum declaration) - //! - [ ] Add enum value expression (returns an enum value) - } - - pub mod implementation { - //! Impl block support - //! - [ ] Add impl block expression? Statement? - //! - [ ] Add member function call expression - } +/// Stores a concrete Item +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum ItemKind { + /// A [constant](Const) + Const(Const), + /// A [static](Static) variable + Static(Static), + /// A [module](Module) + Module(Module), + /// A [function definition](Function) + Function(Function), + /// A [structure](Struct) + Struct(Struct), + /// An [enumerated type](Enum) + Enum(Enum), + /// An [implementation](Impl) + Impl(Impl), } + +/// Stores a `const` value +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Const { + pub name: Identifier, + pub ty: Box, + pub init: Box, + // TODO: Type path in const +} + +/// Stores a `static` variable +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Static { + pub mutable: Mutability, + pub name: Identifier, + pub ty: Box, + pub init: Box, + // TODO: Type path in static +} + +/// Stores a collection of [Items](Item) +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Module { + pub name: Identifier, + pub kind: ModuleKind, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum ModuleKind { + Inline(File), + Outline, +} + +/// Contains code, and the interface to that code +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Function { + pub name: Identifier, + pub args: Vec, + pub body: Option, + pub rety: Option>, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Param { + pub mutability: Mutability, + pub name: Identifier, + pub ty: Box, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Struct { + pub name: Identifier, + pub kind: StructKind, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum StructKind { + Empty, + Tuple(Vec), + Struct(Vec), +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct StructMember { + pub vis: Visibility, + pub name: Identifier, + pub ty: Ty, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Enum { + pub name: Identifier, + pub kind: EnumKind, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum EnumKind { + /// Represents an enum with no variants + NoVariants, + Variants(Vec), +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Variant { + pub name: Identifier, + pub kind: VariantKind, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum VariantKind { + Named(Identifier), + Tuple(Vec), + Struct(Vec), +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Impl { + pub target: Ty, + pub body: Vec, + // TODO: `impl` { } +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum ImplKind { + Type(Box), + Trait { impl_trait: Path, for_type: Box }, +} + +/// # Static Type Information +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Ty { + pub extents: Span, + pub kind: TyKind, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum TyKind { + Never, + Empty, + Path(Path), + Tuple(TyTuple), + Ref(TyRef), + Fn(TyFn), +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct TyTuple { + pub types: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct TyRef { + pub count: usize, + pub to: Path, +} +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct TyFn { + pub args: TyTuple, + pub rety: Option>, +} + +// Path +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Path { + pub absolute: bool, + pub parts: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum PathPart { + SuperKw, + SelfKw, + Ident(Identifier), +} + +// TODO: Capture token? +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Identifier(pub String); + +/// Stores an abstract statement, and associated metadata +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Stmt { + pub extents: Span, + pub kind: StmtKind, + pub semi: Semi, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum Semi { + Terminated, + Unterminated, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum StmtKind { + Empty, + Local(Let), + Item(Box), + Expr(Box), +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Let { + pub mutable: Mutability, + pub name: Identifier, + pub init: Option>, +} + +/// Stores an abstract expression, and associated metadata +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Expr { + pub extents: Span, + pub kind: ExprKind, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum ExprKind { + Assign(Box), + /// A [Binary] expression, with a leading and trailing side + Binary(Binary), + /// A [Unary] expression, with a trailing side + Unary(Unary), + /// A [Member] access expression + Member(Member), + /// A [Call] expression, with arguments + Call(Call), + /// An Array [Index] expression + Index(Index), + /// A [path expression](Path): `::`? [PathPart] (`::` [PathPart])* + Path(Path), + /// A [Literal]: 0x42, 1e123, 2.4, "Hello" + Literal(Literal), + /// An [Array] literal: `[` Expr (`,` Expr)* `]` + Array(Array), + /// An Array literal constructed with [repeat syntax](ArrayRep) + /// `[` [Expr] `;` [Literal] `]` + ArrayRep(ArrayRep), + /// An address-of expression: `&`foo + AddrOf(AddrOf), + /// A [Block] expression: `{` Stmt* Expr? `}` + Block(Block), + /// An empty expression: `(` `)` + Empty, + /// A [Grouping](Group) expression `(` Expr `)` + Group(Group), + /// A [Tuple] expression: `(` Expr (`,` Expr)+ `)` + Tuple(Tuple), + /// A [While] expression: `while` Expr Block Else? + While(While), + /// An [If] expression: `if` Expr Block Else? + If(If), + /// A [For] expression: `for` Pattern in Expr Block Else? + For(For), + /// A [Break] expression: `break` Expr? + Break(Break), + /// A [Return] expression `return` Expr? + Return(Return), + /// A continue expression: `continue` + Continue(Continue), +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Assign { + pub head: Expr, + pub op: AssignKind, + pub tail: Box, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum AssignKind { + /// Standard Assignment with no read-back + Plain, + And, + Or, + Xor, + Shl, + Shr, + Add, + Sub, + Mul, + Div, + Rem, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Binary { + pub head: Box, + pub tail: Vec<(BinaryKind, Expr)>, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum BinaryKind { + Lt, + LtEq, + Equal, + NotEq, + GtEq, + Gt, + RangeExc, + RangeInc, + LogAnd, + LogOr, + LogXor, + BitAnd, + BitOr, + BitXor, + Shl, + Shr, + Add, + Sub, + Mul, + Div, + Rem, + Dot, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Unary { + pub ops: Vec, + pub tail: Box, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum UnaryKind { + Deref, + Neg, + Not, + /// Unused + At, + /// Unused + Hash, + /// Unused + Tilde, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Member { + pub head: Box, + pub tail: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum MemberKind { + Dot, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Call { + pub callee: Box, + pub args: Vec, +} + +/// Index operator: Member (`[` Expr `]`)* +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Index { + pub head: Box, + pub indices: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Indices { + pub exprs: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum Literal { + Bool(bool), + Char(char), + Int(u128), + String(String), +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Array { + pub values: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct ArrayRep { + pub value: Box, + pub repeat: Box, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct AddrOf { + pub count: usize, + pub mutable: Mutability, + pub expr: Box, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Block { + pub stmts: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Group { + pub expr: Box, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Tuple { + pub exprs: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct While { + pub cond: Box, + pub pass: Box, + pub fail: Else, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct If { + pub cond: Box, + pub pass: Box, + pub fail: Else, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct For { + pub bind: Identifier, // TODO: Patterns? + pub cond: Box, + pub pass: Box, + pub fail: Else, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Else { + pub body: Option>, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Break { + pub body: Option>, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Return { + pub body: Option>, +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] +pub struct Continue; diff --git a/libconlang/src/ast/ast_impl.rs b/libconlang/src/ast/ast_impl.rs new file mode 100644 index 0000000..d952549 --- /dev/null +++ b/libconlang/src/ast/ast_impl.rs @@ -0,0 +1,744 @@ +//! Implementations of AST nodes and traits +use super::*; + +mod display { + //! Implements [Display] for [AST](super::super) Types + use super::*; + pub use delimiters::*; + use std::fmt::{Display, Write}; + mod delimiters { + #![allow(dead_code)] + #[derive(Clone, Copy, Debug)] + pub struct Delimiters<'t> { + pub open: &'t str, + pub close: &'t str, + } + /// Delimits with braces on separate lines `{\n`, ..., `\n}` + pub const BRACES: Delimiters = Delimiters { open: "{\n", close: "\n}" }; + /// Delimits with parentheses on separate lines `{\n`, ..., `\n}` + pub const PARENS: Delimiters = Delimiters { open: "(\n", close: "\n)" }; + /// Delimits with square brackets on separate lines `{\n`, ..., `\n}` + pub const SQUARE: Delimiters = Delimiters { open: "[\n", close: "\n]" }; + /// Delimits with braces on the same line `{ `, ..., ` }` + pub const INLINE_BRACES: Delimiters = Delimiters { open: "{ ", close: " }" }; + /// Delimits with parentheses on the same line `( `, ..., ` )` + pub const INLINE_PARENS: Delimiters = Delimiters { open: "(", close: ")" }; + /// Delimits with square brackets on the same line `[ `, ..., ` ]` + pub const INLINE_SQUARE: Delimiters = Delimiters { open: "[", close: "]" }; + } + fn delimit<'a>( + func: impl Fn(&mut std::fmt::Formatter<'_>) -> std::fmt::Result + 'a, + delim: Delimiters<'a>, + ) -> impl Fn(&mut std::fmt::Formatter<'_>) -> std::fmt::Result + 'a { + move |f| { + write!(f, "{}", delim.open)?; + func(f)?; + write!(f, "{}", delim.close) + } + } + fn separate<'iterable, I>( + iterable: &'iterable [I], + sep: impl Display + 'iterable, + ) -> impl Fn(&mut std::fmt::Formatter<'_>) -> std::fmt::Result + 'iterable + where + I: Display, + { + move |f| { + for (idx, item) in iterable.iter().enumerate() { + if idx > 0 { + write!(f, "{sep}")?; + } + item.fmt(f)?; + } + Ok(()) + } + } + + impl Display for Loc { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Loc { line, col } = self; + write!(f, "{line}:{col}:") + } + } + impl Display for Mutability { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Mutability::Not => Ok(()), + Mutability::Mut => "mut ".fmt(f), + } + } + } + impl Display for Visibility { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Visibility::Private => Ok(()), + Visibility::Public => "pub ".fmt(f), + } + } + } + + impl Display for File { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + separate(&self.items, "\n")(f) + } + } + + impl Display for Item { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.vis.fmt(f)?; + match &self.kind { + ItemKind::Const(v) => v.fmt(f), + ItemKind::Static(v) => v.fmt(f), + ItemKind::Module(v) => v.fmt(f), + ItemKind::Function(v) => v.fmt(f), + ItemKind::Struct(v) => v.fmt(f), + ItemKind::Enum(v) => v.fmt(f), + ItemKind::Impl(v) => v.fmt(f), + } + } + } + impl Display for Const { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { name, ty, init } = self; + write!(f, "const {name}: {ty} = {init}") + } + } + impl Display for Static { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { mutable, name, ty, init } = self; + write!(f, "static {mutable}{name}: {ty} = {init}") + } + } + impl Display for Module { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { name, kind } = self; + write!(f, "mod {name}{kind}") + } + } + impl Display for ModuleKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ModuleKind::Inline(items) => { + ' '.fmt(f)?; + delimit(|f| items.fmt(f), BRACES)(f) + } + ModuleKind::Outline => ';'.fmt(f), + } + } + } + impl Display for Function { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { name, args, body, rety } = self; + write!(f, "fn {name} ")?; + delimit(separate(args, ", "), INLINE_PARENS)(f)?; + if let Some(rety) = rety { + write!(f, " -> {rety}")?; + } + match body { + Some(body) => write!(f, " {body}"), + None => ';'.fmt(f), + } + } + } + impl Display for Param { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { mutability, name, ty } = self; + write!(f, "{mutability}{name}: {ty}") + } + } + impl Display for Struct { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { name, kind } = self; + write!(f, "struct {name}{kind}") + } + } + impl Display for StructKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + StructKind::Empty => ';'.fmt(f), + StructKind::Tuple(v) => delimit(separate(v, ", "), INLINE_PARENS)(f), + StructKind::Struct(v) => { + delimit(separate(v, ",\n"), Delimiters { open: " {\n", ..BRACES })(f) + } + } + } + } + impl Display for StructMember { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { vis, name, ty } = self; + write!(f, "{vis}{name}: {ty}") + } + } + impl Display for Enum { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { name, kind } = self; + write!(f, "enum {name}{kind}") + } + } + impl Display for EnumKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + EnumKind::NoVariants => todo!(), + EnumKind::Variants(v) => separate(v, ", ")(f), + } + } + } + impl Display for Variant { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { name, kind } = self; + write!(f, "{name}{kind}") + } + } + impl Display for VariantKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + VariantKind::Named(n) => n.fmt(f), + VariantKind::Tuple(v) => delimit(separate(v, ", "), INLINE_PARENS)(f), + VariantKind::Struct(v) => delimit(separate(v, ",\n"), BRACES)(f), + } + } + } + impl Display for Impl { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!("impl Display for Impl") + } + } + + impl Display for Ty { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.kind { + TyKind::Never => "!".fmt(f), + TyKind::Empty => "()".fmt(f), + TyKind::Path(v) => v.fmt(f), + TyKind::Tuple(v) => v.fmt(f), + TyKind::Ref(v) => v.fmt(f), + TyKind::Fn(v) => v.fmt(f), + } + } + } + impl Display for TyTuple { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + delimit(separate(&self.types, ", "), INLINE_PARENS)(f) + } + } + impl Display for TyRef { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { count: _, to } = self; + for _ in 0..self.count { + f.write_char('&')?; + } + write!(f, "{to}") + } + } + impl Display for TyFn { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { args, rety } = self; + write!(f, "fn {args}")?; + match rety { + Some(v) => write!(f, " -> {v}"), + None => Ok(()), + } + } + } + + impl Display for Stmt { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Stmt { extents: _, kind, semi } = self; + match kind { + StmtKind::Empty => Ok(()), + StmtKind::Local(v) => v.fmt(f), + StmtKind::Item(v) => v.fmt(f), + StmtKind::Expr(v) => v.fmt(f), + }?; + match semi { + Semi::Terminated => ';'.fmt(f), + Semi::Unterminated => Ok(()), + } + } + } + impl Display for Let { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { mutable, name, init } = self; + write!(f, "let {mutable}{name}")?; + if let Some(value) = init { + write!(f, " = {value}")?; + } + Ok(()) + } + } + + impl Display for Expr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.kind { + ExprKind::Assign(v) => v.fmt(f), + ExprKind::Binary(v) => v.fmt(f), + ExprKind::Unary(v) => v.fmt(f), + ExprKind::Index(v) => v.fmt(f), + ExprKind::Call(v) => v.fmt(f), + ExprKind::Member(v) => v.fmt(f), + ExprKind::Path(v) => v.fmt(f), + ExprKind::Literal(v) => v.fmt(f), + ExprKind::Array(v) => v.fmt(f), + ExprKind::ArrayRep(v) => v.fmt(f), + ExprKind::AddrOf(v) => v.fmt(f), + ExprKind::Block(v) => v.fmt(f), + ExprKind::Empty => "()".fmt(f), + ExprKind::Group(v) => v.fmt(f), + ExprKind::Tuple(v) => v.fmt(f), + ExprKind::While(v) => v.fmt(f), + ExprKind::If(v) => v.fmt(f), + ExprKind::For(v) => v.fmt(f), + ExprKind::Break(v) => v.fmt(f), + ExprKind::Return(v) => v.fmt(f), + ExprKind::Continue(_) => "continue".fmt(f), + } + } + } + impl Display for Assign { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { head, op, tail } = self; + write!(f, "{head} {op} {tail}") + } + } + impl Display for AssignKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + AssignKind::Plain => "=", + AssignKind::Mul => "*=", + AssignKind::Div => "/=", + AssignKind::Rem => "%=", + AssignKind::Add => "+=", + AssignKind::Sub => "-=", + AssignKind::And => "&=", + AssignKind::Or => "|=", + AssignKind::Xor => "^=", + AssignKind::Shl => "<<=", + AssignKind::Shr => ">>=", + } + .fmt(f) + } + } + impl Display for Binary { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { head, tail } = self; + write!(f, "{head}")?; + for (kind, expr) in tail { + write!(f, " {kind} {expr}")?; + } + Ok(()) + } + } + impl Display for BinaryKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + BinaryKind::Lt => "<", + BinaryKind::LtEq => "<=", + BinaryKind::Equal => "==", + BinaryKind::NotEq => "!=", + BinaryKind::GtEq => ">=", + BinaryKind::Gt => ">", + BinaryKind::RangeExc => "..", + BinaryKind::RangeInc => "..=", + BinaryKind::LogAnd => "&&", + BinaryKind::LogOr => "||", + BinaryKind::LogXor => "^^", + BinaryKind::BitAnd => "&", + BinaryKind::BitOr => "|", + BinaryKind::BitXor => "^", + BinaryKind::Shl => "<<", + BinaryKind::Shr => ">>", + BinaryKind::Add => "+", + BinaryKind::Sub => "-", + BinaryKind::Mul => "*", + BinaryKind::Div => "/", + BinaryKind::Rem => "%", + BinaryKind::Dot => ".", + } + .fmt(f) + } + } + impl Display for Unary { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { ops: kinds, tail } = self; + for kind in kinds { + kind.fmt(f)? + } + tail.fmt(f) + } + } + impl Display for UnaryKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + UnaryKind::Deref => "*", + UnaryKind::Neg => "-", + UnaryKind::Not => "!", + UnaryKind::At => "@", + UnaryKind::Hash => "#", + UnaryKind::Tilde => "~", + } + .fmt(f) + } + } + impl Display for Call { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { callee, args } = self; + callee.fmt(f)?; + for args in args { + args.fmt(f)?; + } + Ok(()) + } + } + impl Display for Tuple { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + delimit(separate(&self.exprs, ", "), INLINE_PARENS)(f) + } + } + impl Display for Member { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { head: parent, tail: children } = self; + write!(f, "{parent}.")?; + separate(children, ".")(f)?; + Ok(()) + } + } + impl Display for Index { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { head, indices } = self; + write!(f, "{head}")?; + for indices in indices { + indices.fmt(f)?; + } + Ok(()) + } + } + impl Display for Indices { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + delimit(separate(&self.exprs, ", "), INLINE_SQUARE)(f) + } + } + impl Display for Path { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { absolute, parts } = self; + if *absolute { + "::".fmt(f)?; + } + separate(parts, "::")(f) + } + } + impl Display for PathPart { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + PathPart::SuperKw => "super".fmt(f), + PathPart::SelfKw => "self".fmt(f), + PathPart::Ident(id) => id.fmt(f), + } + } + } + impl Display for Identifier { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } + } + impl Display for Literal { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Literal::Bool(v) => v.fmt(f), + Literal::Char(v) => write!(f, "'{v}'"), + Literal::Int(v) => v.fmt(f), + Literal::String(v) => write!(f, "\"{v}\""), + } + } + } + impl Display for Array { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + delimit(separate(&self.values, ", "), INLINE_SQUARE)(f) + } + } + impl Display for ArrayRep { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { value, repeat } = self; + write!(f, "[{value}; {repeat}]") + } + } + impl Display for AddrOf { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { count, mutable, expr } = self; + for _ in 0..*count { + f.write_char('&')?; + } + write!(f, "{mutable}{expr}") + } + } + impl Display for Block { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + delimit(separate(&self.stmts, "\n"), BRACES)(f) + } + } + impl Display for Group { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "({})", self.expr) + } + } + impl Display for While { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { cond, pass, fail } = self; + write!(f, "while {cond} {pass}{fail}") + } + } + impl Display for If { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { cond, pass, fail } = self; + write!(f, "if {cond} {pass}{fail}") + } + } + impl Display for For { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { bind, cond, pass, fail } = self; + write!(f, "for {bind} in {cond} {pass}{fail}") + } + } + impl Display for Else { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.body { + Some(body) => write!(f, " else {body}"), + _ => Ok(()), + } + } + } + impl Display for Break { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "break")?; + match &self.body { + Some(body) => write!(f, " {body}"), + _ => Ok(()), + } + } + } + impl Display for Return { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "return")?; + match &self.body { + Some(body) => write!(f, " {body}"), + _ => Ok(()), + } + } + } +} + +pub mod format { + //! Code formatting for the [AST](super::super) + + use std::{ + io::{Result, Write as IoWrite}, + ops::{Deref, DerefMut}, + }; + + /// Trait which adds a function to [Writers](IoWrite) to turn them into [Prettifier] + pub trait Pretty { + /// Indents code according to the number of matched curly braces + fn pretty(self) -> Prettifier<'static, Self> + where Self: IoWrite + Sized; + } + impl Pretty for W { + fn pretty(self) -> Prettifier<'static, Self> + where Self: IoWrite + Sized { + Prettifier::new(self) + } + } + + pub struct Prettifier<'i, T: IoWrite> { + level: isize, + indent: &'i str, + writer: T, + } + impl<'i, W: IoWrite> Prettifier<'i, W> { + pub fn new(writer: W) -> Self { + Self { level: 0, indent: " ", writer } + } + pub fn with_indent(indent: &'i str, writer: W) -> Self { + Self { level: 0, indent, writer } + } + pub fn indent<'scope>(&'scope mut self) -> Indent<'scope, 'i, W> { + Indent::new(self) + } + fn write_indentation(&mut self) -> Result { + let Self { level, indent, writer } = self; + let mut count = 0; + for _ in 0..*level { + count += writer.write(indent.as_bytes())?; + } + Ok(count) + } + } + impl From for Prettifier<'static, W> { + fn from(value: W) -> Self { + Self::new(value) + } + } + impl<'i, W: IoWrite> IoWrite for Prettifier<'i, W> { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + let mut size = 0; + for buf in buf.split_inclusive(|b| b"{}".contains(b)) { + match buf.last() { + Some(b'{') => self.level += 1, + Some(b'}') => self.level -= 1, + _ => (), + } + for buf in buf.split_inclusive(|b| b'\n' == *b) { + size += self.writer.write(buf)?; + if let Some(b'\n') = buf.last() { + self.write_indentation()?; + } + } + } + Ok(size) + } + + fn flush(&mut self) -> std::io::Result<()> { + self.writer.flush() + } + } + + pub struct Indent<'scope, 'i, T: IoWrite> { + formatter: &'scope mut Prettifier<'i, T>, + } + impl<'s, 'i, T: IoWrite> Indent<'s, 'i, T> { + pub fn new(formatter: &'s mut Prettifier<'i, T>) -> Self { + formatter.level += 1; + Self { formatter } + } + } + impl<'s, 'i, T: IoWrite> Deref for Indent<'s, 'i, T> { + type Target = Prettifier<'i, T>; + fn deref(&self) -> &Self::Target { + self.formatter + } + } + impl<'s, 'i, T: IoWrite> DerefMut for Indent<'s, 'i, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.formatter + } + } + impl<'s, 'i, T: IoWrite> Drop for Indent<'s, 'i, T> { + fn drop(&mut self) { + self.formatter.level -= 1; + } + } +} + +mod convert { + //! Converts between major enums and enum variants + use super::*; + use crate::lexer::Lexer; + + impl> From for Identifier { + fn from(value: T) -> Self { + Identifier(value.as_ref().into()) + } + } + + macro impl_from ($(impl From for $T:ty {$($from:ty => $to:expr),*$(,)?})*) {$($( + impl From<$from> for $T { + fn from(value: $from) -> Self { + $to(value.into()) // Uses *tuple constructor* + } + } + impl From> for $T { + fn from(value: Box<$from>) -> Self { + $to((*value).into()) + } + } + )*)*} + + impl_from! { + impl From for ItemKind { + Const => ItemKind::Const, + Static => ItemKind::Static, + Module => ItemKind::Module, + Function => ItemKind::Function, + Struct => ItemKind::Struct, + Enum => ItemKind::Enum, + Impl => ItemKind::Impl, + } + impl From for StructKind { + Vec => StructKind::Tuple, + // TODO: Struct members in struct + } + impl From for EnumKind { + Vec => EnumKind::Variants, + } + impl From for VariantKind { + Identifier => VariantKind::Named, + Vec => VariantKind::Tuple, + // TODO: enum struct variants + } + impl From for TyKind { + Path => TyKind::Path, + TyTuple => TyKind::Tuple, + TyRef => TyKind::Ref, + TyFn => TyKind::Fn, + } + impl From for StmtKind { + Let => StmtKind::Local, + Item => StmtKind::Item, + // NOTE: There are multiple conversions from Expr to StmtKind + } + impl From for ExprKind { + Assign => ExprKind::Assign, + Binary => ExprKind::Binary, + Unary => ExprKind::Unary, + Call => ExprKind::Call, + Member => ExprKind::Member, + Index => ExprKind::Index, + Path => ExprKind::Path, + Literal => ExprKind::Literal, + Array => ExprKind::Array, + ArrayRep => ExprKind::ArrayRep, + AddrOf => ExprKind::AddrOf, + Block => ExprKind::Block, + Group => ExprKind::Group, + Tuple => ExprKind::Tuple, + While => ExprKind::While, + If => ExprKind::If, + For => ExprKind::For, + Break => ExprKind::Break, + Return => ExprKind::Return, + Continue => ExprKind::Continue, + } + impl From for Literal { + bool => Literal::Bool, + char => Literal::Char, + u128 => Literal::Int, + &str => Literal::String, + } + } + + impl From for Indices { + fn from(value: Tuple) -> Self { + Self { exprs: value.exprs } + } + } + impl From for Tuple { + fn from(value: Indices) -> Self { + Self { exprs: value.exprs } + } + } + + impl From> for Else { + fn from(value: Option) -> Self { + Self { body: value.map(Into::into) } + } + } + impl From for Else { + fn from(value: Expr) -> Self { + Self { body: Some(value.into()) } + } + } + + impl<'t> From<&Lexer<'t>> for Loc { + fn from(value: &Lexer<'t>) -> Self { + Self { line: value.line(), col: value.col() } + } + } +} diff --git a/libconlang/src/interpreter.rs b/libconlang/src/interpreter.rs index a689921..4ec09a6 100644 --- a/libconlang/src/interpreter.rs +++ b/libconlang/src/interpreter.rs @@ -1,8 +1,8 @@ //! Interprets an AST as a program -use crate::ast::preamble::*; use env::Environment; use error::{Error, IResult}; +use interpret::Interpret; use temp_type_impl::ConValue; /// Callable types can be called from within a Conlang program @@ -44,6 +44,8 @@ pub mod temp_type_impl { Char(char), /// A string String(String), + /// An Array + Array(Vec), /// A tuple Tuple(Vec), /// An exclusive range @@ -75,6 +77,17 @@ pub mod temp_type_impl { }; Ok(Self::RangeInc(a, b)) } + pub fn index(&self, index: &Self) -> IResult { + let Self::Int(index) = index else { + Err(Error::TypeError)? + }; + let Self::Array(arr) = self else { + Err(Error::TypeError)? + }; + arr.get(*index as usize) + .cloned() + .ok_or(Error::OobIndex(*index as usize, arr.len())) + } cmp! { lt: false, <; lt_eq: true, <=; @@ -259,6 +272,16 @@ pub mod temp_type_impl { ConValue::Bool(v) => v.fmt(f), ConValue::Char(v) => v.fmt(f), ConValue::String(v) => v.fmt(f), + ConValue::Array(array) => { + '['.fmt(f)?; + for (idx, element) in array.iter().enumerate() { + if idx > 0 { + ", ".fmt(f)? + } + element.fmt(f)? + } + ']'.fmt(f) + } ConValue::RangeExc(a, b) => write!(f, "{a}..{}", b + 1), ConValue::RangeInc(a, b) => write!(f, "{a}..={b}"), ConValue::Tuple(tuple) => { @@ -282,352 +305,472 @@ pub mod temp_type_impl { } } -/// A work-in-progress tree walk interpreter for Conlang -pub trait Interpret { - /// Interprets this thing in the given [`Environment`]. - /// - /// Everything returns a value!™ - fn interpret(&self, env: &mut Environment) -> IResult; -} +pub mod interpret { + use super::*; + use crate::ast::*; + /// A work-in-progress tree walk interpreter for Conlang + pub trait Interpret { + /// Interprets this thing in the given [`Environment`]. + /// + /// Everything returns a value!™ + fn interpret(&self, env: &mut Environment) -> IResult; + } -impl Interpret for Start { - fn interpret(&self, env: &mut Environment) -> IResult { - self.0.interpret(env) - } -} -impl Interpret for Program { - fn interpret(&self, env: &mut Environment) -> IResult { - let mut out = ConValue::Empty; - for stmt in &self.0 { - out = stmt.interpret(env)?; - } - Ok(out) - } -} -impl Interpret for Stmt { - fn interpret(&self, env: &mut Environment) -> IResult { - match self { - Stmt::Let(l) => l.interpret(env), - Stmt::Fn(f) => f.interpret(env), - Stmt::Expr(e) => e.interpret(env), - } - } -} -impl Interpret for Let { - fn interpret(&self, env: &mut Environment) -> IResult { - let Let { name: Name { symbol: Identifier { name, .. }, .. }, init, .. } = self; - if let Some(init) = init { - let init = init.interpret(env)?; - env.insert(name, Some(init)); - } else { - env.insert(name, None); - } - Ok(ConValue::Empty) - } -} -impl Interpret for FnDecl { - fn interpret(&self, env: &mut Environment) -> IResult { - // register the function in the current environment - env.insert_fn(self); - Ok(ConValue::Empty) - } -} -impl Interpret for Expr { - fn interpret(&self, env: &mut Environment) -> IResult { - self.0.interpret(env) - } -} -impl Interpret for Operation { - fn interpret(&self, env: &mut Environment) -> IResult { - match self { - Operation::Assign(op) => op.interpret(env), - Operation::Binary(op) => op.interpret(env), - Operation::Unary(op) => op.interpret(env), - Operation::Call(op) => op.interpret(env), - } - } -} -impl Interpret for Assign { - fn interpret(&self, env: &mut Environment) -> IResult { - use operator::Assign; - let math::Assign { target: Identifier { name, .. }, operator, init } = self; - let init = init.interpret(env)?; - let target = env.get_mut(name)?; - - if let Assign::Assign = operator { - use std::mem::discriminant as variant; - // runtime typecheck - match target { - Some(value) if variant(value) == variant(&init) => { - *value = init; - } - value @ None => *value = Some(init), - _ => Err(Error::TypeError)?, + impl Interpret for File { + fn interpret(&self, env: &mut Environment) -> IResult { + for item in &self.items { + item.interpret(env)?; } - return Ok(ConValue::Empty); + Ok(ConValue::Empty) } - let Some(target) = target else { - return Err(Error::NotInitialized(name.into())); - }; - - match operator { - Assign::AddAssign => target.add_assign(init)?, - Assign::SubAssign => target.sub_assign(init)?, - Assign::MulAssign => target.mul_assign(init)?, - Assign::DivAssign => target.div_assign(init)?, - Assign::RemAssign => target.rem_assign(init)?, - Assign::BitAndAssign => target.bitand_assign(init)?, - Assign::BitOrAssign => target.bitor_assign(init)?, - Assign::BitXorAssign => target.bitxor_assign(init)?, - Assign::ShlAssign => target.shl_assign(init)?, - Assign::ShrAssign => target.shr_assign(init)?, - _ => (), - } - Ok(ConValue::Empty) } -} -impl Interpret for Binary { - fn interpret(&self, env: &mut Environment) -> IResult { - let Binary { first, other } = self; - let mut first = first.interpret(env)?; - for (op, other) in other { - first = match op { - operator::Binary::LogAnd => { - if first.truthy()? { - other.interpret(env) - } else { - return Ok(first); // Short circuiting + impl Interpret for Item { + fn interpret(&self, env: &mut Environment) -> IResult { + match &self.kind { + ItemKind::Const(item) => item.interpret(env), + ItemKind::Static(item) => item.interpret(env), + ItemKind::Module(item) => item.interpret(env), + ItemKind::Function(item) => item.interpret(env), + ItemKind::Struct(item) => item.interpret(env), + ItemKind::Enum(item) => item.interpret(env), + ItemKind::Impl(item) => item.interpret(env), + } + } + } + impl Interpret for Const { + fn interpret(&self, env: &mut Environment) -> IResult { + todo!("interpret const in {env}") + } + } + impl Interpret for Static { + fn interpret(&self, env: &mut Environment) -> IResult { + todo!("interpret static in {env}") + } + } + impl Interpret for Module { + fn interpret(&self, env: &mut Environment) -> IResult { + // TODO: Enter this module's namespace + match &self.kind { + ModuleKind::Inline(file) => file.interpret(env), + ModuleKind::Outline => todo!("Load and parse external files"), + } + } + } + impl Interpret for Function { + fn interpret(&self, env: &mut Environment) -> IResult { + // register the function in the current environment + env.insert_fn(self); + Ok(ConValue::Empty) + } + } + impl Interpret for Struct { + fn interpret(&self, env: &mut Environment) -> IResult { + todo!("Interpret structs in {env}") + } + } + impl Interpret for Enum { + fn interpret(&self, env: &mut Environment) -> IResult { + todo!("Interpret enums in {env}") + } + } + impl Interpret for Impl { + fn interpret(&self, env: &mut Environment) -> IResult { + todo!("Enter a struct's namespace and insert function definitions into it in {env}"); + } + } + impl Interpret for Stmt { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { extents: _, kind, semi } = self; + let out = match kind { + StmtKind::Empty => ConValue::Empty, + StmtKind::Local(stmt) => stmt.interpret(env)?, + StmtKind::Item(stmt) => stmt.interpret(env)?, + StmtKind::Expr(stmt) => stmt.interpret(env)?, + }; + Ok(match semi { + Semi::Terminated => ConValue::Empty, + Semi::Unterminated => out, + }) + } + } + impl Interpret for Let { + fn interpret(&self, env: &mut Environment) -> IResult { + let Let { mutable: _, name: Identifier(name), init } = self; + if let Some(init) = init { + let init = init.interpret(env)?; + env.insert(name, Some(init)); + } else { + env.insert(name, None); + } + Ok(ConValue::Empty) + } + } + impl Interpret for Expr { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { extents: _, kind } = self; + match kind { + ExprKind::Assign(v) => v.interpret(env), + ExprKind::Binary(v) => v.interpret(env), + ExprKind::Unary(v) => v.interpret(env), + ExprKind::Member(v) => v.interpret(env), + ExprKind::Call(v) => v.interpret(env), + ExprKind::Index(v) => v.interpret(env), + ExprKind::Path(v) => v.interpret(env), + ExprKind::Literal(v) => v.interpret(env), + ExprKind::Array(v) => v.interpret(env), + ExprKind::ArrayRep(v) => v.interpret(env), + ExprKind::AddrOf(v) => v.interpret(env), + ExprKind::Block(v) => v.interpret(env), + ExprKind::Empty => Ok(ConValue::Empty), + ExprKind::Group(v) => v.interpret(env), + ExprKind::Tuple(v) => v.interpret(env), + ExprKind::While(v) => v.interpret(env), + ExprKind::If(v) => v.interpret(env), + ExprKind::For(v) => v.interpret(env), + ExprKind::Break(v) => v.interpret(env), + ExprKind::Return(v) => v.interpret(env), + ExprKind::Continue(v) => v.interpret(env), + } + } + } + impl Interpret for Assign { + fn interpret(&self, env: &mut Environment) -> IResult { + let Assign { head, op, tail } = self; + // Resolve the head pattern + let head = match &head.kind { + ExprKind::Path(Path { parts, .. }) if parts.len() == 1 => { + match parts.last().expect("parts should not be empty") { + PathPart::SuperKw => Err(Error::NotAssignable(head.extents.head))?, + PathPart::SelfKw => todo!("Assignment to `self`"), + PathPart::Ident(Identifier(s)) => s, } } - operator::Binary::LogOr => { - if !first.truthy()? { - other.interpret(env) - } else { - return Ok(first); // Short circuiting + ExprKind::Member(_) => todo!("Member access assignment"), + ExprKind::Call(_) => todo!("Assignment to the result of a function call?"), + ExprKind::Index(_) => todo!("Assignment to an index operation"), + ExprKind::Path(_) => todo!("Path expression resolution (IMPORTANT)"), + ExprKind::Empty | ExprKind::Group(_) | ExprKind::Tuple(_) => { + todo!("Pattern Destructuring?") + } + _ => Err(Error::NotAssignable(head.extents.head))?, + }; + // Get the initializer and the tail + let init = tail.interpret(env)?; + let target = env.get_mut(head)?; + + if let AssignKind::Plain = op { + use std::mem::discriminant as variant; + // runtime typecheck + match target { + Some(value) if variant(value) == variant(&init) => { + *value = init; + } + value @ None => *value = Some(init), + _ => Err(Error::TypeError)?, + } + return Ok(ConValue::Empty); + } + let Some(target) = target else { + return Err(Error::NotInitialized(head.into())); + }; + + match op { + AssignKind::Add => target.add_assign(init)?, + AssignKind::Sub => target.sub_assign(init)?, + AssignKind::Mul => target.mul_assign(init)?, + AssignKind::Div => target.div_assign(init)?, + AssignKind::Rem => target.rem_assign(init)?, + AssignKind::And => target.bitand_assign(init)?, + AssignKind::Or => target.bitor_assign(init)?, + AssignKind::Xor => target.bitxor_assign(init)?, + AssignKind::Shl => target.shl_assign(init)?, + AssignKind::Shr => target.shr_assign(init)?, + _ => (), + } + Ok(ConValue::Empty) + } + } + impl Interpret for Binary { + fn interpret(&self, env: &mut Environment) -> IResult { + let Binary { head, tail } = self; + let mut head = head.interpret(env)?; + for (op, tail) in tail { + head = match op { + BinaryKind::LogAnd => { + if head.truthy()? { + tail.interpret(env) + } else { + return Ok(head); // Short circuiting + } + } + BinaryKind::LogOr => { + if !head.truthy()? { + tail.interpret(env) + } else { + return Ok(head); // Short circuiting + } + } + BinaryKind::LogXor => { + // TODO: It should be possible to assemble better error information from + // this + let (lhs, rhs) = (head.truthy()?, tail.interpret(env)?.truthy()?); + Ok(ConValue::Bool(lhs ^ rhs)) + } + // TODO: For all overloadable operators, transmute into function call + BinaryKind::Mul => head * tail.interpret(env)?, + BinaryKind::Div => head / tail.interpret(env)?, + BinaryKind::Rem => head % tail.interpret(env)?, + BinaryKind::Add => head + tail.interpret(env)?, + BinaryKind::Sub => head - tail.interpret(env)?, + BinaryKind::Shl => head << tail.interpret(env)?, + BinaryKind::Shr => head >> tail.interpret(env)?, + BinaryKind::BitAnd => head & tail.interpret(env)?, + BinaryKind::BitOr => head | tail.interpret(env)?, + BinaryKind::BitXor => head ^ tail.interpret(env)?, + BinaryKind::RangeExc => head.range_exc(tail.interpret(env)?), + BinaryKind::RangeInc => head.range_inc(tail.interpret(env)?), + BinaryKind::Lt => head.lt(&tail.interpret(env)?), + BinaryKind::LtEq => head.lt_eq(&tail.interpret(env)?), + BinaryKind::Equal => head.eq(&tail.interpret(env)?), + BinaryKind::NotEq => head.neq(&tail.interpret(env)?), + BinaryKind::GtEq => head.gt_eq(&tail.interpret(env)?), + BinaryKind::Gt => head.gt(&tail.interpret(env)?), + BinaryKind::Dot => todo!("search within a type's namespace!"), + }?; + } + Ok(head) + } + } + impl Interpret for Unary { + fn interpret(&self, env: &mut Environment) -> IResult { + let Unary { tail, ops } = self; + let mut operand = tail.interpret(env)?; + + for op in ops.iter().rev() { + operand = match op { + UnaryKind::Deref => todo!("Deref operator"), + UnaryKind::Neg => (-operand)?, + UnaryKind::Not => (!operand)?, + UnaryKind::At => unimplemented!("At operator"), + UnaryKind::Hash => { + println!("{operand}"); + operand + } + UnaryKind::Tilde => unimplemented!("Tilde operator"), + }; + } + Ok(operand) + } + } + impl Interpret for Member { + fn interpret(&self, env: &mut Environment) -> IResult { + todo!("Interpret member accesses in {env}") + } + } + impl Interpret for Call { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { callee, args } = self; + // evaluate the callee + let mut callee = callee.interpret(env)?; + for args in args { + let ConValue::Tuple(args) = args.interpret(env)? else { + Err(Error::TypeError)? + }; + callee = callee.call(env, &args)?; + } + Ok(callee) + } + } + impl Interpret for Index { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { head, indices } = self; + let mut head = head.interpret(env)?; + for indices in indices { + let Indices { exprs } = indices; + for index in exprs { + head = head.index(&index.interpret(env)?)?; + } + } + Ok(head) + } + } + impl Interpret for Path { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { absolute: _, parts } = self; + + if parts.len() == 1 { + match parts.last().expect("parts should not be empty") { + PathPart::SuperKw | PathPart::SelfKw => todo!("Path navigation"), + PathPart::Ident(Identifier(s)) => env.get(s).cloned(), + } + } else { + todo!("Path navigation!") + } + } + } + impl Interpret for Literal { + fn interpret(&self, _env: &mut Environment) -> IResult { + Ok(match self { + Literal::String(value) => ConValue::from(value.as_str()), + Literal::Char(value) => ConValue::Char(*value), + Literal::Bool(value) => ConValue::Bool(*value), + // Literal::Float(value) => todo!("Float values in interpreter: {value:?}"), + Literal::Int(value) => ConValue::Int(*value as _), + }) + } + } + impl Interpret for Array { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { values } = self; + let mut out = vec![]; + for expr in values { + out.push(expr.interpret(env)?) + } + Ok(ConValue::Array(out)) + } + } + impl Interpret for ArrayRep { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { value, repeat } = self; + let repeat = match repeat.interpret(env)? { + ConValue::Int(v) => v, + _ => Err(Error::TypeError)?, + }; + let value = value.interpret(env)?; + Ok(ConValue::Array(vec![value; repeat as usize])) + } + } + impl Interpret for AddrOf { + fn interpret(&self, env: &mut Environment) -> IResult { + todo!("Implement AddrOf in {env}") + } + } + impl Interpret for Block { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { stmts } = self; + let mut env = env.frame("block"); + let mut out = ConValue::Empty; + for stmt in stmts { + let Stmt { kind, semi, .. } = stmt; + out = match (kind, semi) { + (StmtKind::Expr(_), Semi::Unterminated) => stmt.interpret(&mut env)?, + (StmtKind::Expr(_), _) => { + stmt.interpret(&mut env)?; + ConValue::Empty + } + _ => { + stmt.interpret(&mut env)?; + continue; } } - operator::Binary::LogXor => { - // TODO: It should be possible to assemble better error information from this - let (lhs, rhs) = (first.truthy()?, other.interpret(env)?.truthy()?); - Ok(ConValue::Bool(lhs ^ rhs)) + } + Ok(out) + } + } + impl Interpret for Group { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { expr } = self; + expr.interpret(env) + } + } + impl Interpret for Tuple { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { exprs } = self; + Ok(ConValue::Tuple(exprs.iter().try_fold( + vec![], + |mut out, element| { + out.push(element.interpret(env)?); + Ok(out) + }, + )?)) + } + } + impl Interpret for While { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { cond, pass, fail } = self; + while cond.interpret(env)?.truthy()? { + match pass.interpret(env) { + Err(Error::Break(value)) => return Ok(value), + Err(Error::Continue) => continue, + e => e?, + }; + } + fail.interpret(env) + } + } + impl Interpret for If { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { cond, pass, fail } = self; + if cond.interpret(env)?.truthy()? { + pass.interpret(env) + } else { + fail.interpret(env) + } + } + } + impl Interpret for For { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { bind: Identifier(name), cond, pass, fail } = self; + // TODO: A better iterator model + let bounds = match cond.interpret(env)? { + ConValue::RangeExc(a, b) => a..=b, + ConValue::RangeInc(a, b) => a..=b, + _ => Err(Error::TypeError)?, + }; + { + let mut env = env.frame("loop variable"); + for loop_var in bounds { + env.insert(name, Some(loop_var.into())); + match pass.interpret(&mut env) { + Err(Error::Break(value)) => return Ok(value), + Err(Error::Continue) => continue, + result => result?, + }; } - // TODO: For all overloadable operators, transmute into function call - operator::Binary::Mul => first * other.interpret(env)?, - operator::Binary::Div => first / other.interpret(env)?, - operator::Binary::Rem => first % other.interpret(env)?, - operator::Binary::Add => first + other.interpret(env)?, - operator::Binary::Sub => first - other.interpret(env)?, - operator::Binary::Lsh => first << other.interpret(env)?, - operator::Binary::Rsh => first >> other.interpret(env)?, - operator::Binary::BitAnd => first & other.interpret(env)?, - operator::Binary::BitOr => first | other.interpret(env)?, - operator::Binary::BitXor => first ^ other.interpret(env)?, - operator::Binary::RangeExc => first.range_exc(other.interpret(env)?), - operator::Binary::RangeInc => first.range_inc(other.interpret(env)?), - operator::Binary::Less => first.lt(&other.interpret(env)?), - operator::Binary::LessEq => first.lt_eq(&other.interpret(env)?), - operator::Binary::Equal => first.eq(&other.interpret(env)?), - operator::Binary::NotEq => first.neq(&other.interpret(env)?), - operator::Binary::GreaterEq => first.gt_eq(&other.interpret(env)?), - operator::Binary::Greater => first.gt(&other.interpret(env)?), - }?; - } - Ok(first) - } -} -impl Interpret for Unary { - fn interpret(&self, env: &mut Environment) -> IResult { - let Unary { operand, operators } = self; - let mut operand = operand.interpret(env)?; - - for op in operators.iter().rev() { - operand = match op { - operator::Unary::RefRef => todo!(), - operator::Unary::Ref => todo!(), - operator::Unary::Deref => todo!(), - operator::Unary::Neg => (-operand)?, - operator::Unary::Not => (!operand)?, - operator::Unary::At => todo!(), - operator::Unary::Hash => { - println!("{operand}"); - operand - } - operator::Unary::Tilde => todo!(), - }; - } - Ok(operand) - } -} -impl Interpret for Call { - fn interpret(&self, env: &mut Environment) -> IResult { - match self { - Call::FnCall(fncall) => fncall.interpret(env), - Call::Primary(primary) => primary.interpret(env), + } + fail.interpret(env) } } -} -impl Interpret for FnCall { - fn interpret(&self, env: &mut Environment) -> IResult { - // evaluate the callee - let mut callee = self.callee.interpret(env)?; - for args in &self.args { - let ConValue::Tuple(args) = args.interpret(env)? else { - Err(Error::TypeError)? - }; - callee = callee.call(env, &args)?; - } - Ok(callee) - } -} -impl Interpret for Primary { - fn interpret(&self, env: &mut Environment) -> IResult { - match self { - Primary::Identifier(prim) => prim.interpret(env), - Primary::Literal(prim) => prim.interpret(env), - Primary::Block(prim) => prim.interpret(env), - Primary::Group(prim) => prim.interpret(env), - Primary::Branch(prim) => prim.interpret(env), + impl Interpret for Else { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { body } = self; + match body { + Some(body) => body.interpret(env), + None => Ok(ConValue::Empty), + } } } -} -impl Interpret for Identifier { - fn interpret(&self, env: &mut Environment) -> IResult { - env.get(&self.name).cloned() - } -} -impl Interpret for Literal { - fn interpret(&self, _env: &mut Environment) -> IResult { - Ok(match self { - Literal::String(value) => ConValue::from(value.as_str()), - Literal::Char(value) => ConValue::Char(*value), - Literal::Bool(value) => ConValue::Bool(*value), - Literal::Float(value) => todo!("Float values in interpreter: {value:?}"), - Literal::Int(value) => ConValue::Int(*value as _), - }) - } -} -impl Interpret for Block { - fn interpret(&self, env: &mut Environment) -> IResult { - let mut env = env.frame("block"); - // TODO: this could TOTALLY be done with a binary operator. - for stmt in &self.statements { - stmt.interpret(&mut env)?; - } - if let Some(expr) = self.expr.as_ref() { - expr.interpret(&mut env) - } else { - Ok(ConValue::Empty) + impl Interpret for Continue { + fn interpret(&self, _env: &mut Environment) -> IResult { + Err(Error::Continue) } } -} -impl Interpret for Group { - fn interpret(&self, env: &mut Environment) -> IResult { - match self { - Group::Tuple(tuple) => tuple.interpret(env), - Group::Single(value) => value.interpret(env), - Group::Empty => Ok(ConValue::Empty), + impl Interpret for Return { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { body } = self; + Err(Error::Return( + body.as_ref() + .map(|body| body.interpret(env)) + .unwrap_or(Ok(ConValue::Empty))?, + )) } } -} -impl Interpret for Tuple { - fn interpret(&self, env: &mut Environment) -> IResult { - Ok(ConValue::Tuple(self.elements.iter().try_fold( - vec![], - |mut out, element| { - out.push(element.interpret(env)?); - Ok(out) - }, - )?)) - } -} -impl Interpret for Flow { - fn interpret(&self, env: &mut Environment) -> IResult { - match self { - Flow::While(flow) => flow.interpret(env), - Flow::If(flow) => flow.interpret(env), - Flow::For(flow) => flow.interpret(env), - Flow::Continue(flow) => flow.interpret(env), - Flow::Return(flow) => flow.interpret(env), - Flow::Break(flow) => flow.interpret(env), + impl Interpret for Break { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { body } = self; + Err(Error::Return( + body.as_ref() + .map(|body| body.interpret(env)) + .unwrap_or(Ok(ConValue::Empty))?, + )) } } } -impl Interpret for While { - fn interpret(&self, env: &mut Environment) -> IResult { - while self.cond.interpret(env)?.truthy()? { - match self.body.interpret(env) { - Err(Error::Break(value)) => return Ok(value), - Err(Error::Continue) => continue, - e => e?, - }; - } - if let Some(other) = &self.else_ { - other.interpret(env) - } else { - Ok(ConValue::Empty) - } - } -} -impl Interpret for Else { - fn interpret(&self, env: &mut Environment) -> IResult { - self.expr.interpret(env) - } -} -impl Interpret for If { - fn interpret(&self, env: &mut Environment) -> IResult { - if self.cond.interpret(env)?.truthy()? { - self.body.interpret(env) - } else if let Some(other) = &self.else_ { - other.interpret(env) - } else { - Ok(ConValue::Empty) - } - } -} -impl Interpret for For { - fn interpret(&self, env: &mut Environment) -> IResult { - let bounds = match self.iter.interpret(env)? { - ConValue::RangeExc(a, b) => a..=b, - ConValue::RangeInc(a, b) => a..=b, - _ => Err(Error::TypeError)?, - }; - - let mut env = env.frame("loop variable"); - for loop_var in bounds { - env.insert(&self.var.name, Some(loop_var.into())); - match self.body.interpret(&mut env) { - Err(Error::Break(value)) => return Ok(value), - Err(Error::Continue) => continue, - result => result?, - }; - } - if let Some(other) = &self.else_ { - other.interpret(&mut env) - } else { - Ok(ConValue::Empty) - } - } -} -impl Interpret for Continue { - fn interpret(&self, _env: &mut Environment) -> IResult { - Err(Error::Continue) - } -} -impl Interpret for Return { - fn interpret(&self, env: &mut Environment) -> IResult { - Err(Error::Return(self.expr.interpret(env)?)) - } -} -impl Interpret for Break { - fn interpret(&self, env: &mut Environment) -> IResult { - Err(Error::Break(self.expr.interpret(env)?)) - } -} pub mod function { //! Represents a block of code which lives inside the Interpreter - use super::{Callable, ConValue, Environment, Error, FnDecl, IResult, Identifier, Interpret}; - use crate::ast::preamble::Name; + use super::{Callable, ConValue, Environment, Error, IResult, Interpret}; + use crate::ast::{Function as FnDecl, Identifier, Param}; /// Represents a block of code which persists inside the Interpreter #[derive(Clone, Debug)] pub struct Function { @@ -645,22 +788,26 @@ pub mod function { impl Callable for Function { fn name(&self) -> &str { - &self.decl.name.symbol.name + let FnDecl { name: Identifier(ref name), .. } = *self.decl; + name } fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult { + let FnDecl { name: Identifier(name), args: declargs, body, rety: _ } = &*self.decl; // Check arg mapping - if args.len() != self.decl.args.len() { - return Err(Error::ArgNumber { want: self.decl.args.len(), got: args.len() }); + if args.len() != declargs.len() { + return Err(Error::ArgNumber { want: declargs.len(), got: args.len() }); } - // TODO: Isolate cross-function scopes! - // let mut env = self.env.clone(); + let Some(body) = body else { + return Err(Error::NotDefined(name.into())); + }; + // TODO: completely refactor data storage let mut frame = env.frame("fn args"); - for (Name { symbol: Identifier { name, .. }, .. }, value) in - self.decl.args.iter().zip(args) + for (Param { mutability: _, name: Identifier(name), ty: _ }, value) in + declargs.iter().zip(args) { frame.insert(name, Some(value.clone())); } - match self.decl.body.interpret(&mut frame) { + match body.interpret(&mut frame) { Err(Error::Return(value)) => Ok(value), Err(Error::Break(value)) => Err(Error::BadBreak(value)), result => result, @@ -734,14 +881,14 @@ pub mod builtin { pub mod env { //! Lexical and non-lexical scoping for variables - use super::{ builtin::DEFAULT_BUILTINS, error::{Error, IResult}, function::Function, temp_type_impl::ConValue, - Callable, FnDecl, Interpret, + Callable, Interpret, }; + use crate::ast::{Function as FnDecl, Identifier}; use std::{ collections::HashMap, fmt::Display, @@ -838,10 +985,8 @@ pub mod env { } /// A convenience function for registering a [FnDecl] as a [Function] pub fn insert_fn(&mut self, decl: &FnDecl) { - let (name, function) = ( - decl.name.symbol.name.clone(), - Some(Function::new(decl).into()), - ); + let FnDecl { name: Identifier(name), .. } = decl; + let (name, function) = (name.clone(), Some(Function::new(decl).into())); if let Some((frame, _)) = self.frames.last_mut() { frame.insert(name, function); } @@ -898,6 +1043,7 @@ pub mod error { //! The [Error] type represents any error thrown by the [Environment](super::Environment) use super::temp_type_impl::ConValue; + use crate::ast::Loc; pub type IResult = Result; @@ -921,6 +1067,12 @@ pub mod error { TypeError, /// In clause of For loop didn't yield a Range NotIterable, + /// A value at this [location](struct@Loc) can't be indexed + NotIndexable(Loc), + /// An array index went out of bounds + OobIndex(usize, usize), + /// An expression at this [location](struct@Loc)ation is not assignable + NotAssignable(Loc), /// A name was not defined in scope before being used NotDefined(String), /// A name was defined but not initialized @@ -943,6 +1095,15 @@ pub mod error { Error::ScopeExit => "Exited the last scope. This is a logic bug.".fmt(f), Error::TypeError => "Incompatible types".fmt(f), Error::NotIterable => "`in` clause of `for` loop did not yield an iterable".fmt(f), + Error::NotIndexable(location) => { + write!(f, "{location} expression cannot be indexed") + } + Error::OobIndex(idx, len) => { + write!(f, "Index out of bounds: index was {idx}. but len is {len}") + } + Error::NotAssignable(location) => { + write!(f, "{location} expression is not assignable") + } Error::NotDefined(value) => { write!(f, "{value} not bound. Did you mean `let {value};`?") } @@ -950,7 +1111,7 @@ pub mod error { write!(f, "{value} bound, but not initialized") } Error::NotCallable(value) => { - write!(f, "{value} is not a function, and cannot be called") + write!(f, "{value} is not callable.") } Error::ArgNumber { want, got } => { write!(f, "Expected {want} arguments, got {got}") diff --git a/libconlang/src/interpreter/tests.rs b/libconlang/src/interpreter/tests.rs index 0b60ab8..e05c9d6 100644 --- a/libconlang/src/interpreter/tests.rs +++ b/libconlang/src/interpreter/tests.rs @@ -49,12 +49,30 @@ mod macros { //! env_eq!(env.x, 10); // like assert_eq! for Environments //! ``` #![allow(unused_macros)] + use crate::interpreter::IResult; + use super::*; + + pub fn test_inside_block(block: &Block, env: &mut Environment) -> IResult<()> { + let Block { stmts } = block; + for stmt in stmts { + stmt.interpret(env)?; + } + Ok(()) + } + /// Stringifies, lexes, and parses everything you give to it /// - /// Returns a `Result<`[`Start`]`, ParseError>` - pub macro parse($($t:tt)*) { - Parser::from(Lexer::new(stringify!( $($t)* ))).parse() + /// Returns a `Result<`[`File`]`, ParseError>` + pub macro file($($t:tt)*) { + Parser::new(Lexer::new(stringify!( $($t)* ))).file() + } + + /// Stringifies, lexes, and parses everything you give to it + /// + /// Returns a `Result<`[`Block`]`, ParseError>` + pub macro block($($t:tt)*) { + Parser::new(Lexer::new(stringify!({ $($t)* }))).block() } /// Evaluates a block of code in the given environment @@ -68,9 +86,9 @@ mod macros { /// ) /// ``` pub macro eval($env: path, $($t:tt)*) {{ - parse!($($t)*) - .expect("code passed to eval! should parse correctly") - .interpret(&mut $env) + test_inside_block(&block!($($t)*) + .expect("code passed to eval! should parse correctly"), + &mut $env) }} /// Evaluates a block of code in the given environment, expecting the interpreter to succeed @@ -194,7 +212,7 @@ mod fn_declarations { } mod operators { - use crate::ast::preamble::expression::tuple; + use crate::ast::Tuple; use super::*; #[test] @@ -337,6 +355,7 @@ mod operators { let is_20_ne_10 = 20 != 10; let is_20_ge_10 = 20 >= 10; let is_20_gt_10 = 20 > 10; + dump(); ); // Less than diff --git a/libconlang/src/lib.rs b/libconlang/src/lib.rs index 395398e..fbbbad4 100644 --- a/libconlang/src/lib.rs +++ b/libconlang/src/lib.rs @@ -10,8 +10,6 @@ pub mod lexer; pub mod parser; -pub mod pretty_printer; - pub mod resolver; pub mod interpreter; diff --git a/libconlang/src/parser.rs b/libconlang/src/parser.rs index 31cb880..76784a7 100644 --- a/libconlang/src/parser.rs +++ b/libconlang/src/parser.rs @@ -1,831 +1,1229 @@ //! Parses [tokens](super::token) into an [AST](super::ast) -#![deprecated] -#![allow(deprecated)] -use super::{ast::preamble::*, lexer::Lexer, token::preamble::*}; -use error::{Error, *}; +//! +//! For the full grammar, see [grammar.ebnf][1] +//! +//! [1]: https://git.soft.fish/j/Conlang/src/branch/main/grammar.ebnf + +use self::error::{ + Error, + ErrorKind::{self, *}, + PResult, WhileParsing, +}; +use crate::{ + ast::*, + lexer::{error::Error as LexError, Lexer}, + token::{ + token_data::Data, + token_type::{Keyword, Type}, + Token, + }, +}; pub mod error { - use super::{Token, Type}; use std::fmt::Display; - pub trait WrapError { - /// Wraps this error in a parent [Error] - fn wrap(self, parent: Error) -> Self; - } - impl WrapError for Error { - fn wrap(self, parent: Error) -> Self { - Self { child: Some(self.into()), ..parent } - } - } - impl WrapError for Result { - fn wrap(self, parent: Error) -> Self { - self.map_err(|e| e.wrap(parent)) - } - } - - /// The reason for the [Error] - #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] - pub enum Reason { - Expected(Type), - Unexpected(Type), - NotPathSegment(Type), - NotIdentifier, - NotStatement, - NotLet, - NotFnDecl, - NotOperator, - NotLiteral, - NotString, - NotChar, - NotBool, - NotFloat, - NotInt, - FloatExponentOverflow, - FloatMantissaOverflow, - IntOverflow, - NotBranch, - IncompleteBranch, - EndOfFile, - PanicStackUnderflow, - #[default] - Unspecified, - } - use Reason::*; - - impl Display for Reason { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Expected(t) => write!(f, "Expected {t}"), - Self::Unexpected(t) => write!(f, "Unexpected {t} in bagging area"), - Self::NotPathSegment(t) => write!(f, "{t} not a path segment"), - Self::NotIdentifier => "Not an identifier".fmt(f), - Self::NotStatement => "Not a statement".fmt(f), - Self::NotLet => "Not a let statement".fmt(f), - Self::NotFnDecl => "Not a valid function declaration".fmt(f), - Self::NotOperator => "Not an operator".fmt(f), - Self::NotLiteral => "Not a literal".fmt(f), - Self::NotString => "Not a string".fmt(f), - Self::NotChar => "Not a char".fmt(f), - Self::NotBool => "Not a bool".fmt(f), - Self::NotFloat => "Not a float".fmt(f), - Self::FloatExponentOverflow => "Float exponent too large".fmt(f), - Self::FloatMantissaOverflow => "Float mantissa too large".fmt(f), - Self::NotInt => "Not an integer".fmt(f), - Self::IntOverflow => "Integer too large".fmt(f), - Self::IncompleteBranch => "Branch expression was incomplete".fmt(f), - Self::NotBranch => "Expected branch expression".fmt(f), - Self::EndOfFile => "Got end of file".fmt(f), - Self::PanicStackUnderflow => "Could not recover from panic".fmt(f), - Self::Unspecified => { - "Unspecified error. You are permitted to slap the code author.".fmt(f) - } - } - } - } - - /// [Parser](super::Parser) [Result] + use super::*; pub type PResult = Result; - /// An error produced by the [Parser](super::Parser). - /// - /// Contains a [Reason], and, optionally, a start [Token] - #[derive(Clone, Debug, Default, PartialEq)] + + /// Contains information about [Parser] errors + #[derive(Clone, Debug, PartialEq, Eq)] pub struct Error { - reason: Reason, - child: Option>, - start: Option, + pub reason: ErrorKind, + pub while_parsing: WhileParsing, + pub loc: Loc, } impl std::error::Error for Error {} + + /// Represents the reason for parse failure + #[derive(Clone, Debug, PartialEq, Eq)] + pub enum ErrorKind { + Lexical(LexError), + EndOfInput, + UnmatchedParentheses, + UnmatchedCurlyBraces, + UnmatchedSquareBrackets, + Unexpected(Type), + Expected { + want: Type, + got: Type, + }, + /// No rules matched + Nothing, + /// Indicates unfinished code + Todo, + } + impl From for ErrorKind { + fn from(value: LexError) -> Self { + use crate::lexer::error::Reason; + match value.reason() { + Reason::EndOfFile => Self::EndOfInput, + _ => Self::Lexical(value), + } + } + } + + /// Compactly represents the stage of parsing an [Error] originated in + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub enum WhileParsing { + File, + + Item, + Visibility, + Mutability, + ItemKind, + Const, + Static, + Module, + ModuleKind, + Function, + Param, + Struct, + StructKind, + StructMember, + Enum, + EnumKind, + Variant, + VariantKind, + Impl, + + Ty, + TyKind, + TyTuple, + TyRef, + TyFn, + + Stmt, + StmtKind, + Let, + + Expr, + ExprKind, + Assign, + AssignKind, + Binary, + BinaryKind, + Unary, + UnaryKind, + Index, + Call, + Member, + PathExpr, + PathPart, + Identifier, + Literal, + Array, + ArrayRep, + AddrOf, + Block, + Group, + Tuple, + While, + If, + For, + Else, + Break, + Return, + Continue, + } + impl Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if let Some(child) = &self.child { - write!(f, "{child}: ")?; + let Self { reason, while_parsing, loc } = self; + match reason { + // TODO entries are debug-printed + Todo => write!(f, "{loc} {reason} {while_parsing:?}"), + // lexical errors print their own higher-resolution loc info + Lexical(e) => write!(f, "{e} (while parsing {while_parsing})"), + _ => write!(f, "{loc} {reason} while parsing {while_parsing}"), } - if let Some(token) = &self.start { - write!(f, "{}:{}: ", token.line(), token.col())?; - } - write!(f, "{}", self.reason) } } + impl Display for ErrorKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ErrorKind::Lexical(e) => e.fmt(f), + ErrorKind::EndOfInput => write!(f, "End of input"), + ErrorKind::UnmatchedParentheses => write!(f, "Unmatched parentheses"), + ErrorKind::UnmatchedCurlyBraces => write!(f, "Unmatched curly braces"), + ErrorKind::UnmatchedSquareBrackets => write!(f, "Unmatched square brackets"), + ErrorKind::Unexpected(t) => write!(f, "Encountered unexpected token `{t}`"), + ErrorKind::Expected { want: e, got: g } => { + write!(f, "Expected {e}, but got {g}") + } + ErrorKind::Nothing => write!(f, "Nothing found"), + ErrorKind::Todo => write!(f, "TODO:"), + } + } + } + impl Display for WhileParsing { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + WhileParsing::File => "a file", + WhileParsing::Item => "an item", + WhileParsing::Visibility => "a visibility qualifier", + WhileParsing::Mutability => "a mutability qualifier", + WhileParsing::ItemKind => "an item", + WhileParsing::Const => "a const item", + WhileParsing::Static => "a static variable", + WhileParsing::Module => "a module", + WhileParsing::ModuleKind => "a module", + WhileParsing::Function => "a function", + WhileParsing::Param => "a function parameter", + WhileParsing::Struct => "a struct", + WhileParsing::StructKind => "a struct", + WhileParsing::StructMember => "a struct member", + WhileParsing::Enum => "an enum", + WhileParsing::EnumKind => "an enum", + WhileParsing::Variant => "an enum variant", + WhileParsing::VariantKind => "an enum variant", + WhileParsing::Impl => "an impl block", - macro error_impl($($fn:ident$(($($p:ident: $t:ty),*))?: $reason:expr),*$(,)?) {$( - /// Creates an [Error] with this [Reason]: - #[doc = concat!("[`", stringify!($reason), "`]")] - #[allow(dead_code)] - pub(crate) fn $fn($($($p : $t),*)?) -> Self { - Self { reason: $reason$(($($p)*))?, child: None, start: None } - } - )*} - impl Error { - /// Provides an optional start [Token] - pub fn token(self, start: Token) -> Self { - Self { start: Some(start), ..self } - } - /// Optionally sets the start [Token] - pub fn maybe_token(self, start: Option) -> Self { - Self { start, ..self } - } - /// Gets a reference to the start [Token], if there is one - pub fn start(&self) -> Option<&Token> { - self.start.as_ref() - } - /// Gets the [Reason] for this error - pub fn reason(&self) -> Reason { - self.reason - } - error_impl! { - expected(e: Type): Expected, - unexpected(e: Type): Unexpected, - not_path_segment(e: Type): NotPathSegment, - not_identifier: NotIdentifier, - not_statement: NotStatement, - not_let: NotLet, - not_fn_decl: NotFnDecl, - not_operator: NotOperator, - not_literal: NotLiteral, - not_string: NotString, - not_char: NotChar, - not_bool: NotBool, - not_float: NotFloat, - float_exponent_overflow: FloatExponentOverflow, - float_mantissa_overflow: FloatMantissaOverflow, - not_int: NotInt, - int_overflow: IntOverflow, - not_branch: NotBranch, - end_of_file: EndOfFile, - panic_underflow: PanicStackUnderflow, - unspecified: Unspecified, + WhileParsing::Ty => "a type", + WhileParsing::TyKind => "a type", + WhileParsing::TyTuple => "a tuple of types", + WhileParsing::TyRef => "a reference type", + WhileParsing::TyFn => "a function pointer type", + + WhileParsing::Stmt => "a statement", + WhileParsing::StmtKind => "a statement", + WhileParsing::Let => "a local variable declaration", + + WhileParsing::Expr => "an expression", + WhileParsing::ExprKind => "an expression", + WhileParsing::Assign => "an assignment", + WhileParsing::AssignKind => "an assignment", + WhileParsing::Binary => "a binary expression", + WhileParsing::BinaryKind => "a binary expression", + WhileParsing::Unary => "a unary expression", + WhileParsing::UnaryKind => "a unary expression", + WhileParsing::Index => "an indexing expression", + WhileParsing::Call => "a call expression", + WhileParsing::Member => "a member access expression", + WhileParsing::PathExpr => "a path", + WhileParsing::PathPart => "a path component", + WhileParsing::Identifier => "an identifier", + WhileParsing::Literal => "a literal", + WhileParsing::Array => "an array", + WhileParsing::ArrayRep => "an array of form [k;N]", + WhileParsing::AddrOf => "a borrow op", + WhileParsing::Block => "a block", + WhileParsing::Group => "a grouped expression", + WhileParsing::Tuple => "a tuple", + WhileParsing::While => "a while expression", + WhileParsing::If => "an if expression", + WhileParsing::For => "a for expression", + WhileParsing::Else => "an else block", + WhileParsing::Break => "a break expression", + WhileParsing::Return => "a return expression", + WhileParsing::Continue => "a continue expression", + } + .fmt(f) } } } -/// The Parser performs recursive descent on the AST's grammar -/// using a provided [Lexer]. -pub struct Parser { - tokens: Vec, - panic_stack: Vec, - pub errors: Vec, - cursor: usize, -} -impl<'t> From> for Parser { - fn from(value: Lexer<'t>) -> Self { - let mut tokens = vec![]; - for result in value { - match result { - Ok(t) => tokens.push(t), - Err(e) => println!("{e}"), - } - } - Self::new(tokens) - } +pub struct Parser<'t> { + /// Lazy tokenizer + lexer: Lexer<'t>, + /// Look-ahead buffer + next: Option, + /// The location of the current token + loc: Loc, } -impl Parser { - /// Create a new [Parser] from a list of [Tokens][1] - /// and the [text](str) used to generate that list - /// (as [Tokens][1] do not store their strings) +impl<'t> Parser<'t> { + pub fn new(lexer: Lexer<'t>) -> Self { + Self { loc: Loc::from(&lexer), lexer, next: None } + } + /// Gets the location of the last consumed [Token] + pub fn loc(&self) -> Loc { + self.loc + } + + /// Constructs an [Error] + fn error(&self, reason: ErrorKind, while_parsing: WhileParsing) -> Error { + Error { reason, while_parsing, loc: self.loc } + } + /// Internal impl of peek and consume + fn consume_from_lexer(&mut self, while_parsing: WhileParsing) -> PResult { + loop { + match self + .lexer + .scan() + .map_err(|e| self.error(e.into(), while_parsing))? + { + t if t.ty() == Type::Comment => continue, + t => break Ok(t), + } + } + } + /// Looks ahead one token /// - /// [1]: Token - pub fn new(tokens: Vec) -> Self { - Self { tokens, panic_stack: vec![], errors: vec![], cursor: 0 } - } - /// Resets the parser, so it can be reused - pub fn reset(&mut self) -> &mut Self { - *self = Self::new(std::mem::take(&mut self.tokens)); - self - } - /// Parses the [start of an AST](Start) - pub fn parse(&mut self) -> PResult { - self.consume_comments(); - Ok(Start(self.program()?)) - } - /// Parses only one expression - pub fn parse_expr(&mut self) -> PResult { - self.expr() - } - /// Peeks at the current token - pub fn peek(&self) -> PResult<&Token> { - self.tokens - .get(self.cursor) - .ok_or_else(|| Error::end_of_file().maybe_token(self.tokens.last().cloned())) - } - /// Consumes any number of consecutive comments - fn consume_comments(&mut self) -> &mut Self { - while let Ok(Type::Comment) = self.peek().map(|t| t.ty()) { - self.cursor += 1; + /// Stores the token in an internal lookahead buffer + pub fn peek(&mut self, while_parsing: WhileParsing) -> PResult<&Token> { + if self.next.is_none() { + self.next = Some(self.consume_from_lexer(while_parsing)?); } - self + self.next.as_ref().ok_or_else(|| unreachable!()) } - /// Consumes the current token - #[inline] - fn consume(&mut self) -> &mut Self { - self.cursor += 1; - self.consume_comments(); - self + /// Consumes a previously peeked [Token], returning it. + /// Returns [None] when there is no peeked token. + /// + /// This avoids the overhead of constructing an [Error] + pub fn consume_peeked(&mut self) -> Option { + // location must be updated whenever a token is pulled from the lexer + self.loc = Loc::from(&self.lexer); + self.next.take() } -} -/// Panicking -#[allow(dead_code)] -impl Parser { - /// Records the current position on the panic stack - fn mark(&mut self) -> &mut Self { - self.panic_stack.push(self.cursor); - self + /// Looks ahead at the next [Token]'s [Type] + pub fn peek_type(&mut self, while_parsing: WhileParsing) -> PResult { + self.peek(while_parsing).map(|t| t.ty()) } - /// Erases a recorded position from the panic stack - fn unmark(&mut self) -> &mut Self { - self.panic_stack.pop(); - self - } - /// Unwinds the panic stack one step - fn unwind(&mut self) -> PResult<&mut Self> { - let v = self.panic_stack.pop().ok_or(Error::panic_underflow())?; - self.cursor = v; - Ok(self) - } - /// Advances forward until a token with type [`t`](Type) is encountered - fn advance_until(&mut self, t: Type) -> PResult<&mut Self> { - while self.matches(t).is_err() { - self.check_eof().wrap(Error::expected(t))?.consume(); + /// Consumes one [Token] + pub fn consume(&mut self, while_parsing: WhileParsing) -> PResult { + self.loc = Loc::from(&self.lexer); + match self.next.take() { + Some(token) => Ok(token), + None => self.consume_from_lexer(while_parsing), } - Ok(self) } - /// Marks the current position, and unwinds the panic stack if `f` fails. - fn attempt(&mut self, f: F) -> PResult - where F: FnOnce(&mut Self) -> PResult { - self.mark(); - let out = f(self); - match out { - Ok(_) => self.unmark(), - Err(_) => self.unwind()?, - }; - out - } -} -/// Helpers -impl Parser { - /// Returns an error if the end of input has been reached - fn check_eof(&mut self) -> PResult<&mut Self> { - if self.cursor < self.tokens.len() { - Ok(self) + /// Consumes the next [Token] if it matches the pattern [Type] + pub fn match_type(&mut self, want: Type, while_parsing: WhileParsing) -> PResult { + let got = self.peek_type(while_parsing)?; + if got == want { + Ok(self.consume_peeked().expect("should not fail after peek")) } else { - Err(Error::end_of_file().maybe_token(self.tokens.last().cloned())) + Err(self.error(Expected { want, got }, while_parsing)) } } - /// Peeks at the next token if it has the expected [Type] - fn matches(&mut self, t: Type) -> PResult<&Token> { - let token = self.check_eof()?.peek().expect("self should not be eof"); - if token.ty() != t { - Err(Error::expected(t).token(token.clone())) - } else { - Ok(token) - } + /// Consumes the next token if it matches the pattern [Keyword] + pub fn match_kw(&mut self, pat: Keyword, while_parsing: WhileParsing) -> PResult { + self.match_type(Type::Keyword(pat), while_parsing) } - /// Consumes, without returning, a token with the given [Keyword], or returns an error. - /// - /// Useful if you only want to check the existence of a [Keyword] - fn keyword(&mut self, keyword: Keyword) -> PResult<&mut Self> { - self.consume_type(Type::Keyword(keyword)) - } - /// Consumes, without returning, a token with the given [Type], or returns an error. - /// - /// Useful if you only want to check the existence of a token. - fn consume_type(&mut self, t: Type) -> PResult<&mut Self> { - self.matches(t)?; - Ok(self.consume()) - } - #[doc(hidden)] - fn todo_error(&mut self, l: u32, c: u32, s: &str) -> Error { - eprintln!("TODO: {s}:{l}:{c}"); - Error::unspecified().token(self.peek().unwrap().clone()) - } -} -/// TODO: Remove `ptodo*` -macro ptodo_err($self:expr $(, $t:expr)*) { - $($t;)* - $self.todo_error(line!(), column!(), file!()) -} -macro ptodo($self:expr $(, $t:expr)*) { - $($t;)* - Err(ptodo_err!($self)) } -/// # Terminals and Pseudo-Terminals -impl Parser { - /// Parses an [Identifier] - fn identifier(&mut self) -> PResult { - let out = match self.matches(Type::Identifier)?.data() { - Data::Identifier(id) => Identifier { name: id.to_string(), index: None }, - _ => Err(Error::not_identifier())?, - }; - self.consume(); +/// Generic parse functions +impl<'t> Parser<'t> { + /// Parses constructions of the form `Open F Close` + fn delimited( + &mut self, + open: Type, + f: F, + close: Type, + while_parsing: WhileParsing, + ) -> PResult + where + F: Fn(&mut Self) -> PResult, + { + self.match_type(open, while_parsing)?; + let out = f(self)?; + self.match_type(close, while_parsing)?; Ok(out) } - /// Parses a [Literal](literal::Literal) - fn literal(&mut self) -> PResult { - use literal::Literal::*; - use Keyword::{False, True}; - let token = self.peek()?; - match token.ty() { - Type::Float => self.float().map(Float), - Type::Integer => self.int().map(Int), - Type::String => self.string().map(String), - Type::Character => self.char().map(Char), - Type::Keyword(True | False) => self.bool().map(Bool), - _ => Err(Error::not_literal().token(token.clone())), - } - } - /// Parses a [floating point literal](literal::Float) - fn float(&mut self) -> PResult { - ptodo!(self) - } - /// Parses an [integer literal](u128) + /// Parses constructions of the form `(F Separator ~Terminator)*` /// - /// u128 was chosen for this, since it stores the largest integer precision Rust natively - /// supports. Conlang doesn't currently plan to support arbitrary-width arithmetic anyway. - fn int(&mut self) -> PResult { - let out = match self.matches(Type::Integer)?.data() { - Data::Integer(i) => *i, - _ => Err(Error::not_int())?, - }; - self.consume(); - Ok(out) - } - /// Parses a [string literal](String) - fn string(&mut self) -> PResult { - let out = match self.matches(Type::String)?.data() { - Data::String(s) => s.clone(), - _ => Err(Error::not_string())?, - }; - self.consume(); - Ok(out) - } - /// Parses a [character literal](char) - fn char(&mut self) -> PResult { - let out = match self.matches(Type::Character)?.data() { - Data::Character(c) => *c, - _ => Err(Error::not_char())?, - }; - self.consume(); - Ok(out) - } - /// Parses a [boolean literal](bool) - fn bool(&mut self) -> PResult { - use Keyword::{False, True}; - let token = self.peek()?; - let out = match token.ty() { - Type::Keyword(False) => false, - Type::Keyword(True) => true, - _ => Err(Error::not_bool().token(token.clone()))?, - }; - self.consume(); - Ok(out) - } -} -/// Statements -impl Parser { - /// Parses a series of [statements](Stmt) - fn program(&mut self) -> PResult { - let mut out = vec![]; - while self.check_eof().is_ok() { - out.push(self.stmt()?); - } - Ok(Program(out)) - } - /// Parses a single [statement](Stmt) - fn stmt(&mut self) -> PResult { - let token = self.peek()?; - match token.ty() { - Type::Keyword(Keyword::Let) => self.let_stmt().map(Stmt::Let).wrap(Error::not_let()), - Type::Keyword(Keyword::Fn) => self.fn_decl().map(Stmt::Fn).wrap(Error::not_fn_decl()), - _ => { - let out = Stmt::Expr(self.expr()?); - self.consume_type(Type::Semi)?; - Ok(out) - } - } - .wrap(Error::not_statement()) - } - /// Parses a [Let] statement - fn let_stmt(&mut self) -> PResult { - self.keyword(Keyword::Let)?; - let out = - Let { name: self.name()?, init: self.consume_type(Type::Eq).and_then(Self::expr).ok() }; - self.consume_type(Type::Semi)?; - Ok(out) - } - /// Parses a [function declaration](FnDecl) statement - fn fn_decl(&mut self) -> PResult { - self.keyword(Keyword::Fn)?; - let name = self.identifier()?; - self.consume_type(Type::LParen)?; - let args = self.params()?; - self.consume_type(Type::RParen)?; - // TODO: Parse type-expressions and store return types in the AST - let ty = if self.consume_type(Type::Arrow).is_ok() { - Some(self.type_expr()?) - } else { - None - }; - Ok(FnDecl { name: Name { symbol: name, mutable: false, ty }, args, body: self.block()? }) - } - /// Parses a [parameter](Name) list for [FnDecl] - fn params(&mut self) -> PResult> { + /// where `~Terminator` is a negative lookahead assertion + fn separated( + &mut self, + separator: Type, + f: F, + terminator: Type, + while_parsing: WhileParsing, + ) -> PResult> + where + F: Fn(&mut Self) -> PResult, + { let mut args = vec![]; - while let Ok(name) = self.name() { - args.push(name); - if self.consume_type(Type::Comma).is_err() { + while terminator != self.peek_type(while_parsing)? { + args.push(f(self)?); + if separator != self.peek_type(while_parsing)? { break; } + self.consume_peeked(); } Ok(args) } - /// Parses a [Name]; the object of a let statement, or a single function parameter. - fn name(&mut self) -> PResult { - Ok(Name { - mutable: self.keyword(Keyword::Mut).is_ok(), - symbol: self.identifier()?, - ty: self - .consume_type(Type::Colon) - .and_then(|this| this.type_expr()) - .ok(), - }) + /// Parses constructions of the form `(F ~Terminator)*` + /// + /// where `~Terminator` is a negative lookahead assertion + fn repeated( + &mut self, + f: F, + terminator: Type, + while_parsing: WhileParsing, + ) -> PResult> + where + F: Fn(&mut Self) -> PResult, + { + let mut out = vec![]; + while terminator != self.peek_type(while_parsing)? { + out.push(f(self)?); + } + Ok(out) } } -/// Path Expressions -impl Parser { - fn path(&mut self) -> PResult { - let absolute = self.consume_type(Type::ColonColon).is_ok(); - let mut parts = vec![]; - while let Ok(id) = self.path_part() { - parts.push(id); - if self.consume_type(Type::ColonColon).is_err() { - break; - } + +/// Expands to a pattern which matches item-like [Token] [Type]s +macro item_like() { + Type::Keyword( + Keyword::Pub + | Keyword::Const + | Keyword::Static + | Keyword::Mod + | Keyword::Fn + | Keyword::Struct + | Keyword::Enum + | Keyword::Impl, + ) +} + +/// Top level parsing +impl<'t> Parser<'t> { + /// Parses a [File] + pub fn file(&mut self) -> PResult { + let mut items = vec![]; + while match self.peek_type(WhileParsing::File) { + Ok(Type::RCurly) | Err(Error { reason: EndOfInput, .. }) => false, + Ok(_) => true, + Err(e) => Err(e)?, + } { + items.push(self.item()?) + } + Ok(File { items }) + } + + /// Parses an [Item] + /// + /// See also: [Parser::itemkind] + pub fn item(&mut self) -> PResult { + let start = self.loc(); + Ok(Item { + vis: self.visibility()?, + kind: self.itemkind()?, + extents: Span(start, self.loc()), + }) + } + + /// Parses a [Ty] + /// + /// See also: [Parser::tykind] + pub fn ty(&mut self) -> PResult { + let start = self.loc(); + Ok(Ty { kind: self.tykind()?, extents: Span(start, self.loc()) }) + } + + /// Parses a [Path] + /// + /// See also: [Parser::path_part], [Parser::identifier] + pub fn path(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::PathExpr; + let absolute = matches!(self.peek_type(PARSING)?, Type::ColonColon); + if absolute { + self.consume_peeked(); + } + + let mut parts = vec![self.path_part()?]; + while let Ok(Type::ColonColon) = self.peek_type(PARSING) { + self.consume_peeked(); + parts.push(self.path_part()?); } Ok(Path { absolute, parts }) } - fn path_part(&mut self) -> PResult { - match self.peek()?.ty() { - Type::Identifier => self.identifier().map(PathPart::PathIdent), - Type::Keyword(Keyword::Super) => { - self.keyword(Keyword::Super).map(|_| PathPart::PathSuper) - } - Type::Keyword(Keyword::SelfKw) => { - self.keyword(Keyword::SelfKw).map(|_| PathPart::PathSelf) - } - e => Err(Error::not_path_segment(e)), - } - } -} -/// Type Expressions -impl Parser { - /// Parses a [Type Expression](TypeExpr) - fn type_expr(&mut self) -> PResult { - match self.peek()?.ty() { - Type::LParen => self.type_tuple().map(TypeExpr::TupleType), - Type::Bang => self.type_never().map(TypeExpr::Never), - _ => self.path().map(TypeExpr::TypePath), - } - } - fn type_tuple(&mut self) -> PResult { - self.consume_type(Type::LParen)?; - let mut types = vec![]; - while let Ok(ty) = self.type_expr() { - types.push(ty); - if self.consume_type(Type::Comma).is_err() { - break; - } - } - self.consume_type(Type::RParen)?; - Ok(TupleType { types }) - } - fn type_never(&mut self) -> PResult { - self.consume_type(Type::Bang).map(|_| Never) - } -} - -/// Expressions -impl Parser { - /// Parses an [expression](Expr) - fn expr(&mut self) -> PResult { - Ok(Expr(self.assign()?)) - } - /// Parses a [block expression](Block) - fn block(&mut self) -> PResult { - let mut statements = vec![]; - let mut expr: Option> = None; - self.consume_type(Type::LCurly)?; - // tHeRe Is No PlAcE iN yOuR gRaMmAr WhErE bOtH aN eXpReSsIoN aNd A sTaTeMeNt ArE eXpEcTeD - while self.consume_type(Type::RCurly).is_err() { - match self.expr() { - Ok(e) if self.consume_type(Type::Semi).is_ok() => statements.push(Stmt::Expr(e)), - Ok(e) => { - expr = Some(Box::new(e)); - self.consume_type(Type::RCurly)?; - break; + /// Parses a [Stmt] + /// + /// See also: [Parser::stmtkind] + pub fn stmt(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::Stmt; + let start = self.loc(); + Ok(Stmt { + kind: match self.peek_type(PARSING)? { + Type::Semi => Ok(StmtKind::Empty), + Type::Keyword(Keyword::Let) => self.stmtkind_local(), + item_like!() => self.stmtkind_item(), + _ => self.stmtkind_expr(), + }?, + semi: match self.peek_type(PARSING) { + Ok(Type::Semi) => { + self.consume_peeked(); + Semi::Terminated } - Err(_) => statements.push(self.stmt()?), - } - } - Ok(Block { statements, expr, let_count: None }) - } - /// Parses a [primary expression](Primary) - fn primary(&mut self) -> PResult { - let token = self.peek()?; - match token.ty() { - Type::Identifier => self.identifier().map(Primary::Identifier), - Type::String - | Type::Character - | Type::Integer - | Type::Float - | Type::Keyword(Keyword::True | Keyword::False) => self.literal().map(Primary::Literal), - Type::LCurly => self.block().map(Primary::Block), - Type::LParen => self.group().map(Primary::Group), - Type::Keyword(_) => self.flow().map(Primary::Branch), - e => Err(Error::unexpected(e).token(token.clone()))?, - } - } -} -/// [Call] expressions -impl Parser { - /// Parses a [call expression](Call) - fn call(&mut self) -> PResult { - let callee = self.primary()?; - if self.matches(Type::LParen).is_err() { - return Ok(Call::Primary(callee)); - }; - let mut args = vec![]; - while self.consume_type(Type::LParen).is_ok() { - match self.consume_type(Type::RParen) { - Ok(_) => args.push(Tuple { elements: vec![] }), - Err(_) => { - args.push(self.tuple()?); - self.consume_type(Type::RParen)?; - } - } - } - Ok(Call::FnCall(FnCall { callee: callee.into(), args })) - } -} - -/// Groups and Tuples -impl Parser { - /// Parses a [group expression](Group) - fn group(&mut self) -> PResult { - let t = self.consume_type(Type::LParen)?.peek()?; - match t.ty() { - Type::RParen => { - self.consume(); - Ok(Group::Empty) - } - _ => { - let mut out = self.tuple()?; - let out = if out.elements.len() == 1 { - Group::Single(out.elements.remove(0).into()) - } else { - Group::Tuple(out) - }; - self.consume_type(Type::RParen)?; - Ok(out) - } - } - } - /// Parses a [tuple expression](Tuple) - fn tuple(&mut self) -> PResult { - let mut elements = vec![self.expr()?]; - while self.consume_type(Type::Comma).is_ok() { - elements.push(self.expr()?); - } - Ok(Tuple { elements }) - } -} - -/// Helper macro for math parsing subexpressions with production -/// ```ebnf -/// Ret = a (b a)* -/// ``` -/// # Examples -/// ```rust,ignore -/// binary!{ -/// function_name: ret::Value = parse_operands, parse_operators; -/// } -/// ``` -/// becomes -/// ```rust,ignore -/// fn function_name(&mut self) -> PResult { ... } -/// ``` -macro binary ($($f:ident = $a:ident, $b:ident);*$(;)?) {$( - #[doc = concat!("Parses a(n) [", stringify!($f), " operation](Operation::Binary) expression")] - fn $f (&mut self) -> PResult { - let (first, mut other) = (self.$a()?, vec![]); - while let Ok(op) = self.$b() { - other.push((op, self.$a()?)); - } - Ok(if other.is_empty() { first } else { - Operation::Binary(Binary { first: first.into(), other }) + _ => Semi::Unterminated, + }, + extents: Span(start, self.loc()), }) } -)*} -/// # [Arithmetic and Logical Subexpressions](math) -impl Parser { - fn assign(&mut self) -> PResult { - let next = self.compare()?; - let Ok(operator) = self.assign_op() else { - return Ok(next); - }; - let Operation::Call(Call::Primary(Primary::Identifier(target))) = next else { - return Ok(next); - }; - Ok(Operation::Assign(Assign { - target, - operator, - init: self.assign()?.into(), - })) - } - binary! { - // name operands operators - compare = range, compare_op; - range = logic, range_op; - logic = bitwise, logic_op; - bitwise = shift, bitwise_op; - shift = term, shift_op; - term = factor, term_op; - factor = unary, factor_op; - } - /// Parses a [unary operation](Operation::Unary) expression - fn unary(&mut self) -> PResult { - let mut operators = vec![]; - while let Ok(op) = self.unary_op() { - operators.push(op) - } - if operators.is_empty() { - return self.primary_operation(); - } - Ok(Operation::Unary(Unary { - operators, - operand: self.primary_operation()?.into(), - })) - } - /// Parses a [primary operation](Operation::Primary) expression - fn primary_operation(&mut self) -> PResult { - Ok(Operation::Call(self.call()?)) + + /// Parses an [Expr] + /// + /// See also: [Parser::exprkind] + pub fn expr(&mut self) -> PResult { + self.expr_from(Self::exprkind) } } -macro operator_impl ($($(#[$m:meta])* $f:ident : {$($type:pat => $op:ident),*$(,)?})*) { - $($(#[$m])* fn $f(&mut self) -> PResult { - use operator::Binary; - let token = self.peek().wrap(Error::not_operator())?; - let out = Ok(match token.ty() { - $($type => Binary::$op,)* - _ => Err(Error::not_operator().token(token.clone()))?, + +/// Item parsing +impl<'t> Parser<'t> { + /// Parses an [ItemKind] + /// + /// See also: [Parser::item] + pub fn itemkind(&mut self) -> PResult { + Ok(match self.peek_type(WhileParsing::Item)? { + Type::Keyword(Keyword::Const) => self.parse_const()?.into(), + Type::Keyword(Keyword::Static) => self.parse_static()?.into(), + Type::Keyword(Keyword::Mod) => self.parse_module()?.into(), + Type::Keyword(Keyword::Fn) => self.parse_function()?.into(), + Type::Keyword(Keyword::Struct) => self.parse_struct()?.into(), + Type::Keyword(Keyword::Enum) => self.parse_enum()?.into(), + Type::Keyword(Keyword::Impl) => self.parse_impl()?.into(), + t => Err(self.error(Unexpected(t), WhileParsing::Item))?, + }) + } + + pub fn parse_const(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::Const; + self.match_kw(Keyword::Const, PARSING)?; + let out = Ok(Const { + name: self.identifier()?, + ty: { + self.match_type(Type::Colon, PARSING)?; + self.ty()?.into() + }, + init: { + self.match_type(Type::Eq, PARSING)?; + self.expr()?.into() + }, }); - self.consume(); + self.match_type(Type::Semi, PARSING)?; out + } + pub fn parse_static(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::Static; + self.match_kw(Keyword::Static, PARSING)?; + let out = Ok(Static { + mutable: self.mutability()?, + name: self.identifier()?, + ty: { + self.match_type(Type::Colon, PARSING)?; + self.ty()?.into() + }, + init: { + self.match_type(Type::Eq, PARSING)?; + self.expr()?.into() + }, + }); + self.match_type(Type::Semi, PARSING)?; + out + } + pub fn parse_module(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::Module; + self.match_kw(Keyword::Mod, PARSING)?; + Ok(Module { name: self.identifier()?, kind: self.modulekind()? }) + } + pub fn modulekind(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::ModuleKind; + match self.peek_type(PARSING)? { + Type::LCurly => Ok(ModuleKind::Inline(self.delimited( + Type::LCurly, + Self::file, + Type::RCurly, + PARSING, + )?)), + Type::Semi => { + self.consume_peeked(); + Ok(ModuleKind::Outline) + } + got => Err(self.error(Expected { want: Type::Semi, got }, PARSING)), + } + } + pub fn parse_function(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::Function; + self.match_kw(Keyword::Fn, PARSING)?; + Ok(Function { + name: self.identifier()?, + args: self.parse_params()?, + rety: match self.peek_type(PARSING)? { + Type::LCurly | Type::Semi => None, + Type::Arrow => { + self.consume_peeked(); + Some(self.ty()?.into()) + } + got => Err(self.error(Expected { want: Type::Arrow, got }, PARSING))?, + }, + body: match self.peek_type(PARSING)? { + Type::LCurly => Some(self.block()?), + Type::Semi => { + self.consume_peeked(); + None + } + t => Err(self.error(Unexpected(t), PARSING))?, + }, + }) + } + pub fn parse_params(&mut self) -> PResult> { + const PARSING: WhileParsing = WhileParsing::Function; + self.delimited( + Type::LParen, + |this| this.separated(Type::Comma, Self::parse_param, Type::RParen, PARSING), + Type::RParen, + PARSING, + ) + } + pub fn parse_param(&mut self) -> PResult { + Ok(Param { + mutability: self.mutability()?, + name: self.identifier()?, + ty: { + self.match_type(Type::Colon, WhileParsing::Param)?; + self.ty()?.into() + }, + }) + } + pub fn parse_struct(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::Struct; + self.match_kw(Keyword::Struct, PARSING)?; + Ok(Struct { + name: self.identifier()?, + kind: match self.peek_type(PARSING)? { + Type::LParen => self.structkind_tuple()?, + Type::LCurly => self.structkind_struct()?, + Type::Semi => { + self.consume_peeked(); + StructKind::Empty + } + got => Err(self.error(Expected { want: Type::Semi, got }, PARSING))?, + }, + }) + } + pub fn structkind_tuple(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::StructKind; + + Ok(StructKind::Tuple(self.delimited( + Type::LParen, + |s| s.separated(Type::Comma, Self::ty, Type::RParen, PARSING), + Type::RParen, + PARSING, + )?)) + } + pub fn structkind_struct(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::StructKind; + + Ok(StructKind::Struct(self.delimited( + Type::LCurly, + |s| s.separated(Type::Comma, Self::struct_member, Type::RCurly, PARSING), + Type::RCurly, + PARSING, + )?)) + } + pub fn struct_member(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::StructMember; + Ok(StructMember { + vis: self.visibility()?, + name: self.identifier()?, + ty: { + self.match_type(Type::Colon, PARSING)?; + self.ty()? + }, + }) + } + pub fn parse_enum(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::Enum; + self.match_kw(Keyword::Enum, PARSING)?; + Err(self.error(Todo, PARSING)) + } + pub fn parse_impl(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::Impl; + self.match_kw(Keyword::Impl, PARSING)?; + Err(self.error(Todo, PARSING)) + } + + pub fn visibility(&mut self) -> PResult { + if let Type::Keyword(Keyword::Pub) = self.peek_type(WhileParsing::Visibility)? { + self.consume_peeked(); + return Ok(Visibility::Public); + }; + Ok(Visibility::Private) + } + pub fn mutability(&mut self) -> PResult { + if let Type::Keyword(Keyword::Mut) = self.peek_type(WhileParsing::Mutability)? { + self.consume_peeked(); + return Ok(Mutability::Mut); + }; + Ok(Mutability::Not) + } +} + +/// # Type parsing +impl<'t> Parser<'t> { + /// Parses a [TyKind] + /// + /// See also: [Parser::ty] + pub fn tykind(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::TyKind; + let out = match self.peek_type(PARSING)? { + Type::Bang => { + self.consume_peeked(); + TyKind::Never + } + Type::Amp | Type::AmpAmp => self.tyref()?.into(), + Type::LParen => self.tytuple()?.into(), + Type::Keyword(Keyword::Fn) => self.tyfn()?.into(), + path_like!() => self.path()?.into(), + t => Err(self.error(Unexpected(t), PARSING))?, + }; + + Ok(out) + } + /// [TyTuple] = `(` ([Ty] `,`)* [Ty]? `)` + pub fn tytuple(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::TyTuple; + Ok(TyTuple { + types: self.delimited( + Type::LParen, + |s| s.separated(Type::Comma, Self::ty, Type::RParen, PARSING), + Type::RParen, + PARSING, + )?, + }) + } + /// [TyRef] = (`&`|`&&`)* [Path] + pub fn tyref(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::TyRef; + let mut count = 0; + loop { + match self.peek_type(PARSING)? { + Type::Amp => count += 1, + Type::AmpAmp => count += 2, + _ => break, + } + self.consume_peeked(); + } + Ok(TyRef { count, to: self.path()? }) + } + /// [TyFn] = `fn` [TyTuple] (-> [Ty])? + pub fn tyfn(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::TyFn; + self.match_type(Type::Keyword(Keyword::Fn), PARSING)?; + Ok(TyFn { + args: self.tytuple()?, + rety: { + match self.peek_type(PARSING)? { + Type::Arrow => { + self.consume_peeked(); + Some(self.ty()?.into()) + } + _ => None, + } + }, + }) + } +} + +/// Expands to a pattern which matches literal-like [Type]s +macro literal_like() { + Type::Keyword(Keyword::True | Keyword::False) + | Type::String + | Type::Character + | Type::Integer + | Type::Float +} +/// Expands to a pattern which matches path-like [token Types](Type) +macro path_like() { + Type::Keyword(Keyword::Super | Keyword::SelfKw) | Type::Identifier | Type::ColonColon +} +/// # Path parsing +impl<'t> Parser<'t> { + /// [PathPart] = `super` | `self` | [Identifier] + pub fn path_part(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::PathPart; + let out = match self.peek_type(PARSING)? { + Type::Keyword(Keyword::Super) => PathPart::SuperKw, + Type::Keyword(Keyword::SelfKw) => PathPart::SelfKw, + Type::Identifier => PathPart::Ident(self.identifier()?), + t => return Err(self.error(Unexpected(t), PARSING)), + }; + self.consume_peeked(); + Ok(out) + } + /// [Identifier] = [`Identifier`](Type::Identifier) + pub fn identifier(&mut self) -> PResult { + let tok = self.match_type(Type::Identifier, WhileParsing::Identifier)?; + match tok.data() { + Data::Identifier(ident) => Ok(ident.into()), + _ => panic!("Expected token data for {tok:?}"), + } + } +} + +/// # Statement parsing +impl<'t> Parser<'t> { + /// Parses a [StmtKind] + /// + /// See also: [Parser::stmt] + pub fn stmtkind(&mut self) -> PResult { + match self.peek_type(WhileParsing::StmtKind)? { + Type::Semi => Ok(StmtKind::Empty), + Type::Keyword(Keyword::Let) => self.stmtkind_local(), + item_like!() => self.stmtkind_item(), + _ => self.stmtkind_expr(), + } + } + pub fn stmtkind_local(&mut self) -> PResult { + Ok(StmtKind::Local(self.parse_let()?)) + } + pub fn stmtkind_item(&mut self) -> PResult { + Ok(StmtKind::Item(Box::new(self.item()?))) + } + pub fn stmtkind_expr(&mut self) -> PResult { + Ok(StmtKind::Expr(self.expr()?.into())) + } + + pub fn parse_let(&mut self) -> PResult { + self.match_kw(Keyword::Let, WhileParsing::Let)?; + Ok(Let { + mutable: self.mutability()?, + name: self.identifier()?, + init: if Type::Eq == self.peek_type(WhileParsing::Let)? { + self.consume_peeked(); + Some(self.expr()?.into()) + } else { + None + }, + }) + } +} + +macro binary($($name:ident {$lower:ident, $op:ident})*) { + $(pub fn $name(&mut self) -> PResult { + let head = self.expr_from(Self::$lower)?; + let mut tail = vec![]; + loop { + match self.$op() { + Ok(op) => tail.push((op, self.expr_from(Self::$lower)?)), + Err(Error { reason: Unexpected(_), ..}) => break, + Err(e) => Err(e)?, + } + } + if tail.is_empty() { + return Ok(head.kind); + } + Ok(Binary { head: head.into(), tail }.into()) })* } -/// # [Operators](operator) -impl Parser { - operator_impl! { - /// Parses a [factor operator](operator) - factor_op: { - Type::Star => Mul, - Type::Slash => Div, - Type::Rem => Rem, - } - /// Parses a [term operator](operator) - term_op: { - Type::Plus => Add, - Type::Minus => Sub, - } - /// Parses a [shift operator](operator) - shift_op: { - Type::LtLt => Lsh, - Type::GtGt => Rsh, - } - /// Parses a [bitwise operator](operator) - bitwise_op: { - Type::Amp => BitAnd, - Type::Bar => BitOr, - Type::Xor => BitXor, - } - /// Parses a [logic operator](operator) - logic_op: { - Type::AmpAmp => LogAnd, - Type::BarBar => LogOr, - Type::XorXor => LogXor, - } - /// Parses a [range operator](operator) - range_op: { - Type::DotDot => RangeExc, - Type::DotDotEq => RangeInc, - } - /// Parses a [compare operator](operator) - compare_op: { - Type::Lt => Less, - Type::LtEq => LessEq, - Type::EqEq => Equal, - Type::BangEq => NotEq, - Type::GtEq => GreaterEq, - Type::Gt => Greater, +/// # Expression parsing +impl<'t> Parser<'t> { + /// Parses an [ExprKind] + /// + /// See also: [Parser::expr], [Parser::exprkind_primary] + pub fn exprkind(&mut self) -> PResult { + self.exprkind_assign() + } + /// Creates an [Expr] with the given [ExprKind]-parser + pub fn expr_from(&mut self, f: impl Fn(&mut Self) -> PResult) -> PResult { + let start = self.loc(); + Ok(Expr { kind: f(self)?, extents: Span(start, self.loc()) }) + } + pub fn optional_expr(&mut self) -> PResult> { + match self.expr() { + Ok(v) => Ok(Some(v)), + Err(Error { reason: Nothing, .. }) => Ok(None), + Err(e) => Err(e), } } - /// Parses an [assign operator](operator::Assign) - fn assign_op(&mut self) -> PResult { - use operator::Assign; - let token = self.peek()?; - let out = Ok(match token.ty() { - Type::Eq => Assign::Assign, - Type::PlusEq => Assign::AddAssign, - Type::MinusEq => Assign::SubAssign, - Type::StarEq => Assign::MulAssign, - Type::SlashEq => Assign::DivAssign, - Type::RemEq => Assign::RemAssign, - Type::AmpEq => Assign::BitAndAssign, - Type::BarEq => Assign::BitOrAssign, - Type::XorEq => Assign::BitXorAssign, - Type::LtLtEq => Assign::ShlAssign, - Type::GtGtEq => Assign::ShrAssign, - _ => Err(Error::not_operator().token(token.clone()))?, - }); - self.consume(); + + /// [Assign] = [Path] ([AssignKind] [Assign]) | [Compare](Binary) + pub fn exprkind_assign(&mut self) -> PResult { + let head = self.expr_from(Self::exprkind_compare)?; + if !matches!(head.kind, ExprKind::Path(_)) { + return Ok(head.kind); + } + let Ok(op) = self.assign_op() else { + return Ok(head.kind); + }; + Ok(Assign { head, op, tail: self.expr_from(Self::exprkind_assign)?.into() }.into()) + } + binary! { + exprkind_compare {exprkind_range, compare_op} + exprkind_range {exprkind_logic, range_op} + exprkind_logic {exprkind_bitwise, logic_op} + exprkind_bitwise {exprkind_shift, bitwise_op} + exprkind_shift {exprkind_factor, shift_op} + exprkind_factor {exprkind_term, factor_op} + exprkind_term {exprkind_unary, term_op} + } + /// [Unary] = [UnaryKind]* [Member] + pub fn exprkind_unary(&mut self) -> PResult { + let mut ops = vec![]; + loop { + match self.unary_op() { + Ok(v) => ops.push(v), + Err(Error { reason: Unexpected(_), .. }) => break, + Err(e) => Err(e)?, + } + } + let tail = self.expr_from(Self::exprkind_member)?; + if ops.is_empty() { + return Ok(tail.kind); + } + Ok(Unary { ops, tail: Box::new(tail) }.into()) + } + /// [Member] = [Call] `.` [Call] + pub fn exprkind_member(&mut self) -> PResult { + let head = self.expr_from(Self::exprkind_call)?; + let mut tail = vec![]; + while self.member_op().is_ok() { + tail.push(self.expr_from(Self::exprkind_call)?) + } + if tail.is_empty() { + Ok(head.kind) + } else { + Ok(Member { head: head.into(), tail }.into()) + } + } + /// Call = [Index] (`(` [Tuple]? `)`)* + pub fn exprkind_call(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::Call; + let callee = self.expr_from(Self::exprkind_index)?; + let mut args = vec![]; + while Ok(Type::LParen) == self.peek_type(PARSING) { + self.consume_peeked(); + args.push(self.tuple()?); + self.match_type(Type::RParen, PARSING)?; + } + if args.is_empty() { + Ok(callee.kind) + } else { + Ok(Call { callee: callee.into(), args }.into()) + } + } + /// [Index] = [Primary](Parser::exprkind_primary) (`[` [Indices] `]`)* + pub fn exprkind_index(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::Index; + let head = self.expr_from(Self::exprkind_primary)?; + if Type::LBrack != self.peek_type(PARSING)? { + return Ok(head.kind); + } + + let mut indices = vec![]; + while Ok(Type::LBrack) == self.peek_type(PARSING) { + self.consume_peeked(); + indices.push(self.tuple()?.into()); + self.match_type(Type::RBrack, PARSING)?; + } + Ok(Index { head: head.into(), indices }.into()) + } + /// Delegates to the set of highest-priority rules based on unambiguous pattern matching + pub fn exprkind_primary(&mut self) -> PResult { + match self.peek_type(WhileParsing::Expr)? { + Type::Amp | Type::AmpAmp => self.exprkind_addrof(), + Type::LCurly => self.exprkind_block(), + Type::LBrack => self.exprkind_array(), + Type::LParen => self.exprkind_empty_group_or_tuple(), + literal_like!() => Ok(self.literal()?.into()), + path_like!() => Ok(self.path()?.into()), + Type::Keyword(Keyword::If) => Ok(self.parse_if()?.into()), + Type::Keyword(Keyword::For) => Ok(self.parse_for()?.into()), + Type::Keyword(Keyword::While) => Ok(self.parse_while()?.into()), + Type::Keyword(Keyword::Break) => Ok(self.parse_break()?.into()), + Type::Keyword(Keyword::Return) => Ok(self.parse_return()?.into()), + Type::Keyword(Keyword::Continue) => Ok(self.parse_continue()?.into()), + _ => Err(self.error(Nothing, WhileParsing::Expr)), + } + } + /// [Array] = '[' ([Expr] ',')* [Expr]? ']' + /// + /// Array and ArrayRef are ambiguous until the second token, + /// so they can't be independent subexpressions + pub fn exprkind_array(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::Array; + const START: Type = Type::LBrack; + const END: Type = Type::RBrack; + self.match_type(START, PARSING)?; + match self.peek_type(PARSING)? { + END => { + self.consume_peeked(); + Ok(Array { values: vec![] }.into()) + } + _ => self.exprkind_array_rep(), + } + } + /// [ArrayRep] = `[` [Expr] `;` [Expr] `]` + pub fn exprkind_array_rep(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::Array; + const END: Type = Type::RBrack; + let first = self.expr()?; + let out: ExprKind = match self.peek_type(PARSING)? { + Type::Semi => ArrayRep { + value: first.into(), + repeat: { + self.consume_peeked(); + Box::new(self.expr()?) + }, + } + .into(), + Type::RBrack => Array { values: vec![first] }.into(), + Type::Comma => Array { + values: { + self.consume_peeked(); + let mut out = vec![first]; + out.extend(self.separated(Type::Comma, Self::expr, Type::RBrack, PARSING)?); + out + }, + } + .into(), + ty => Err(self.error(Unexpected(ty), PARSING))?, + }; + self.match_type(END, PARSING)?; + Ok(out) + } + + /// [AddrOf] = (`&`|`&&`)* [Expr] + pub fn exprkind_addrof(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::AddrOf; + let mut count = 0; + loop { + match self.peek_type(PARSING)? { + Type::Amp => count += 1, + Type::AmpAmp => count += 2, + _ => break, + } + self.consume_peeked(); + } + Ok(AddrOf { count, mutable: self.mutability()?, expr: self.expr()?.into() }.into()) + } + /// [Block] = `{` [Stmt]* `}` + pub fn exprkind_block(&mut self) -> PResult { + self.block().map(Into::into) + } + /// [Group] = `(`([Empty](ExprKind::Empty)|[Expr]|[Tuple])`)` + /// + /// [ExprKind::Empty] and [Group] are special cases of [Tuple] + pub fn exprkind_empty_group_or_tuple(&mut self) -> PResult { + self.match_type(Type::LParen, WhileParsing::Group)?; + let out = match self.peek_type(WhileParsing::Group)? { + Type::RParen => Ok(ExprKind::Empty), + _ => self.exprkind_group(), + }; + match self.peek_type(WhileParsing::Group) { + Ok(Type::RParen) => self.consume_peeked(), + _ => Err(self.error(UnmatchedParentheses, WhileParsing::Group))?, + }; out } - /// Parses a [unary operator](operator::Unary) - fn unary_op(&mut self) -> PResult { - use operator::Unary; - let token = self.peek()?; - let out = Ok(match token.ty() { - Type::AmpAmp => Unary::RefRef, - Type::Amp => Unary::Ref, - Type::Star => Unary::Deref, - Type::Minus => Unary::Neg, - Type::Bang => Unary::Not, - Type::At => Unary::At, - Type::Hash => Unary::Hash, - Type::Tilde => Unary::Tilde, - _ => Err(Error::not_operator().token(token.clone()))?, - }); - self.consume(); - out + /// [Group] = `(`([Empty](ExprKind::Empty)|[Expr]|[Tuple])`)` + pub fn exprkind_group(&mut self) -> PResult { + let first = self.expr()?; + match self.peek_type(WhileParsing::Group)? { + Type::Comma => { + let mut exprs = vec![first]; + self.consume_peeked(); + while Type::RParen != self.peek_type(WhileParsing::Tuple)? { + exprs.push(self.expr()?); + match self.peek_type(WhileParsing::Tuple)? { + Type::Comma => self.consume_peeked(), + _ => break, + }; + } + Ok(Tuple { exprs }.into()) + } + _ => Ok(Group { expr: first.into() }.into()), + } } } -/// # [Control Flow](control) -impl Parser { - /// Parses a [control flow](Flow) expression - fn flow(&mut self) -> PResult { - use Keyword::{Break, Continue, For, If, Return, While}; - let token = self.peek()?; - match token.ty() { - Type::Keyword(While) => self.parse_while().map(Flow::While), - Type::Keyword(For) => self.parse_for().map(Flow::For), - Type::Keyword(If) => self.parse_if().map(Flow::If), - Type::Keyword(Break) => self.parse_break().map(Flow::Break), - Type::Keyword(Return) => self.parse_return().map(Flow::Return), - Type::Keyword(Continue) => self.parse_continue().map(Flow::Continue), - e => Err(Error::unexpected(e).token(token.clone()))?, + +/// ## Subexpressions +impl<'t> Parser<'t> { + /// [Literal] = [String](Type::String) | [Character](Type::Character) + /// | [Float](Type::Float) (TODO) | [Integer](Type::Integer) | `true` | `false` + pub fn literal(&mut self) -> PResult { + let tok = self.consume(WhileParsing::Literal)?; + // keyword literals true and false + match tok.ty() { + Type::Keyword(Keyword::True) => return Ok(Literal::Bool(true)), + Type::Keyword(Keyword::False) => return Ok(Literal::Bool(false)), + Type::String | Type::Character | Type::Integer | Type::Float => (), + t => return Err(self.error(Unexpected(t), WhileParsing::Literal)), } - .wrap(Error::not_branch()) - } - /// Parses an [if](If) expression - fn parse_if(&mut self) -> PResult { - self.keyword(Keyword::If)?; - Ok(If { cond: self.expr()?.into(), body: self.block()?, else_: self.parse_else()? }) - } - /// Parses a [while](While) expression - fn parse_while(&mut self) -> PResult { - self.keyword(Keyword::While)?; - Ok(While { cond: self.expr()?.into(), body: self.block()?, else_: self.parse_else()? }) - } - /// Parses a [for](For) expression - fn parse_for(&mut self) -> PResult { - self.keyword(Keyword::For)?; - Ok(For { - var: self.identifier()?, - iter: { self.keyword(Keyword::In)?.expr()?.into() }, - body: self.block()?, - else_: self.parse_else()?, + Ok(match tok.data() { + Data::String(v) => Literal::from(v.as_str()), + Data::Character(v) => Literal::from(*v), + Data::Integer(v) => Literal::from(*v), + Data::Float(v) => todo!("Literal::Float({v})"), + _ => panic!("Expected token data for {tok:?}"), }) } - /// Parses an [else](Else) sub-expression - fn parse_else(&mut self) -> PResult> { - // it's fine for `else` to be missing entirely - self.keyword(Keyword::Else) - .ok() - .map(|p| Ok(Else { expr: p.expr()?.into() })) - .transpose() + /// [Tuple] = ([Expr] `,`)* [Expr]? + pub fn tuple(&mut self) -> PResult { + let mut exprs = vec![]; + while let Some(expr) = match self.expr() { + Ok(v) => Some(v), + Err(Error { reason: Nothing, .. }) => None, + Err(e) => return Err(e), + } { + exprs.push(expr); + match self.peek_type(WhileParsing::Tuple)? { + Type::Comma => self.consume_peeked(), + _ => break, + }; + } + Ok(Tuple { exprs }) } - /// Parses a [break](Break) expression - fn parse_break(&mut self) -> PResult { - Ok(Break { expr: self.keyword(Keyword::Break)?.expr()?.into() }) - } - /// Parses a [return](Return) expression - fn parse_return(&mut self) -> PResult { - Ok(Return { expr: self.keyword(Keyword::Return)?.expr()?.into() }) - } - /// Parses a [continue](Continue) expression - fn parse_continue(&mut self) -> PResult { - self.keyword(Keyword::Continue)?; - Ok(Continue) + /// [Block] = `{` [Stmt]* `}` + pub fn block(&mut self) -> PResult { + const PARSING: WhileParsing = WhileParsing::Block; + const START: Type = Type::LCurly; + const END: Type = Type::RCurly; + Ok(Block { + stmts: self.delimited( + START, + |this| this.repeated(Self::stmt, END, PARSING), + END, + PARSING, + )?, + }) + } +} +/// ## Control flow subexpressions +impl<'t> Parser<'t> { + /// [Break] = `break` [Expr]? + pub fn parse_break(&mut self) -> PResult { + self.match_kw(Keyword::Break, WhileParsing::Break)?; + Ok(Break { body: self.optional_expr()?.map(Into::into) }) + } + /// [Return] = `return` [Expr]? + pub fn parse_return(&mut self) -> PResult { + self.match_kw(Keyword::Return, WhileParsing::Return)?; + Ok(Return { body: self.optional_expr()?.map(Into::into) }) + } + /// [Continue] = `continue` + pub fn parse_continue(&mut self) -> PResult { + self.match_kw(Keyword::Continue, WhileParsing::Continue)?; + Ok(Continue) + } + /// [While] = `while` [Expr] [Block] [Else]? + pub fn parse_while(&mut self) -> PResult { + self.match_kw(Keyword::While, WhileParsing::While)?; + Ok(While { + cond: self.expr()?.into(), + pass: self.block()?.into(), + fail: self.parse_else()?, + }) + } + /// [If] = `if` [Expr] [Block] [Else]? + #[rustfmt::skip] // second line is barely not long enough + pub fn parse_if(&mut self) -> PResult { + self.match_kw(Keyword::If, WhileParsing::If)?; + Ok(If { + cond: self.expr()?.into(), + pass: self.block()?.into(), + fail: self.parse_else()?, + }) + } + /// [For]: `for` Pattern (TODO) `in` [Expr] [Block] [Else]? + pub fn parse_for(&mut self) -> PResult { + self.match_kw(Keyword::For, WhileParsing::For)?; + let bind = self.identifier()?; + self.match_kw(Keyword::In, WhileParsing::For)?; + Ok(For { + bind, + cond: self.expr()?.into(), + pass: self.block()?.into(), + fail: self.parse_else()?, + }) + } + /// [Else]: (`else` [Block])? + pub fn parse_else(&mut self) -> PResult { + match self.peek_type(WhileParsing::Else) { + Ok(Type::Keyword(Keyword::Else)) => { + self.consume_peeked(); + Ok(self.expr()?.into()) + } + Ok(_) | Err(Error { reason: EndOfInput, .. }) => Ok(None.into()), + Err(e) => Err(e), + } + } +} + +macro operator($($name:ident ($returns:ident) {$($t:ident => $p:ident),*$(,)?};)*) {$( + pub fn $name (&mut self) -> PResult<$returns> { + const PARSING: WhileParsing = WhileParsing::$returns; + let out = Ok(match self.peek_type(PARSING) { + $(Ok(Type::$t) => $returns::$p,)* + Err(e) => Err(e)?, + Ok(t) => Err(self.error(Unexpected(t), PARSING))?, + }); + self.consume_peeked(); + out + } +)*} + +/// ## Operator Kinds +impl<'t> Parser<'t> { + operator! { + assign_op (AssignKind) { + Eq => Plain, // = + AmpEq => And, // &= + BarEq => Or, // |= + XorEq => Xor, // ^= + LtLtEq => Shl, // <<= + GtGtEq => Shr, // >>= + PlusEq => Add, // += + MinusEq => Sub, // -= + StarEq => Mul, // *= + SlashEq => Div, // /= + RemEq => Rem, // %= + }; + compare_op (BinaryKind) { + Lt => Lt, // < + LtEq => LtEq, // <= + EqEq => Equal, // == + BangEq => NotEq,// != + GtEq => GtEq, // >= + Gt => Gt, // > + }; + range_op (BinaryKind) { + DotDot => RangeExc, // .. + DotDotEq => RangeInc,// ..= + }; + logic_op (BinaryKind) { + AmpAmp => LogAnd, // && + BarBar => LogOr, // || + XorXor => LogXor, // ^^ + }; + bitwise_op (BinaryKind) { + Amp => BitAnd, // & + Bar => BitOr, // | + Xor => BitXor, // ^ + }; + shift_op (BinaryKind) { + LtLt => Shl, // << + GtGt => Shr, // >> + }; + factor_op (BinaryKind) { + Plus => Add, // + + Minus => Sub, // - + }; + term_op (BinaryKind) { + Star => Mul, // * + Slash => Div, // / + Rem => Rem, // % + }; + unary_op (UnaryKind) { + Star => Deref, // * + Minus => Neg, // - + Bang => Not, // ! + At => At, // @ + Hash => Hash, // # + Tilde => Tilde, // ~ + }; + } + pub fn member_op(&mut self) -> PResult<()> { + const PARSING: WhileParsing = WhileParsing::Member; + match self.peek(PARSING)?.ty() { + Type::Dot => {} + t => Err(self.error(Unexpected(t), PARSING))?, + } + self.consume_peeked(); + Ok(()) } } diff --git a/libconlang/src/pretty_printer.rs b/libconlang/src/pretty_printer.rs deleted file mode 100644 index e977e55..0000000 --- a/libconlang/src/pretty_printer.rs +++ /dev/null @@ -1,460 +0,0 @@ -//! A [Printer] pretty-prints a Conlang [syntax tree](crate::ast) -#![deprecated] -#![allow(deprecated)] -use super::ast::preamble::*; -use std::{ - fmt::Display, - io::{stdout, Result as IOResult, StdoutLock, Write}, -}; -/// Prettily prints this node -pub trait PrettyPrintable { - /// Prettily prints this node - fn print(&self) { - let _ = self.visit(&mut Printer::default()); - } - /// Prettily writes this node into the given [Writer](Write) - fn write(&self, into: impl Write) -> IOResult<()> { - self.visit(&mut Printer::from(into)) - } - fn visit(&self, p: &mut Printer) -> IOResult<()>; -} - -/// Prints a Conlang [syntax tree](crate::ast) into a [Writer](Write) -#[derive(Debug)] -pub struct Printer { - level: u32, - writer: W, -} - -impl Write for Printer { - #[inline] - fn write(&mut self, buf: &[u8]) -> IOResult { - self.writer.write(buf) - } - #[inline] - fn flush(&mut self) -> IOResult<()> { - self.writer.flush() - } -} - -impl<'t> Default for Printer> { - fn default() -> Self { - Self { level: 0, writer: stdout().lock() } - } -} -impl From for Printer { - fn from(writer: W) -> Self { - Self { level: 0, writer } - } -} -impl Printer { - fn pad(&mut self) -> IOResult<&mut Self> { - for _ in 0..self.level * 4 { - write!(self.writer, " ")?; - } - Ok(self) - } - fn newline(&mut self) -> IOResult<&mut Self> { - writeln!(self.writer)?; - self.pad() - } - fn put(&mut self, d: impl Display) -> IOResult<&mut Self> { - write!(self.writer, "{d}")?; - Ok(self) - } - fn space(&mut self) -> IOResult<&mut Self> { - write!(self.writer, " ").map(|_| self) - } - /// Increase the indentation level by 1 - fn indent(&mut self) -> &mut Self { - self.level += 1; - self - } - fn dedent(&mut self) -> &mut Self { - self.level -= 1; - self - } -} -macro visit_operator($self:ident.$op:expr) { - $self.space()?.put($op)?.space().map(drop) -} - -impl PrettyPrintable for Start { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let Self(program) = self; - program.visit(p) - } -} -impl PrettyPrintable for Program { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let Self(module) = self; - for decl in module { - decl.visit(p)?; - p.newline()?; - } - Ok(()) - } -} -impl PrettyPrintable for Stmt { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - match self { - Stmt::Let(value) => value.visit(p), - Stmt::Fn(value) => value.visit(p), - Stmt::Expr(value) => { - value.visit(p)?; - p.put(';')?.newline().map(drop) - } - } - } -} -impl PrettyPrintable for Let { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let Let { name: Name { symbol: name, mutable, ty }, init } = self; - p.put("let")?.space()?; - if *mutable { - p.put("mut")?.space()?; - } - name.visit(p)?; - if let Some(ty) = ty { - ty.visit(p.put(':')?.space()?)? - } - if let Some(init) = init { - init.visit(p.space()?.put('=')?.space()?)?; - } - p.put(';').map(drop) - } -} -impl PrettyPrintable for FnDecl { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let FnDecl { name, args, body } = self; - p.put("fn")?.space()?; - name.visit(p)?; - p.space()?.put('(')?; - for (idx, arg) in args.iter().enumerate() { - if idx > 0 { - p.put(',')?.space()?; - } - arg.visit(p)?; - } - p.put(')')?.space()?; - body.visit(p) - } -} -impl PrettyPrintable for Name { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - if self.mutable { - p.put("mut")?.space()?; - } - self.symbol.visit(p)?; - if let Some(ty) = &self.ty { - ty.visit(p.put(':')?.space()?)?; - } - Ok(()) - } -} -impl PrettyPrintable for TypeExpr { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - match self { - TypeExpr::TupleType(_tt) => todo!(), - TypeExpr::TypePath(t) => t.visit(p), - TypeExpr::Empty(_) => p.put("()").map(drop), - TypeExpr::Never(_) => p.put('!').map(drop), - } - } -} -impl PrettyPrintable for Path { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let Path { absolute, parts } = self; - if *absolute { - p.put("::")?; - } - for (idx, part) in parts.iter().enumerate() { - if idx != 0 { - p.put("::")?; - } - part.visit(p)?; - } - Ok(()) - } -} -impl PrettyPrintable for PathPart { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - match self { - PathPart::PathSuper => p.put("super").map(drop), - PathPart::PathSelf => p.put("self").map(drop), - PathPart::PathIdent(id) => id.visit(p), - } - } -} -impl PrettyPrintable for Block { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let Block { let_count: _, statements, expr } = self; - p.put('{')?.indent().newline()?; - for stmt in statements { - stmt.visit(p)?; - } - for expr in expr { - expr.visit(p)?; - } - p.dedent().newline()?.put('}').map(drop) - } -} -impl PrettyPrintable for Expr { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let Expr(expr) = self; - expr.visit(p) - } -} - -impl PrettyPrintable for Operation { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - match self { - Operation::Assign(value) => value.visit(p), - Operation::Binary(value) => value.visit(p), - Operation::Unary(value) => value.visit(p), - Operation::Call(value) => value.visit(p), - } - } -} -impl PrettyPrintable for Assign { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let Assign { target, operator, init } = self; - target.visit(p)?; - operator.visit(p)?; - init.visit(p) - } -} -impl PrettyPrintable for operator::Assign { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - use operator::Assign; - visit_operator!(p.match self { - Assign::Assign => "=", - Assign::AddAssign => "+=", - Assign::SubAssign => "-=", - Assign::MulAssign => "*=", - Assign::DivAssign => "/=", - Assign::RemAssign => "%=", - Assign::BitAndAssign => "&=", - Assign::BitOrAssign => "|=", - Assign::BitXorAssign => "^=", - Assign::ShlAssign => "<<=", - Assign::ShrAssign => ">>=", - }) - } -} -impl PrettyPrintable for Binary { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let Binary { first, other } = self; - p.put('(')?; - first.visit(p)?; - for (op, other) in other { - op.visit(p)?; - other.visit(p)? - } - p.put(')').map(drop) - } -} -impl PrettyPrintable for operator::Binary { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - use operator::Binary; - visit_operator!(p.match self { - Binary::Mul => "*", - Binary::Div => "/", - Binary::Rem => "%", - Binary::Add => "+", - Binary::Sub => "-", - Binary::Lsh => "<<", - Binary::Rsh => ">>", - Binary::BitAnd => "&", - Binary::BitOr => "|", - Binary::BitXor => "^", - Binary::LogAnd => "&&", - Binary::LogOr => "||", - Binary::LogXor => "^^", - Binary::RangeExc => "..", - Binary::RangeInc => "..=", - Binary::Less => "<", - Binary::LessEq => "<=", - Binary::Equal => "==", - Binary::NotEq => "!=", - Binary::GreaterEq => ">=", - Binary::Greater => ">", - }) - } -} -impl PrettyPrintable for Unary { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let Unary { operators, operand } = self; - for op in operators { - op.visit(p)?; - } - operand.visit(p) - } -} -impl PrettyPrintable for operator::Unary { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - use operator::Unary; - p.put(match self { - Unary::RefRef => "&&", - Unary::Deref => "*", - Unary::Ref => "&", - Unary::Neg => "-", - Unary::Not => "!", - Unary::At => "@", - Unary::Hash => "#", - Unary::Tilde => "~", - }) - .map(drop) - } -} - -impl PrettyPrintable for Call { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - match self { - Call::FnCall(value) => value.visit(p), - Call::Primary(value) => value.visit(p), - } - } -} -impl PrettyPrintable for FnCall { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let FnCall { callee, args } = self; - callee.visit(p)?; - for arg_list in args { - p.put('(')?; - arg_list.visit(p)?; - p.put(')')?; - } - Ok(()) - } -} -impl PrettyPrintable for Primary { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - match self { - Primary::Identifier(value) => value.visit(p), - Primary::Literal(value) => value.visit(p), - Primary::Block(value) => value.visit(p), - Primary::Group(value) => value.visit(p), - Primary::Branch(value) => value.visit(p), - } - } -} -impl PrettyPrintable for Group { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - p.put('(')?; - match self { - Group::Tuple(tuple) => tuple.visit(p.space()?)?, - Group::Single(expr) => expr.visit(p.space()?)?, - Group::Empty => (), - }; - p.space()?.put(')').map(drop) - } -} -impl PrettyPrintable for Tuple { - /// Writes a *non-delimited* [Tuple] to the [Printer] - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let Tuple { elements } = self; - for (idx, expr) in elements.iter().enumerate() { - if idx > 0 { - p.put(',')?.space()?; - } - expr.visit(p)?; - } - Ok(()) - } -} - -impl PrettyPrintable for Identifier { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let Identifier { name, index: _ } = self; // TODO: Pretty-print variable number as well - p.put(name).map(drop) - } -} -impl PrettyPrintable for Literal { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - match self { - Literal::String(value) => write!(p, "\"{value}\""), - Literal::Char(value) => write!(p, "'{value}'"), - Literal::Bool(value) => write!(p, "{value}"), - Literal::Float(value) => value.visit(p), - Literal::Int(value) => write!(p, "{value}"), - } - } -} -impl PrettyPrintable for Float { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let Float { sign, exponent, mantissa } = self; - p.put(sign)?.put(exponent)?.put(mantissa).map(drop) - } -} - -impl PrettyPrintable for Flow { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - match self { - Flow::While(value) => value.visit(p), - Flow::If(value) => value.visit(p), - Flow::For(value) => value.visit(p), - Flow::Continue(value) => value.visit(p), - Flow::Return(value) => value.visit(p), - Flow::Break(value) => value.visit(p), - } - } -} -impl PrettyPrintable for While { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let While { cond, body, else_ } = self; - cond.visit(p.put("while")?.space()?)?; - body.visit(p.space()?)?; - match else_ { - Some(e) => e.visit(p), - None => Ok(()), - } - } -} -impl PrettyPrintable for If { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let If { cond, body, else_ } = self; - cond.visit(p.put("if")?.space()?)?; - body.visit(p.space()?)?; - match else_ { - Some(e) => e.visit(p), - None => Ok(()), - } - } -} -impl PrettyPrintable for For { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let For { var, iter, body, else_ } = self; - var.visit(p.put("for")?.space()?)?; - iter.visit(p.space()?.put("in")?.space()?)?; - body.visit(p.space()?)?; - match else_ { - Some(e) => e.visit(p), - None => Ok(()), - } - } -} -impl PrettyPrintable for Else { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let Else { expr } = self; - expr.visit(p.space()?.put("else")?.space()?) - } -} -impl PrettyPrintable for Continue { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let control::Continue = self; // using pattern destructuring, rather than assigning to "Continue" - p.put("continue").map(drop) - } -} -impl PrettyPrintable for Break { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let Break { expr } = self; - expr.visit(p.put("break")?.space()?) - } -} -impl PrettyPrintable for Return { - fn visit(&self, p: &mut Printer) -> IOResult<()> { - let Return { expr } = self; - expr.visit(p.put("return")?.space()?) - } -} diff --git a/libconlang/src/resolver.rs b/libconlang/src/resolver.rs index 2e09ef8..4d5e5f9 100644 --- a/libconlang/src/resolver.rs +++ b/libconlang/src/resolver.rs @@ -456,6 +456,7 @@ impl Resolver { self.get_mut(name)?.assign(name, ty) } } +#[allow(unused_macros)] /// Manages a module scope /// ```rust,ignore /// macro module(self, name: &str, inner: {...}) -> Result<_, Error> @@ -487,372 +488,375 @@ pub trait Resolve { } } mod ast1 { - #![allow(deprecated)] - use super::*; - use crate::ast::preamble::*; - impl Resolve for Start { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - let Self(program) = self; - program.resolve(resolver) - } - } - impl Resolve for Program { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - let Self(module) = self; - for decl in module { - decl.resolve(resolver)?; - } - // TODO: record the number of module-level assignments into the AST - Ok(Type::Empty) - } - } - impl Resolve for Stmt { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - match self { - Stmt::Let(value) => value.resolve(resolver), - Stmt::Fn(value) => value.resolve(resolver), - Stmt::Expr(value) => value.resolve(resolver), - } - } - } - impl Resolve for Let { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - let Let { name: Name { symbol: Identifier { name, index }, mutable, ty: _ }, init } = - self; - debugln!("ty> let {name} ..."); - if let Some(init) = init { - let ty = init.resolve(resolver)?; - *index = Some(resolver.insert_scope(name, *mutable)?); - resolver.get_mut(name)?.assign(name, &ty)?; - } else { - resolver.insert_scope(name, *mutable)?; - } - Ok(Type::Empty) - } - } - impl Resolve for FnDecl { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - let FnDecl { name: Name { symbol: Identifier { name, index }, .. }, args, body } = self; - debugln!("ty> fn {name} ..."); - // register the name at module scope - *index = Some(resolver.insert_module(name, false)?); - // create a new lexical scope - let scopes = std::mem::take(&mut resolver.scopes); - // type-check the function body - let out = { - let mut resolver = resolver.frame(); - let mut evaluated_args = vec![]; - for arg in args { - evaluated_args.push(arg.resolve(&mut resolver)?) - } - let fn_decl = Type::Fn { args: evaluated_args.clone(), ret: Box::new(Type::Empty) }; - resolver.get_mut(name)?.assign(name, &fn_decl)?; - module!(resolver, name, { body.resolve(&mut resolver) }) - }; - let _ = std::mem::replace(&mut resolver.scopes, scopes); - out - } - } - impl Resolve for Name { - fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult { - Ok(Type::Empty) - } - } - impl Resolve for Block { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - let Block { let_count: _, statements, expr } = self; - let mut resolver = resolver.frame(); - for stmt in statements { - stmt.resolve(&mut resolver)?; - } - expr.resolve(&mut resolver) - } - } - impl Resolve for Expr { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - let Expr(expr) = self; - expr.resolve(resolver) - } - } + // #![allow(deprecated)] + // use super::*; + // use crate::ast::preamble::*; + // impl Resolve for Start { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // let Self(program) = self; + // program.resolve(resolver) + // } + // } + // impl Resolve for Program { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // let Self(module) = self; + // for decl in module { + // decl.resolve(resolver)?; + // } + // // TODO: record the number of module-level assignments into the AST + // Ok(Type::Empty) + // } + // } + // impl Resolve for Stmt { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // match self { + // Stmt::Let(value) => value.resolve(resolver), + // Stmt::Fn(value) => value.resolve(resolver), + // Stmt::Expr(value) => value.resolve(resolver), + // } + // } + // } + // impl Resolve for Let { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // let Let { name: Name { symbol: Identifier { name, index }, mutable, ty: _ }, init } = + // self; + // debugln!("ty> let {name} ..."); + // if let Some(init) = init { + // let ty = init.resolve(resolver)?; + // *index = Some(resolver.insert_scope(name, *mutable)?); + // resolver.get_mut(name)?.assign(name, &ty)?; + // } else { + // resolver.insert_scope(name, *mutable)?; + // } + // Ok(Type::Empty) + // } + // } + // impl Resolve for FnDecl { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // let FnDecl { name: Name { symbol: Identifier { name, index }, .. }, args, body } = + // self; debugln!("ty> fn {name} ..."); + // // register the name at module scope + // *index = Some(resolver.insert_module(name, false)?); + // // create a new lexical scope + // let scopes = std::mem::take(&mut resolver.scopes); + // // type-check the function body + // let out = { + // let mut resolver = resolver.frame(); + // let mut evaluated_args = vec![]; + // for arg in args { + // evaluated_args.push(arg.resolve(&mut resolver)?) + // } + // let fn_decl = Type::Fn { args: evaluated_args.clone(), ret: Box::new(Type::Empty) + // }; resolver.get_mut(name)?.assign(name, &fn_decl)?; + // module!(resolver, name, { body.resolve(&mut resolver) }) + // }; + // let _ = std::mem::replace(&mut resolver.scopes, scopes); + // out + // } + // } + // impl Resolve for Name { + // fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult { + // Ok(Type::Empty) + // } + // } + // impl Resolve for Block { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // let Block { let_count: _, statements, expr } = self; + // let mut resolver = resolver.frame(); + // for stmt in statements { + // stmt.resolve(&mut resolver)?; + // } + // expr.resolve(&mut resolver) + // } + // } + // impl Resolve for Expr { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // let Expr(expr) = self; + // expr.resolve(resolver) + // } + // } - impl Resolve for Operation { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - match self { - Operation::Assign(value) => value.resolve(resolver), - Operation::Binary(value) => value.resolve(resolver), - Operation::Unary(value) => value.resolve(resolver), - Operation::Call(value) => value.resolve(resolver), - } - } - } - impl Resolve for Assign { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - let Assign { target, operator, init } = self; - // Evaluate the initializer expression - let ty = init.resolve(resolver)?; - // Resolve the variable - match (operator, resolver.get_mut(&target.name)?) { - ( - operator::Assign::Assign, - Variable { status: Status::Initialized(_), mutable: false, index }, - ) => Err(Error::ImmutableAssign(target.name.clone(), *index)), - // TODO: make typing more expressive for modifying assignment - (_, variable) => variable - .modify_assign(&target.name, &ty) - .map(|_| Type::Empty), - } - } - } + // impl Resolve for Operation { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // match self { + // Operation::Assign(value) => value.resolve(resolver), + // Operation::Binary(value) => value.resolve(resolver), + // Operation::Unary(value) => value.resolve(resolver), + // Operation::Call(value) => value.resolve(resolver), + // } + // } + // } + // impl Resolve for Assign { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // let Assign { target, operator, init } = self; + // // Evaluate the initializer expression + // let ty = init.resolve(resolver)?; + // // Resolve the variable + // match (operator, resolver.get_mut(&target.name)?) { + // ( + // operator::Assign::Assign, + // Variable { status: Status::Initialized(_), mutable: false, index }, + // ) => Err(Error::ImmutableAssign(target.name.clone(), *index)), + // // TODO: make typing more expressive for modifying assignment + // (_, variable) => variable + // .modify_assign(&target.name, &ty) + // .map(|_| Type::Empty), + // } + // } + // } - impl Resolve for Binary { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - let Binary { first, other } = self; + // impl Resolve for Binary { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // let Binary { first, other } = self; - let mut first = first.resolve(resolver)?; - for (op, other) in other { - let other = other.resolve(resolver)?; - first = resolver.resolve_binary_operator(first, other, op)?; - } - Ok(first) - } - } - impl Resolve for Unary { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - let Unary { operators, operand } = self; - let mut operand = operand.resolve(resolver)?; - for op in operators { - operand = resolver.resolve_unary_operator(operand, op)?; - } - Ok(operand) - } - } - /// Resolve [operator]s - impl Resolver { - fn resolve_binary_operator( - &mut self, - first: Type, - other: Type, - op: &operator::Binary, - ) -> TyResult { - // TODO: check type compatibility for binary ops - // TODO: desugar binary ops into function calls, when member functions are a thing - eprintln!("Resolve binary operators {first} {op:?} {other}"); - if first != other { - Err(Error::TypeMismatch { want: first, got: other }) - } else { - Ok(first) - } - } - fn resolve_unary_operator( - &mut self, - operand: Type, - op: &operator::Unary, - ) -> TyResult { - // TODO: Allow more expressive unary operator type conversions - todo!("Resolve unary operators {op:?} {operand}") - } - } - impl Resolve for Call { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - match self { - Call::FnCall(value) => value.resolve(resolver), - Call::Primary(value) => value.resolve(resolver), - } - } - } - impl Resolve for FnCall { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - let FnCall { callee, args } = self; - let mut callee = callee.resolve(resolver)?; - for argset in args { - // arguments should always be a tuple here - let arguments = argset.resolve(resolver)?; - let Type::Tuple(arguments) = arguments else { - Err(Error::TypeMismatch { - want: Type::Tuple(vec![Type::ManyInferred]), - got: arguments, - })? - }; - // Verify that the callee is a function, and the arguments match. - // We need the arguments - let Type::Fn { args, ret } = callee else { - return Err(Error::TypeMismatch { - want: Type::Fn { args: arguments, ret: Type::Inferred.into() }, - got: callee, - })?; - }; - for (want, got) in args.iter().zip(&arguments) { - // TODO: verify generics - if let Type::Generic(_) = want { - continue; - } - if want != got { - return Err(Error::TypeMismatch { - want: Type::Fn { args: arguments, ret: Type::Inferred.into() }, - got: Type::Fn { args, ret }, - })?; - } - } - callee = *ret; - } - Ok(callee) - } - } - impl Resolve for Primary { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - match self { - Primary::Identifier(value) => value.resolve(resolver), - Primary::Literal(value) => value.resolve(resolver), - Primary::Block(value) => value.resolve(resolver), - Primary::Group(value) => value.resolve(resolver), - Primary::Branch(value) => value.resolve(resolver), - } - } - } + // let mut first = first.resolve(resolver)?; + // for (op, other) in other { + // let other = other.resolve(resolver)?; + // first = resolver.resolve_binary_operator(first, other, op)?; + // } + // Ok(first) + // } + // } + // impl Resolve for Unary { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // let Unary { operators, operand } = self; + // let mut operand = operand.resolve(resolver)?; + // for op in operators { + // operand = resolver.resolve_unary_operator(operand, op)?; + // } + // Ok(operand) + // } + // } + // /// Resolve [operator]s + // impl Resolver { + // fn resolve_binary_operator( + // &mut self, + // first: Type, + // other: Type, + // op: &operator::Binary, + // ) -> TyResult { + // // TODO: check type compatibility for binary ops + // // TODO: desugar binary ops into function calls, when member functions are a thing + // eprintln!("Resolve binary operators {first} {op:?} {other}"); + // if first != other { + // Err(Error::TypeMismatch { want: first, got: other }) + // } else { + // Ok(first) + // } + // } + // fn resolve_unary_operator( + // &mut self, + // operand: Type, + // op: &operator::Unary, + // ) -> TyResult { + // // TODO: Allow more expressive unary operator type conversions + // todo!("Resolve unary operators {op:?} {operand}") + // } + // } + // impl Resolve for Call { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // match self { + // Call::FnCall(value) => value.resolve(resolver), + // Call::Primary(value) => value.resolve(resolver), + // } + // } + // } + // impl Resolve for FnCall { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // let FnCall { callee, args } = self; + // let mut callee = callee.resolve(resolver)?; + // for argset in args { + // // arguments should always be a tuple here + // let arguments = argset.resolve(resolver)?; + // let Type::Tuple(arguments) = arguments else { + // Err(Error::TypeMismatch { + // want: Type::Tuple(vec![Type::ManyInferred]), + // got: arguments, + // })? + // }; + // // Verify that the callee is a function, and the arguments match. + // // We need the arguments + // let Type::Fn { args, ret } = callee else { + // return Err(Error::TypeMismatch { + // want: Type::Fn { args: arguments, ret: Type::Inferred.into() }, + // got: callee, + // })?; + // }; + // for (want, got) in args.iter().zip(&arguments) { + // // TODO: verify generics + // if let Type::Generic(_) = want { + // continue; + // } + // if want != got { + // return Err(Error::TypeMismatch { + // want: Type::Fn { args: arguments, ret: Type::Inferred.into() }, + // got: Type::Fn { args, ret }, + // })?; + // } + // } + // callee = *ret; + // } + // Ok(callee) + // } + // } + // impl Resolve for Primary { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // match self { + // Primary::Identifier(value) => value.resolve(resolver), + // Primary::Literal(value) => value.resolve(resolver), + // Primary::Block(value) => value.resolve(resolver), + // Primary::Group(value) => value.resolve(resolver), + // Primary::Branch(value) => value.resolve(resolver), + // } + // } + // } - impl Resolve for Group { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - match self { - Group::Tuple(tuple) => tuple.resolve(resolver), - Group::Single(expr) => expr.resolve(resolver), - Group::Empty => Ok(Type::Empty), - } - } - } + // impl Resolve for Group { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // match self { + // Group::Tuple(tuple) => tuple.resolve(resolver), + // Group::Single(expr) => expr.resolve(resolver), + // Group::Empty => Ok(Type::Empty), + // } + // } + // } - impl Resolve for Tuple { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - let Tuple { elements } = self; - let mut types = vec![]; - for expr in elements.iter_mut() { - types.push(expr.resolve(resolver)?); - } - Ok(Type::Tuple(types)) - } - } + // impl Resolve for Tuple { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // let Tuple { elements } = self; + // let mut types = vec![]; + // for expr in elements.iter_mut() { + // types.push(expr.resolve(resolver)?); + // } + // Ok(Type::Tuple(types)) + // } + // } - impl Resolve for Identifier { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - let Identifier { name, index: id_index } = self; - let Variable { index, status, .. } = resolver.get(name)?; - *id_index = Some(*index); - let ty = match status { - Status::Initialized(t) => t, - _ => Err(Error::Uninitialized(name.to_owned(), *index))?, - }; - debugln!("ty> Resolved {} #{index}: {ty}", name); - Ok(ty.to_owned()) - } - } - impl Resolve for Literal { - fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult { - Ok(match self { - Literal::String(_) => Type::String, - Literal::Char(_) => Type::Char, - Literal::Bool(_) => Type::Bool, - Literal::Float(_) => Type::Float, - Literal::Int(_) => Type::Int, - }) - } - } + // impl Resolve for Identifier { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // let Identifier { name, index: id_index } = self; + // let Variable { index, status, .. } = resolver.get(name)?; + // *id_index = Some(*index); + // let ty = match status { + // Status::Initialized(t) => t, + // _ => Err(Error::Uninitialized(name.to_owned(), *index))?, + // }; + // debugln!("ty> Resolved {} #{index}: {ty}", name); + // Ok(ty.to_owned()) + // } + // } + // impl Resolve for Literal { + // fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult { + // Ok(match self { + // Literal::String(_) => Type::String, + // Literal::Char(_) => Type::Char, + // Literal::Bool(_) => Type::Bool, + // Literal::Float(_) => Type::Float, + // Literal::Int(_) => Type::Int, + // }) + // } + // } - impl Resolve for Flow { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - // TODO: Finish this - match self { - Flow::While(value) => value.resolve(resolver), - Flow::If(value) => value.resolve(resolver), - Flow::For(value) => value.resolve(resolver), - Flow::Continue(value) => value.resolve(resolver), - Flow::Return(value) => value.resolve(resolver), - Flow::Break(value) => value.resolve(resolver), - } - } - } - impl Resolve for While { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - // TODO: Finish this - // Visit else first, save that to a break-pattern stack in the Resolver, - // and check it inside Break::resolve() - let While { cond, body, else_ } = self; - cond.resolve(resolver)?; // must be Type::Bool - body.resolve(resolver)?; // discard - else_.resolve(resolver) // compare with returns inside body - } - } - impl Resolve for If { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - let If { cond, body, else_ } = self; - let cond = cond.resolve(resolver)?; - if Type::Bool != cond { - return Err(Error::TypeMismatch { want: Type::Bool, got: cond }); - } - let body_ty = body.resolve(resolver)?; - let else_ty = else_.resolve(resolver)?; - if body_ty == else_ty { - Ok(body_ty) - } else { - Err(Error::TypeMismatch { want: body_ty, got: else_ty }) - } - } - } + // impl Resolve for Flow { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // // TODO: Finish this + // match self { + // Flow::While(value) => value.resolve(resolver), + // Flow::If(value) => value.resolve(resolver), + // Flow::For(value) => value.resolve(resolver), + // Flow::Continue(value) => value.resolve(resolver), + // Flow::Return(value) => value.resolve(resolver), + // Flow::Break(value) => value.resolve(resolver), + // } + // } + // } + // impl Resolve for While { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // // TODO: Finish this + // // Visit else first, save that to a break-pattern stack in the Resolver, + // // and check it inside Break::resolve() + // let While { cond, body, else_ } = self; + // cond.resolve(resolver)?; // must be Type::Bool + // body.resolve(resolver)?; // discard + // else_.resolve(resolver) // compare with returns inside body + // } + // } + // impl Resolve for If { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // let If { cond, body, else_ } = self; + // let cond = cond.resolve(resolver)?; + // if Type::Bool != cond { + // return Err(Error::TypeMismatch { want: Type::Bool, got: cond }); + // } + // let body_ty = body.resolve(resolver)?; + // let else_ty = else_.resolve(resolver)?; + // if body_ty == else_ty { + // Ok(body_ty) + // } else { + // Err(Error::TypeMismatch { want: body_ty, got: else_ty }) + // } + // } + // } - impl Resolve for For { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - let For { var: Identifier { name, index }, iter, body, else_ } = self; - debugln!("> for {name} in ..."); - // Visit the iter expression and get its type - let range = iter.resolve(resolver)?; - let ty = match range { - Type::Range(t) => t, - got => Err(Error::TypeMismatch { want: Type::Range(Type::Inferred.into()), got })?, - }; - let body_ty = { - let mut resolver = resolver.frame(); - // bind the variable in the loop scope - *index = Some(resolver.insert_scope(name, false)?); - resolver.get_mut(name)?.assign(name, &ty)?; - body.resolve(&mut resolver) - }?; - // visit the else block - let else_ty = else_.resolve(resolver)?; - if body_ty != else_ty { - Err(Error::TypeMismatch { want: body_ty, got: else_ty }) - } else { - Ok(body_ty) - } - } - } - impl Resolve for Else { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - let Else { expr } = self; - expr.resolve(resolver) - } - } + // impl Resolve for For { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // let For { var: Identifier { name, index }, iter, body, else_ } = self; + // debugln!("> for {name} in ..."); + // // Visit the iter expression and get its type + // let range = iter.resolve(resolver)?; + // let ty = match range { + // Type::Range(t) => t, + // got => Err(Error::TypeMismatch { want: Type::Range(Type::Inferred.into()), got + // })?, }; + // let body_ty = { + // let mut resolver = resolver.frame(); + // // bind the variable in the loop scope + // *index = Some(resolver.insert_scope(name, false)?); + // resolver.get_mut(name)?.assign(name, &ty)?; + // body.resolve(&mut resolver) + // }?; + // // visit the else block + // let else_ty = else_.resolve(resolver)?; + // if body_ty != else_ty { + // Err(Error::TypeMismatch { want: body_ty, got: else_ty }) + // } else { + // Ok(body_ty) + // } + // } + // } + // impl Resolve for Else { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // let Else { expr } = self; + // expr.resolve(resolver) + // } + // } - impl Resolve for Continue { - fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult { - // TODO: Finish control flow - Ok(Type::Never) - } - } - impl Resolve for Break { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - // TODO: Finish control flow - let Break { expr } = self; - expr.resolve(resolver) - } - } - impl Resolve for Return { - fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { - // TODO: Finish control flow - let Return { expr } = self; - expr.resolve(resolver) - } - } + // impl Resolve for Continue { + // fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult { + // // TODO: Finish control flow + // Ok(Type::Never) + // } + // } + // impl Resolve for Break { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // // TODO: Finish control flow + // let Break { expr } = self; + // expr.resolve(resolver) + // } + // } + // impl Resolve for Return { + // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult { + // // TODO: Finish control flow + // let Return { expr } = self; + // expr.resolve(resolver) + // } + // } } -mod ast2 {} +mod ast { + #![allow(unused_imports)] + use crate::ast::*; +} // heakc yea man, generics impl Resolve for Option { diff --git a/libconlang/src/token/token_type.rs b/libconlang/src/token/token_type.rs index dec1b3f..150ada3 100644 --- a/libconlang/src/token/token_type.rs +++ b/libconlang/src/token/token_type.rs @@ -78,6 +78,7 @@ pub enum Type { pub enum Keyword { Break, Cl, + Const, Continue, Else, Enum, @@ -85,13 +86,16 @@ pub enum Keyword { For, Fn, If, + Impl, In, Let, Mod, Mut, + Pub, Return, SelfKw, SelfTy, + Static, Struct, Super, True, @@ -172,6 +176,7 @@ impl Display for Keyword { match self { Self::Break => "break".fmt(f), Self::Cl => "cl".fmt(f), + Self::Const => "const".fmt(f), Self::Continue => "continue".fmt(f), Self::Else => "else".fmt(f), Self::Enum => "enum".fmt(f), @@ -179,13 +184,16 @@ impl Display for Keyword { Self::For => "for".fmt(f), Self::Fn => "fn".fmt(f), Self::If => "if".fmt(f), + Self::Impl => "impl".fmt(f), Self::In => "in".fmt(f), Self::Let => "let".fmt(f), Self::Mod => "mod".fmt(f), Self::Mut => "mut".fmt(f), + Self::Pub => "pub".fmt(f), Self::Return => "return".fmt(f), Self::SelfKw => "self".fmt(f), Self::SelfTy => "Self".fmt(f), + Self::Static => "static".fmt(f), Self::Struct => "struct".fmt(f), Self::Super => "super".fmt(f), Self::True => "true".fmt(f), @@ -200,6 +208,7 @@ impl FromStr for Keyword { Ok(match s { "break" => Self::Break, "cl" => Self::Cl, + "const" => Self::Const, "continue" => Self::Continue, "else" => Self::Else, "enum" => Self::Enum, @@ -207,13 +216,16 @@ impl FromStr for Keyword { "for" => Self::For, "fn" => Self::Fn, "if" => Self::If, + "impl" => Self::Impl, "in" => Self::In, "let" => Self::Let, "mod" => Self::Mod, "mut" => Self::Mut, + "pub" => Self::Pub, "return" => Self::Return, "self" => Self::SelfKw, "Self" => Self::SelfTy, + "static" => Self::Static, "struct" => Self::Struct, "super" => Self::Super, "true" => Self::True,