parse tweaks
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user