|
|
|
@ -452,7 +452,11 @@ impl Parser {
|
|
|
|
|
token::Kind::StringLiteral => Ok(tree::Node::String(token.raw)),
|
|
|
|
|
token::Kind::TrueKeyword => Ok(tree::Node::Bool(true)),
|
|
|
|
|
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),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -472,7 +476,8 @@ impl Parser {
|
|
|
|
|
token::Kind::OParen => {
|
|
|
|
|
// function call
|
|
|
|
|
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 {
|
|
|
|
|
func: Box::new(start),
|
|
|
|
|
params,
|
|
|
|
@ -494,43 +499,54 @@ impl Parser {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// ```notrust
|
|
|
|
|
/// ArrayLiteral
|
|
|
|
|
/// : "[" ArrayElements "]"
|
|
|
|
|
///
|
|
|
|
|
/// ArrayElements
|
|
|
|
|
/// : Expression [ "," [ ArrayElements ] ]
|
|
|
|
|
/// ```
|
|
|
|
|
fn parse_array(&mut self) -> Result<tree::Node, Error> {
|
|
|
|
|
let mut elements = Vec::new();
|
|
|
|
|
while let Some(result) = self.lexer.peek() {
|
|
|
|
|
if result?.kind == token::Kind::CBracket {
|
|
|
|
|
/// Parse a terminated, delimited list of expressions. This is used for
|
|
|
|
|
/// parameter lists in function calls and elements in array literals.
|
|
|
|
|
fn parse_delimited_list(
|
|
|
|
|
&mut self,
|
|
|
|
|
delimiter: token::Kind,
|
|
|
|
|
terminator: token::Kind,
|
|
|
|
|
allow_trailing_delimiter: bool,
|
|
|
|
|
) -> Result<Vec<tree::Node>, Error> {
|
|
|
|
|
let mut list = Vec::new();
|
|
|
|
|
|
|
|
|
|
// 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();
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
elements.push(self.parse_expr(&[token::Kind::Comma, token::Kind::CBracket])?);
|
|
|
|
|
return Ok(list);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(tree::Node::Array(elements))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_param_list(&mut self) -> Result<Vec<tree::Node>, Error> {
|
|
|
|
|
let mut params = Vec::new();
|
|
|
|
|
while let Some(result) = self.lexer.peek() {
|
|
|
|
|
match result?.kind {
|
|
|
|
|
token::Kind::CParen => {
|
|
|
|
|
self.lexer.next();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
params.push(self.parse_expr(&[token::Kind::Comma, token::Kind::CParen])?);
|
|
|
|
|
if self.lexer.current().unwrap().kind == token::Kind::CParen {
|
|
|
|
|
// now we know the list must contain at least one item
|
|
|
|
|
while self.lexer.peek().is_some() {
|
|
|
|
|
list.push(self.parse_expr(&[delimiter, terminator])?);
|
|
|
|
|
|
|
|
|
|
let current = self.lexer.current().unwrap();
|
|
|
|
|
if current.kind == terminator {
|
|
|
|
|
// this is the end of the list, we are finished
|
|
|
|
|
break;
|
|
|
|
|
} else if current.kind == delimiter {
|
|
|
|
|
// depending on whether trailing delimiters are allowed,
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} 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.
|
|
|
|
|