Parser - Lambda functions
This commit is contained in:
parent
4769a2a7f3
commit
2881eb5a61
1 changed files with 89 additions and 33 deletions
|
@ -30,6 +30,36 @@ impl From<&Option<Token>> for LoopParsingState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The type of a function that is being parsed.
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum FunctionKind {
|
||||||
|
Function,
|
||||||
|
Lambda,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FunctionKind {
|
||||||
|
/// The name of this kind.
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Function => "function",
|
||||||
|
Self::Lambda => "lambda",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The string that designates what can be found before the parameters
|
||||||
|
fn before_params(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Function => "function name",
|
||||||
|
Self::Lambda => "'fun' keyword",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The maximal amount of explicit parameters for a function of this kind.
|
||||||
|
fn max_params(&self) -> usize {
|
||||||
|
255
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The result of one of the parser's functions.
|
/// The result of one of the parser's functions.
|
||||||
type ParserResult<T> = Result<T, ParserError>;
|
type ParserResult<T> = Result<T, ParserError>;
|
||||||
|
|
||||||
|
@ -118,7 +148,13 @@ impl Parser {
|
||||||
if self.expect(&[TokenType::Var]).is_some() {
|
if self.expect(&[TokenType::Var]).is_some() {
|
||||||
self.parse_var_declaration()
|
self.parse_var_declaration()
|
||||||
} else if self.expect(&[TokenType::Fun]).is_some() {
|
} else if self.expect(&[TokenType::Fun]).is_some() {
|
||||||
self.parse_fun_declaration("function")
|
if self.check(&TokenType::LeftParen) {
|
||||||
|
// This is a lambda.
|
||||||
|
self.current -= 1;
|
||||||
|
self.parse_expression_stmt()
|
||||||
|
} else {
|
||||||
|
self.parse_fun_declaration(FunctionKind::Function)
|
||||||
|
}
|
||||||
} else if self.expect(&[TokenType::LeftBrace]).is_some() {
|
} else if self.expect(&[TokenType::LeftBrace]).is_some() {
|
||||||
self.parse_block()
|
self.parse_block()
|
||||||
} else if self.expect(&[TokenType::Address]).is_some() {
|
} else if self.expect(&[TokenType::Address]).is_some() {
|
||||||
|
@ -177,35 +213,53 @@ impl Parser {
|
||||||
/// ```
|
/// ```
|
||||||
/// fun_declaration := "fun" function
|
/// fun_declaration := "fun" function
|
||||||
/// function := IDENTIFIER function_info
|
/// function := IDENTIFIER function_info
|
||||||
/// function_info := "(" parameters? ")" block
|
|
||||||
/// parameters := IDENTIFIER ( "," IDENTIFIER )*
|
|
||||||
/// ```
|
/// ```
|
||||||
/// The `kind` parameter is used to generate error messages.
|
/// The `kind` parameter is used to generate error messages.
|
||||||
fn parse_fun_declaration(&mut self, kind: &'static str) -> ParserResult<ast::StmtNode> {
|
fn parse_fun_declaration(&mut self, kind: FunctionKind) -> ParserResult<ast::StmtNode> {
|
||||||
// Read the name
|
// Read the name
|
||||||
let name = match self.peek().token_type {
|
let name = match self.peek().token_type {
|
||||||
TokenType::Identifier(_) => self.advance().clone(),
|
TokenType::Identifier(_) => self.advance().clone(),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ParserError::new(
|
return Err(ParserError::new(
|
||||||
self.peek(),
|
self.peek(),
|
||||||
&format!("expected {} name", kind),
|
&format!("expected {} name", kind.name()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let (params, block) = self.parse_function_info(kind)?;
|
||||||
|
Ok(ast::StmtNode::FunDecl {
|
||||||
|
name,
|
||||||
|
params,
|
||||||
|
body: block,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse the following rules:
|
||||||
|
/// ```
|
||||||
|
/// function_info := "(" parameters? ")" block
|
||||||
|
/// parameters := IDENTIFIER ( "," IDENTIFIER )*
|
||||||
|
/// ```
|
||||||
|
fn parse_function_info(
|
||||||
|
&mut self,
|
||||||
|
kind: FunctionKind,
|
||||||
|
) -> ParserResult<(Vec<Token>, Vec<ast::StmtNode>)> {
|
||||||
// Read the list of parameter names
|
// Read the list of parameter names
|
||||||
self.consume(
|
self.consume(
|
||||||
&TokenType::LeftParen,
|
&TokenType::LeftParen,
|
||||||
&format!("expected '(' after {} name", kind),
|
&format!("expected '(' after {}", kind.before_params()),
|
||||||
)?;
|
)?;
|
||||||
let params = {
|
|
||||||
let mut params = Vec::new();
|
let mut params = Vec::new();
|
||||||
if self.expect(&[TokenType::RightParen]).is_none() {
|
if self.expect(&[TokenType::RightParen]).is_none() {
|
||||||
loop {
|
loop {
|
||||||
if params.len() >= 255 {
|
if params.len() >= kind.max_params() {
|
||||||
return Err(ParserError::new(
|
return Err(ParserError::new(
|
||||||
self.peek(),
|
self.peek(),
|
||||||
&format!("{} can't have more than 255 parameters", kind),
|
&format!(
|
||||||
|
"{} can't have more than {} parameters",
|
||||||
|
kind.name(),
|
||||||
|
kind.max_params()
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if let TokenType::Identifier(_) = self.peek().token_type {
|
if let TokenType::Identifier(_) = self.peek().token_type {
|
||||||
|
@ -219,13 +273,11 @@ impl Parser {
|
||||||
}
|
}
|
||||||
self.consume(&TokenType::RightParen, "')' expected after parameters")?;
|
self.consume(&TokenType::RightParen, "')' expected after parameters")?;
|
||||||
}
|
}
|
||||||
params
|
|
||||||
};
|
|
||||||
|
|
||||||
// Read the function's body
|
// Read the function's body
|
||||||
self.consume(
|
self.consume(
|
||||||
&TokenType::LeftBrace,
|
&TokenType::LeftBrace,
|
||||||
&format!("'{{' expected before {} body", kind),
|
&format!("'{{' expected before {} body", kind.name()),
|
||||||
)?;
|
)?;
|
||||||
let block = {
|
let block = {
|
||||||
self.loop_state.push(LoopParsingState::None);
|
self.loop_state.push(LoopParsingState::None);
|
||||||
|
@ -233,11 +285,7 @@ impl Parser {
|
||||||
self.loop_state.pop();
|
self.loop_state.pop();
|
||||||
result?
|
result?
|
||||||
};
|
};
|
||||||
Ok(ast::StmtNode::FunDecl {
|
Ok((params, block.extract_block_statements()))
|
||||||
name,
|
|
||||||
params,
|
|
||||||
body: block.extract_block_statements(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the following rule:
|
/// Parse the following rule:
|
||||||
|
@ -626,6 +674,7 @@ impl Parser {
|
||||||
/// primary := "(" expression ")"
|
/// primary := "(" expression ")"
|
||||||
/// primary := FALSE | TRUE | NIL | STRING | NUMBER
|
/// primary := FALSE | TRUE | NIL | STRING | NUMBER
|
||||||
/// primary := IDENTIFIER
|
/// primary := IDENTIFIER
|
||||||
|
/// primary := "fun" function_info
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_primary(&mut self) -> ParserResult<ast::ExprNode> {
|
fn parse_primary(&mut self) -> ParserResult<ast::ExprNode> {
|
||||||
if self.expect(&[TokenType::LeftParen]).is_some() {
|
if self.expect(&[TokenType::LeftParen]).is_some() {
|
||||||
|
@ -634,6 +683,13 @@ impl Parser {
|
||||||
Ok(ast::ExprNode::Grouping {
|
Ok(ast::ExprNode::Grouping {
|
||||||
expression: Box::new(expr),
|
expression: Box::new(expr),
|
||||||
})
|
})
|
||||||
|
} else if let Some(token) = self.expect(&[TokenType::Fun]) {
|
||||||
|
let (params, body) = self.parse_function_info(FunctionKind::Lambda)?;
|
||||||
|
Ok(ast::ExprNode::Lambda {
|
||||||
|
token,
|
||||||
|
params,
|
||||||
|
body,
|
||||||
|
})
|
||||||
} else if let Some(token) =
|
} else if let Some(token) =
|
||||||
self.expect(&[TokenType::False, TokenType::True, TokenType::Nil])
|
self.expect(&[TokenType::False, TokenType::True, TokenType::Nil])
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue