implement chapter 12 in rust
This commit is contained in:
parent
283155c38b
commit
621c97102a
10 changed files with 366 additions and 17 deletions
|
@ -25,6 +25,8 @@ pub enum ParserError {
|
|||
SemicolonAfterValueExpected(usize),
|
||||
#[error("line {0}: expected ';' after expression.")]
|
||||
SemicolonAfterExpressionExpected(usize),
|
||||
#[error("line {0}: expected class name.")]
|
||||
ClassNameExpected(usize),
|
||||
#[error("line {0}: expected variable name.")]
|
||||
VariableNameExpected(usize),
|
||||
#[error("line {0}: invalid assignment target.")]
|
||||
|
@ -57,6 +59,12 @@ pub enum ParserError {
|
|||
LeftBraceBeforeFunctionBodyExpected(usize),
|
||||
#[error("line {0}: expected ';' after return value.")]
|
||||
SemicolonAfterReturnExpected(usize),
|
||||
#[error("line {0}: expected '{{' before class body.")]
|
||||
LeftBraceBeforeClassExpected(usize),
|
||||
#[error("line {0}: expected '}}' after class body.")]
|
||||
RightBraceAfterClassExpected(usize),
|
||||
#[error("line {0}: expected property name after '.'.")]
|
||||
PropertyNameAfterDotExpected(usize),
|
||||
}
|
||||
|
||||
/// Parse the Lox language.
|
||||
|
@ -174,7 +182,9 @@ impl Parser {
|
|||
}
|
||||
|
||||
fn declaration(&mut self) -> Result<Statement, ParserError> {
|
||||
if self.matches(&[Fun]) {
|
||||
if self.matches(&[Class]) {
|
||||
self.class_declaration()
|
||||
} else if self.matches(&[Fun]) {
|
||||
self.function()
|
||||
} else if self.matches(&[Var]) {
|
||||
self.var_declaration()
|
||||
|
@ -297,6 +307,28 @@ impl Parser {
|
|||
Ok(Statement::Return { keyword, value })
|
||||
}
|
||||
|
||||
fn class_declaration(&mut self) -> Result<Statement, ParserError> {
|
||||
let line = self.current_token.line;
|
||||
let name = self
|
||||
.consume(&Identifier)
|
||||
.ok_or(ParserError::ClassNameExpected(line))?
|
||||
.clone();
|
||||
|
||||
self.consume(&LeftBrace)
|
||||
.ok_or(ParserError::LeftBraceBeforeClassExpected(line))?;
|
||||
|
||||
let mut methods = Vec::new();
|
||||
while !self.check(&RightBrace) && !self.is_at_end() {
|
||||
let method = self.function()?;
|
||||
methods.push(method);
|
||||
}
|
||||
|
||||
self.consume(&RightBrace)
|
||||
.ok_or(ParserError::RightBraceAfterClassExpected(line))?;
|
||||
|
||||
Ok(Statement::Class { name, methods })
|
||||
}
|
||||
|
||||
fn var_declaration(&mut self) -> Result<Statement, ParserError> {
|
||||
let line = self.current_token.line;
|
||||
let name = self
|
||||
|
@ -409,6 +441,12 @@ impl Parser {
|
|||
name,
|
||||
value: Box::new(value),
|
||||
})
|
||||
} else if let Expression::Get { object, name } = expr {
|
||||
Ok(Expression::Set {
|
||||
object,
|
||||
name,
|
||||
value: Box::new(value),
|
||||
})
|
||||
} else {
|
||||
Err(ParserError::InvalidAssignmentTarget(equals.line))
|
||||
}
|
||||
|
@ -490,6 +528,17 @@ impl Parser {
|
|||
loop {
|
||||
if self.matches(&[LeftParen]) {
|
||||
expr = self.finish_call(expr)?;
|
||||
} else if self.matches(&[Dot]) {
|
||||
let line = self.current_token.line;
|
||||
|
||||
let name = self
|
||||
.consume(&Identifier)
|
||||
.ok_or(ParserError::PropertyNameAfterDotExpected(line))?
|
||||
.clone();
|
||||
expr = Expression::Get {
|
||||
object: Box::new(expr),
|
||||
name,
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -536,6 +585,10 @@ impl Parser {
|
|||
Ok(Expression::Literal {
|
||||
value: token::Literal::Nil,
|
||||
})
|
||||
} else if self.matches(&[This]) {
|
||||
Ok(Expression::This {
|
||||
keyword: self.previous()?.clone(),
|
||||
})
|
||||
} else if self.matches(&[Identifier]) {
|
||||
let prev = self.previous()?.clone();
|
||||
Ok(Expression::Variable { name: prev })
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue