chapter 10 in rust
This commit is contained in:
parent
a13db8e29c
commit
a98d249399
9 changed files with 401 additions and 35 deletions
|
@ -1,6 +1,3 @@
|
|||
use thiserror::Error;
|
||||
use tracing::error;
|
||||
|
||||
use crate::{
|
||||
expression::Expression,
|
||||
statement::Statement,
|
||||
|
@ -9,6 +6,8 @@ use crate::{
|
|||
TokenType::{self, *},
|
||||
},
|
||||
};
|
||||
use thiserror::Error;
|
||||
use tracing::error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ParserError {
|
||||
|
@ -44,6 +43,20 @@ pub enum ParserError {
|
|||
SemicolonAfterLoopConditionExpected(usize),
|
||||
#[error("[line {0}] expected ')' after for clauses.")]
|
||||
RightParenAfterForClausesExpected(usize),
|
||||
#[error("[line {0}] expected ')' after arguments.")]
|
||||
RightParenAfterArgumentsExpected(usize),
|
||||
#[error("[line {0}] expected function name.")]
|
||||
FunctionNameExpected(usize),
|
||||
#[error("[line {0}] expected '(' after function name.")]
|
||||
LeftParenAfterFunctionNameExpected(usize),
|
||||
#[error("[line {0}] expected ')' after parameters.")]
|
||||
RightParenAfterParamsExpected(usize),
|
||||
#[error("[line {0}] expected parameter name.")]
|
||||
ParamNameExpected(usize),
|
||||
#[error("[line {0}] expected '{{' before function body.")]
|
||||
LeftBraceBeforeFunctionBodyExpected(usize),
|
||||
#[error("[line {0}] expected ';' after return value.")]
|
||||
SemicolonAfterReturnExpected(usize),
|
||||
}
|
||||
|
||||
/// Parse the Lox language.
|
||||
|
@ -161,7 +174,9 @@ impl Parser {
|
|||
}
|
||||
|
||||
fn declaration(&mut self) -> Result<Statement, ParserError> {
|
||||
if self.matches(&[Var]) {
|
||||
if self.matches(&[Fun]) {
|
||||
self.function()
|
||||
} else if self.matches(&[Var]) {
|
||||
self.var_declaration()
|
||||
} else {
|
||||
self.statement()
|
||||
|
@ -175,6 +190,8 @@ impl Parser {
|
|||
self.if_statement()
|
||||
} else if self.matches(&[Print]) {
|
||||
self.print_statement()
|
||||
} else if self.matches(&[Return]) {
|
||||
self.return_statement()
|
||||
} else if self.matches(&[While]) {
|
||||
self.while_statement()
|
||||
} else if self.matches(&[LeftBrace]) {
|
||||
|
@ -266,6 +283,20 @@ impl Parser {
|
|||
Ok(Statement::Print(value))
|
||||
}
|
||||
|
||||
fn return_statement(&mut self) -> Result<Statement, ParserError> {
|
||||
let keyword = self.previous()?.clone();
|
||||
let value = if self.check(&Semicolon) {
|
||||
None
|
||||
} else {
|
||||
Some(self.expression()?)
|
||||
};
|
||||
|
||||
self.consume(&Semicolon)
|
||||
.ok_or(ParserError::SemicolonAfterReturnExpected(keyword.line))?;
|
||||
|
||||
Ok(Statement::Return { keyword, value })
|
||||
}
|
||||
|
||||
fn var_declaration(&mut self) -> Result<Statement, ParserError> {
|
||||
let line = self.current_token.line;
|
||||
let name = self
|
||||
|
@ -315,6 +346,43 @@ impl Parser {
|
|||
Ok(Statement::Expression(expr))
|
||||
}
|
||||
|
||||
fn function(&mut self) -> Result<Statement, ParserError> {
|
||||
let line = self.current_token.line;
|
||||
let name = self
|
||||
.consume(&Identifier)
|
||||
.ok_or(ParserError::FunctionNameExpected(line))?
|
||||
.clone();
|
||||
|
||||
self.consume(&LeftParen)
|
||||
.ok_or(ParserError::LeftParenAfterFunctionNameExpected(line))?;
|
||||
|
||||
let mut params = Vec::new();
|
||||
if !self.check(&RightParen) {
|
||||
let param = self
|
||||
.consume(&Identifier)
|
||||
.ok_or(ParserError::ParamNameExpected(line))?
|
||||
.clone();
|
||||
params.push(param);
|
||||
|
||||
while self.matches(&[Comma]) {
|
||||
let param = self
|
||||
.consume(&Identifier)
|
||||
.ok_or(ParserError::ParamNameExpected(line))?
|
||||
.clone();
|
||||
params.push(param);
|
||||
}
|
||||
}
|
||||
|
||||
self.consume(&RightParen)
|
||||
.ok_or(ParserError::RightParenAfterParamsExpected(line))?;
|
||||
self.consume(&LeftBrace)
|
||||
.ok_or(ParserError::LeftBraceBeforeFunctionBodyExpected(line))?;
|
||||
|
||||
let body = self.block()?;
|
||||
|
||||
Ok(Statement::Function { name, params, body })
|
||||
}
|
||||
|
||||
fn block(&mut self) -> Result<Vec<Statement>, ParserError> {
|
||||
let mut statements = Vec::new();
|
||||
|
||||
|
@ -412,10 +480,48 @@ impl Parser {
|
|||
right: Box::new(right),
|
||||
})
|
||||
} else {
|
||||
self.primary()
|
||||
self.call()
|
||||
}
|
||||
}
|
||||
|
||||
fn call(&mut self) -> Result<Expression, ParserError> {
|
||||
let mut expr = self.primary()?;
|
||||
|
||||
loop {
|
||||
if self.matches(&[LeftParen]) {
|
||||
expr = self.finish_call(expr)?;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn finish_call(&mut self, callee: Expression) -> Result<Expression, ParserError> {
|
||||
let mut args = Vec::new();
|
||||
|
||||
if !self.check(&RightParen) {
|
||||
args.push(self.expression()?);
|
||||
|
||||
while self.matches(&[Comma]) {
|
||||
args.push(self.expression()?);
|
||||
}
|
||||
}
|
||||
|
||||
let line = self.current_token.line;
|
||||
let paren = self
|
||||
.consume(&RightParen)
|
||||
.ok_or(ParserError::RightParenAfterArgumentsExpected(line))?
|
||||
.clone();
|
||||
|
||||
Ok(Expression::Call {
|
||||
callee: Box::new(callee),
|
||||
paren,
|
||||
args,
|
||||
})
|
||||
}
|
||||
|
||||
/// primary -> NUMBER | STRING | "true" | "false" | "nil" | "(" expression ")" ;
|
||||
fn primary(&mut self) -> Result<Expression, ParserError> {
|
||||
if self.matches(&[False]) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue