From c2c0dacb6758d7f1ab78c28412bfde9bbbc2ef5d Mon Sep 17 00:00:00 2001 From: mat ess Date: Sun, 30 Apr 2023 23:05:39 -0400 Subject: [PATCH] Blocks and statements --- docs/ROADMAP.md | 3 +++ example.mul | 12 +++++++----- src/main.rs | 23 +++++++++++++++++------ src/parser.lalrpop | 22 +++++++++++++++++----- src/syntax.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 16 deletions(-) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 528d89f..33d2b08 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -1,6 +1,8 @@ # implementation roadmap - [ ] parser + - [ ] uniform function call syntax + - [ ] lossless syntax trees (rowan + ungrammar) - [ ] typechecker - [ ] interpreter - [ ] code generator @@ -11,4 +13,5 @@ - [ ] product types - [ ] sum types - [ ] variant types +- [ ] pattern matching - [ ] trait / interface system diff --git a/example.mul b/example.mul index eb6b777..f641e45 100644 --- a/example.mul +++ b/example.mul @@ -1,7 +1,9 @@ -main = () { - print(sum_equals(1, 2, 3) == true) +main = () -> { + result = sum_equals(1, 2, 3); + print(result) } -sum_equals = (x, y, sum) { - equals(add(x, y), sum) -} \ No newline at end of file +sum_equals = (x, y, expected) -> { + sum = add(x, y); + equals(sum, expected) +} diff --git a/src/main.rs b/src/main.rs index 456d649..ff787e8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,22 @@ use std::io::{stdin, stdout, BufRead, Write}; -use mul::parser::ExpressionParser; +use mul::parser::{ExpressionParser, StatementParser}; + +macro_rules! parse { + ($parser:expr, $line:expr) => { + match $parser.parse($line.as_str()) { + Ok(parsed) => println!("{parsed:?}"), + Err(lalrpop_util::ParseError::UnrecognizedEOF { .. }) => break, + Err(e) => println!("Parse error: {e}"), + } + }; +} fn main() { let mut stdin = stdin().lock(); let mut stdout = stdout().lock(); - let parser = ExpressionParser::new(); + let expression = ExpressionParser::new(); + let statement = StatementParser::new(); loop { let mut line = String::new(); print!("> "); @@ -13,10 +24,10 @@ fn main() { stdin .read_line(&mut line) .expect("Failed to read from stdin"); - match parser.parse(line.as_str()) { - Ok(parsed) => println!("{parsed:?}"), - Err(lalrpop_util::ParseError::UnrecognizedEOF { .. }) => break, - Err(e) => println!("Parse error: {e}"), + if line.trim_end().ends_with(';') { + parse!(statement, line) + } else { + parse!(expression, line) } } } diff --git a/src/parser.lalrpop b/src/parser.lalrpop index f23a912..9ad7573 100644 --- a/src/parser.lalrpop +++ b/src/parser.lalrpop @@ -1,19 +1,31 @@ -use crate::syntax::{Expression, Name}; +use crate::syntax::{Expression, Name, Statement}; grammar; +pub Statement: Statement = { + "=" ";" => Statement::Binding(name, body), + ";" => Statement::Expression(body), +}; + pub Expression: Expression = { - "(" > ")" "{" "}" => Expression::Lambda(params, Box::new(body)), - "(" > ")" => Expression::Call(Box::new(callee), args), + "(" > ")" "->" => Expression::Lambda(params, Box::new(body)), + Atom => <>, +}; + +Atom: Expression = { Name => Expression::Variable(<>), + "{" "}" => Expression::Block(statements, Box::new(result)), + "(" > ")" => Expression::Call(Box::new(callee), args), Integer => Expression::Integer(<>), Boolean => Expression::Boolean(<>), }; // TODO: decide on identifier syntax -Name: Name = r"[a-zA-Z_]+" => <>.to_string(); +Name: Name = + r"[a-zA-Z_]+" => <>.to_string(); -Integer: i64 = r"[0-9]+" => <>.parse::().unwrap(); +Integer: i64 = + r"[0-9]+" => <>.parse::().unwrap(); Boolean: bool = { "true" => true, diff --git a/src/syntax.rs b/src/syntax.rs index 0bd6187..53c8ee5 100644 --- a/src/syntax.rs +++ b/src/syntax.rs @@ -1,10 +1,57 @@ +use std::fmt::Display; + pub type Name = String; +#[derive(Debug)] +pub enum Statement { + Binding(Name, Expression), + Expression(Expression), +} + +impl Display for Statement { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Statement::Binding(name, body) => write!(f, "{name} = {body};"), + Statement::Expression(body) => write!(f, "{body};"), + } + } +} + #[derive(Debug)] pub enum Expression { Variable(Name), + Block(Vec, Box), Lambda(Vec, Box), Call(Box, Vec), Boolean(bool), Integer(i64), } + +impl Display for Expression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Expression::Variable(name) => write!(f, "{name}"), + Expression::Block(statements, result) => { + writeln!(f, "{{")?; + for statement in statements { + writeln!(f, "\t{statement}")?; + } + writeln!(f, "\t{result}")?; + writeln!(f, "}}") + } + Expression::Lambda(params, body) => write!(f, "({}) -> {body}", params.join(", ")), + Expression::Call(callee, args) => { + write!(f, "{callee}(")?; + if let Some(arg) = args.first() { + write!(f, "{arg}")?; + } + for arg in args.iter().skip(1) { + write!(f, ", {arg}")?; + } + write!(f, ")") + } + Expression::Boolean(v) => write!(f, "{v}"), + Expression::Integer(v) => write!(f, "{v}"), + } + } +}