ast: unify function param and array parsing

main
anna 2 years ago
parent e932590bca
commit dbcdee1c33
Signed by: fef
GPG Key ID: EC22E476DC2D3D84

@ -452,7 +452,11 @@ impl Parser {
token::Kind::StringLiteral => Ok(tree::Node::String(token.raw)), token::Kind::StringLiteral => Ok(tree::Node::String(token.raw)),
token::Kind::TrueKeyword => Ok(tree::Node::Bool(true)), token::Kind::TrueKeyword => Ok(tree::Node::Bool(true)),
token::Kind::FalseKeyword => Ok(tree::Node::Bool(false)), token::Kind::FalseKeyword => Ok(tree::Node::Bool(false)),
token::Kind::OBracket => self.parse_array(), token::Kind::OBracket => {
let elements =
self.parse_delimited_list(token::Kind::Comma, token::Kind::CBracket, true)?;
Ok(tree::Node::Array(elements))
}
_ => self.syntax_error(format!("Unexpected token {}", token.kind), &token), _ => self.syntax_error(format!("Unexpected token {}", token.kind), &token),
} }
} }
@ -472,7 +476,8 @@ impl Parser {
token::Kind::OParen => { token::Kind::OParen => {
// function call // function call
self.lexer.next(); self.lexer.next();
let params = self.parse_param_list()?; let params =
self.parse_delimited_list(token::Kind::Comma, token::Kind::CParen, false)?;
self.parse_primary_expr_rest(tree::Node::CallExpr { self.parse_primary_expr_rest(tree::Node::CallExpr {
func: Box::new(start), func: Box::new(start),
params, params,
@ -494,43 +499,54 @@ impl Parser {
} }
} }
/// ```notrust /// Parse a terminated, delimited list of expressions. This is used for
/// ArrayLiteral /// parameter lists in function calls and elements in array literals.
/// : "[" ArrayElements "]" fn parse_delimited_list(
/// &mut self,
/// ArrayElements delimiter: token::Kind,
/// : Expression [ "," [ ArrayElements ] ] terminator: token::Kind,
/// ``` allow_trailing_delimiter: bool,
fn parse_array(&mut self) -> Result<tree::Node, Error> { ) -> Result<Vec<tree::Node>, Error> {
let mut elements = Vec::new(); let mut list = Vec::new();
while let Some(result) = self.lexer.peek() {
if result?.kind == token::Kind::CBracket { // In the simplest case, we immediately see the terminator.
// That means we are already finished and return an empty list.
if let Some(Ok(token)) = self.lexer.peek() {
if token.kind == terminator {
self.lexer.next(); self.lexer.next();
break; return Ok(list);
} else {
elements.push(self.parse_expr(&[token::Kind::Comma, token::Kind::CBracket])?);
} }
} }
Ok(tree::Node::Array(elements))
}
fn parse_param_list(&mut self) -> Result<Vec<tree::Node>, Error> { // now we know the list must contain at least one item
let mut params = Vec::new(); while self.lexer.peek().is_some() {
while let Some(result) = self.lexer.peek() { list.push(self.parse_expr(&[delimiter, terminator])?);
match result?.kind {
token::Kind::CParen => { let current = self.lexer.current().unwrap();
self.lexer.next(); if current.kind == terminator {
break; // this is the end of the list, we are finished
} break;
_ => { } else if current.kind == delimiter {
params.push(self.parse_expr(&[token::Kind::Comma, token::Kind::CParen])?); // depending on whether trailing delimiters are allowed,
if self.lexer.current().unwrap().kind == token::Kind::CParen { // this might still be the end of the list
if let Some(Ok(token)) = self.lexer.peek() {
if token.kind == terminator && allow_trailing_delimiter {
// so we saw a trailing delimiter followed by the
// terminator *and* trailing delimiters are allowed;
// this means we are finished here
self.lexer.next();
break; break;
} }
} }
} else {
// this should never happen since parse_expr() always returns
// with the current token kind being one of the ones specified
// (otherwise it would return a syntax error, in which case we
// wouldn't even reach this entire if block in the first place)
panic!("parse_expr() ended with an illegal token");
} }
} }
Ok(params) Ok(list)
} }
/// Ensure that the `scope` stack contains a certain scope. /// Ensure that the `scope` stack contains a certain scope.

@ -120,7 +120,11 @@ impl Node {
p.visit(cb, depth); p.visit(cb, depth);
} }
} }
Node::IfStmt { condition, then_block, else_block} => { Node::IfStmt {
condition,
then_block,
else_block,
} => {
condition.visit(cb, depth); condition.visit(cb, depth);
then_block.visit(cb, depth); then_block.visit(cb, depth);
if let Some(eb) = else_block { if let Some(eb) = else_block {
@ -174,7 +178,11 @@ impl fmt::Display for Node {
Node::Array(_) => "<array>", Node::Array(_) => "<array>",
Node::ArrayExpr { array, index } => "<array-access>", Node::ArrayExpr { array, index } => "<array-access>",
Node::CallExpr { func, params } => "<call>", Node::CallExpr { func, params } => "<call>",
Node::IfStmt { condition, then_block, else_block } => "<if>", Node::IfStmt {
condition,
then_block,
else_block,
} => "<if>",
Node::UnaryExpr { op, node } => op.raw(), Node::UnaryExpr { op, node } => op.raw(),
Node::BinaryExpr { op, lhs, rhs } => op.raw(), Node::BinaryExpr { op, lhs, rhs } => op.raw(),
Node::TypeExpr(_) => "type", Node::TypeExpr(_) => "type",

Loading…
Cancel
Save