|
|
|
@@ -60,7 +60,8 @@ pub Program: Program = {
|
|
|
|
// a program is just a set of statements
|
|
|
|
// a program is just a set of statements
|
|
|
|
<items:ProgramTopLevel> => Program {
|
|
|
|
<items:ProgramTopLevel> => Program {
|
|
|
|
items
|
|
|
|
items
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
=> Program { items: vec![] },
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ProgramTopLevel: Vec<TopLevel> = {
|
|
|
|
ProgramTopLevel: Vec<TopLevel> = {
|
|
|
|
@@ -68,17 +69,21 @@ ProgramTopLevel: Vec<TopLevel> = {
|
|
|
|
rest.push(t);
|
|
|
|
rest.push(t);
|
|
|
|
rest
|
|
|
|
rest
|
|
|
|
},
|
|
|
|
},
|
|
|
|
=> Vec::new(),
|
|
|
|
<t:TopLevel> => vec![t],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub TopLevel: TopLevel = {
|
|
|
|
pub TopLevel: TopLevel = {
|
|
|
|
<f:Function> => f,
|
|
|
|
<f:Function> => f,
|
|
|
|
<s:Statement> => TopLevel::Statement(s),
|
|
|
|
<s:Statement> ";" => TopLevel::Statement(s),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Function: TopLevel = {
|
|
|
|
Function: TopLevel = {
|
|
|
|
"function" <opt_name:OptionalName> "(" <args:Arguments> OptionalComma ")" <exp:Expression> ";" =>
|
|
|
|
"function" <opt_name:OptionalName> "(" <args:Arguments> OptionalComma ")" <exp:Expression> ";" =>
|
|
|
|
TopLevel::Function(opt_name, args, exp),
|
|
|
|
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> = {
|
|
|
|
OptionalName: Option<Name> = {
|
|
|
|
@@ -112,36 +117,22 @@ Statements: Vec<Statement> = {
|
|
|
|
// a statement is either a set of statements followed by another
|
|
|
|
// a statement is either a set of statements followed by another
|
|
|
|
// statement (note, here, that you can name the result of a sub-parse
|
|
|
|
// statement (note, here, that you can name the result of a sub-parse
|
|
|
|
// using <name: subrule>) ...
|
|
|
|
// using <name: subrule>) ...
|
|
|
|
<mut stmts:Statements> <stmt:Statement> => {
|
|
|
|
<mut stmts:Statements> ";" <stmt:Statement> => {
|
|
|
|
stmts.push(stmt);
|
|
|
|
stmts.push(stmt);
|
|
|
|
stmts
|
|
|
|
stmts
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// ... or it's nothing. This may feel like an awkward way to define
|
|
|
|
<stmt:Statement> => {
|
|
|
|
// lists of things -- and it is a bit awkward -- but there are actual
|
|
|
|
vec![stmt]
|
|
|
|
// 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()
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
Statement: Statement = {
|
|
|
|
Statement: Statement = {
|
|
|
|
// A statement can be a variable binding. Note, here, that we use this
|
|
|
|
// 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
|
|
|
|
// funny @L thing to get the source location before the variable, so that
|
|
|
|
// we can say that this statement spans across everything.
|
|
|
|
// 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(
|
|
|
|
Statement::Binding(
|
|
|
|
Location::new(file_idx, ls..le),
|
|
|
|
Location::new(file_idx, ls..le),
|
|
|
|
Name::new(v, Location::new(file_idx, ls..var_end)),
|
|
|
|
Name::new(v, Location::new(file_idx, ls..var_end)),
|
|
|
|
@@ -149,14 +140,14 @@ Statement: Statement = {
|
|
|
|
),
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
|
|
// A statement can just be a print 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(
|
|
|
|
Statement::Print(
|
|
|
|
Location::new(file_idx, ls..le),
|
|
|
|
Location::new(file_idx, ls..le),
|
|
|
|
Name::new(v, Location::new(file_idx, name_start..name_end)),
|
|
|
|
Name::new(v, Location::new(file_idx, name_start..name_end)),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
|
|
// A statement can just be an expression.
|
|
|
|
// A statement can just be an expression.
|
|
|
|
<e: Expression> ";" =>
|
|
|
|
<e: Expression> =>
|
|
|
|
Statement::Expression(e),
|
|
|
|
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)),
|
|
|
|
<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!
|
|
|
|
// this expression could actually be a block!
|
|
|
|
<s:@L> "{" <stmts:Statements> "}" <e:@L> => Expression::Block(Location::new(file_idx, s..e), stmts),
|
|
|
|
<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
|
|
|
|
// finally, let people parenthesize expressions and get back to a
|
|
|
|
// lower precedence
|
|
|
|
// lower precedence
|
|
|
|
"(" <e:Expression> ")" => e,
|
|
|
|
"(" <e:Expression> ")" => e,
|
|
|
|
|