λ Support functions! #5

Open
acw wants to merge 59 commits from awick/functions into develop
4 changed files with 19 additions and 26 deletions
Showing only changes of commit 6c3fc2de01 - Show all commits

View File

@@ -1,7 +1,7 @@
x = 1;
function add_x(y) x + y;
a = 3;
function add_x_twice(y) add_x(y) + x
function add_x_twice(y) add_x(y) + x;
print x;
result = add_x(a);
print x;

View File

@@ -2,7 +2,7 @@ x = 1u64;
function mean_x(y) {
base = x + y;
result = base / 2;
result;
result
};
a = 3;
mean_x_and_a = mean_x(a);

View File

@@ -60,7 +60,8 @@ pub Program: Program = {
// a program is just a set of statements
<items:ProgramTopLevel> => Program {
items
}
},
=> Program { items: vec![] },
}
ProgramTopLevel: Vec<TopLevel> = {
@@ -68,17 +69,21 @@ ProgramTopLevel: Vec<TopLevel> = {
rest.push(t);
rest
},
=> Vec::new(),
<t:TopLevel> => vec![t],
}
pub TopLevel: TopLevel = {
<f:Function> => f,
<s:Statement> => TopLevel::Statement(s),
<s:Statement> ";" => TopLevel::Statement(s),
}
Function: TopLevel = {
"function" <opt_name:OptionalName> "(" <args:Arguments> OptionalComma ")" <exp:Expression> ";" =>
TopLevel::Function(opt_name, args, exp),
// "function" <opt_name:OptionalName> "(" <args:Arguments> OptionalComma ")" <s:@L> "{" "}" <e:@L> =>
// TopLevel::Function(opt_name, args, Expression::Block(Location::new(file_idx, s..e), vec![])),
// "function" <opt_name:OptionalName> "(" <args:Arguments> OptionalComma ")" <s:@L> "{" <stmts:Statements> "}" <e:@L> =>
// TopLevel::Function(opt_name, args, Expression::Block(Location::new(file_idx, s..e), stmts)),
}
OptionalName: Option<Name> = {
@@ -112,36 +117,22 @@ Statements: Vec<Statement> = {
// a statement is either a set of statements followed by another
// statement (note, here, that you can name the result of a sub-parse
// using <name: subrule>) ...
<mut stmts:Statements> <stmt:Statement> => {
<mut stmts:Statements> ";" <stmt:Statement> => {
stmts.push(stmt);
stmts
},
// ... or it's nothing. This may feel like an awkward way to define
// lists of things -- and it is a bit awkward -- but there are actual
// technical reasons that you want to (a) use recursivion to define
// these, and (b) use *left* recursion, specifically. That's why, in
// this file, all of the recursive cases are to the left, like they
// are above.
//
// the details of why left recursion is better is actually pretty
// fiddly and in the weeds, and if you're interested you should look
// up LALR parsers versus LL parsers; both their differences and how
// they're constructed, as they're kind of neat.
//
// but if you're just writing grammars with lalrpop, then you should
// just remember that you should always use left recursion, and be
// done with it.
=> {
Vec::new()
<stmt:Statement> => {
vec![stmt]
}
}
#[inline]
Statement: Statement = {
// A statement can be a variable binding. Note, here, that we use this
// funny @L thing to get the source location before the variable, so that
// we can say that this statement spans across everything.
<ls: @L> <v:"<var>"> <var_end: @L> "=" <e:Expression> ";" <le: @L> =>
<ls: @L> <v:"<var>"> <var_end: @L> "=" <e:Expression> <le: @L> =>
Statement::Binding(
Location::new(file_idx, ls..le),
Name::new(v, Location::new(file_idx, ls..var_end)),
@@ -149,14 +140,14 @@ Statement: Statement = {
),
// A statement can just be a print statement.
<ls: @L> "print" <name_start: @L> <v:"<var>"> <name_end: @L> ";" <le: @L> =>
<ls: @L> "print" <name_start: @L> <v:"<var>"> <name_end: @L> <le: @L> =>
Statement::Print(
Location::new(file_idx, ls..le),
Name::new(v, Location::new(file_idx, name_start..name_end)),
),
// A statement can just be an expression.
<e: Expression> ";" =>
<e: Expression> =>
Statement::Expression(e),
}
@@ -237,6 +228,7 @@ AtomicExpression: Expression = {
<l: @L> <n:"<num>"> <end: @L> => Expression::Value(Location::new(file_idx, l..end), Value::Number(n.0, n.1, n.2)),
// this expression could actually be a block!
<s:@L> "{" <stmts:Statements> "}" <e:@L> => Expression::Block(Location::new(file_idx, s..e), stmts),
<s:@L> "{" "}" <e:@L> => Expression::Block(Location::new(file_idx, s..e), vec![]),
// finally, let people parenthesize expressions and get back to a
// lower precedence
"(" <e:Expression> ")" => e,

View File

@@ -68,6 +68,7 @@ impl Program {
/// actually a problem.
pub fn validate(&self) -> (Vec<Error>, Vec<Warning>) {
let mut bound_variables = ScopedMap::new();
println!("validate: {}", self);
self.validate_with_bindings(&mut bound_variables)
}