Blocks and statements
parent
ea33ae23bc
commit
c2c0dacb67
|
@ -1,6 +1,8 @@
|
||||||
# implementation roadmap
|
# implementation roadmap
|
||||||
|
|
||||||
- [ ] parser
|
- [ ] parser
|
||||||
|
- [ ] uniform function call syntax
|
||||||
|
- [ ] lossless syntax trees (rowan + ungrammar)
|
||||||
- [ ] typechecker
|
- [ ] typechecker
|
||||||
- [ ] interpreter
|
- [ ] interpreter
|
||||||
- [ ] code generator
|
- [ ] code generator
|
||||||
|
@ -11,4 +13,5 @@
|
||||||
- [ ] product types
|
- [ ] product types
|
||||||
- [ ] sum types
|
- [ ] sum types
|
||||||
- [ ] variant types
|
- [ ] variant types
|
||||||
|
- [ ] pattern matching
|
||||||
- [ ] trait / interface system
|
- [ ] trait / interface system
|
||||||
|
|
12
example.mul
12
example.mul
|
@ -1,7 +1,9 @@
|
||||||
main = () {
|
main = () -> {
|
||||||
print(sum_equals(1, 2, 3) == true)
|
result = sum_equals(1, 2, 3);
|
||||||
|
print(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
sum_equals = (x, y, sum) {
|
sum_equals = (x, y, expected) -> {
|
||||||
equals(add(x, y), sum)
|
sum = add(x, y);
|
||||||
}
|
equals(sum, expected)
|
||||||
|
}
|
||||||
|
|
23
src/main.rs
23
src/main.rs
|
@ -1,11 +1,22 @@
|
||||||
use std::io::{stdin, stdout, BufRead, Write};
|
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() {
|
fn main() {
|
||||||
let mut stdin = stdin().lock();
|
let mut stdin = stdin().lock();
|
||||||
let mut stdout = stdout().lock();
|
let mut stdout = stdout().lock();
|
||||||
let parser = ExpressionParser::new();
|
let expression = ExpressionParser::new();
|
||||||
|
let statement = StatementParser::new();
|
||||||
loop {
|
loop {
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
print!("> ");
|
print!("> ");
|
||||||
|
@ -13,10 +24,10 @@ fn main() {
|
||||||
stdin
|
stdin
|
||||||
.read_line(&mut line)
|
.read_line(&mut line)
|
||||||
.expect("Failed to read from stdin");
|
.expect("Failed to read from stdin");
|
||||||
match parser.parse(line.as_str()) {
|
if line.trim_end().ends_with(';') {
|
||||||
Ok(parsed) => println!("{parsed:?}"),
|
parse!(statement, line)
|
||||||
Err(lalrpop_util::ParseError::UnrecognizedEOF { .. }) => break,
|
} else {
|
||||||
Err(e) => println!("Parse error: {e}"),
|
parse!(expression, line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,31 @@
|
||||||
use crate::syntax::{Expression, Name};
|
use crate::syntax::{Expression, Name, Statement};
|
||||||
|
|
||||||
grammar;
|
grammar;
|
||||||
|
|
||||||
|
pub Statement: Statement = {
|
||||||
|
<name:Name> "=" <body:Expression> ";" => Statement::Binding(name, body),
|
||||||
|
<body:Expression> ";" => Statement::Expression(body),
|
||||||
|
};
|
||||||
|
|
||||||
pub Expression: Expression = {
|
pub Expression: Expression = {
|
||||||
"(" <params:Comma<Name>> ")" "{" <body:Expression> "}" => Expression::Lambda(params, Box::new(body)),
|
"(" <params:Comma<Name>> ")" "->" <body:Expression> => Expression::Lambda(params, Box::new(body)),
|
||||||
<callee:Expression> "(" <args:Comma<Expression>> ")" => Expression::Call(Box::new(callee), args),
|
Atom => <>,
|
||||||
|
};
|
||||||
|
|
||||||
|
Atom: Expression = {
|
||||||
Name => Expression::Variable(<>),
|
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(<>),
|
Integer => Expression::Integer(<>),
|
||||||
Boolean => Expression::Boolean(<>),
|
Boolean => Expression::Boolean(<>),
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: decide on identifier syntax
|
// 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 = {
|
Boolean: bool = {
|
||||||
"true" => true,
|
"true" => true,
|
||||||
|
|
|
@ -1,10 +1,57 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
pub type Name = String;
|
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)]
|
#[derive(Debug)]
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
Variable(Name),
|
Variable(Name),
|
||||||
|
Block(Vec<Statement>, Box<Expression>),
|
||||||
Lambda(Vec<Name>, Box<Expression>),
|
Lambda(Vec<Name>, Box<Expression>),
|
||||||
Call(Box<Expression>, Vec<Expression>),
|
Call(Box<Expression>, Vec<Expression>),
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Integer(i64),
|
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}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue