Blocks and statements

main
mat ess 2023-04-30 23:05:39 -04:00
parent ea33ae23bc
commit c2c0dacb67
5 changed files with 91 additions and 16 deletions

View File

@ -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

View File

@ -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)
}
sum_equals = (x, y, expected) -> {
sum = add(x, y);
equals(sum, expected)
}

View File

@ -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)
}
}
}

View File

@ -1,19 +1,31 @@
use crate::syntax::{Expression, Name};
use crate::syntax::{Expression, Name, Statement};
grammar;
pub Statement: Statement = {
<name:Name> "=" <body:Expression> ";" => Statement::Binding(name, body),
<body:Expression> ";" => Statement::Expression(body),
};
pub Expression: Expression = {
"(" <params:Comma<Name>> ")" "{" <body:Expression> "}" => Expression::Lambda(params, Box::new(body)),
<callee:Expression> "(" <args:Comma<Expression>> ")" => Expression::Call(Box::new(callee), args),
"(" <params:Comma<Name>> ")" "->" <body:Expression> => Expression::Lambda(params, Box::new(body)),
Atom => <>,
};
Atom: Expression = {
Name => Expression::Variable(<>),
"{" <statements:Statement*> <result:Expression> "}" => Expression::Block(statements, Box::new(result)),
<callee:Atom> "(" <args:Comma<Expression>> ")" => 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::<i64>().unwrap();
Integer: i64 =
r"[0-9]+" => <>.parse::<i64>().unwrap();
Boolean: bool = {
"true" => true,

View File

@ -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<Statement>, Box<Expression>),
Lambda(Vec<Name>, Box<Expression>),
Call(Box<Expression>, Vec<Expression>),
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}"),
}
}
}