Parser - Variable assignment
This commit is contained in:
parent
b5ff24ffad
commit
3a2e8eeda1
1 changed files with 38 additions and 13 deletions
|
@ -11,6 +11,9 @@ pub struct Parser {
|
||||||
current: usize,
|
current: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The result of one of the parser's functions.
|
||||||
|
type ParserResult<T> = Result<T, ParserError>;
|
||||||
|
|
||||||
impl Parser {
|
impl Parser {
|
||||||
/// Initialize the parser.
|
/// Initialize the parser.
|
||||||
pub fn new(tokens: Vec<Token>) -> Self {
|
pub fn new(tokens: Vec<Token>) -> Self {
|
||||||
|
@ -58,7 +61,7 @@ impl Parser {
|
||||||
/// ```
|
/// ```
|
||||||
/// program := statement*
|
/// program := statement*
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_program(&mut self) -> Result<ast::ProgramNode, ParserError> {
|
fn parse_program(&mut self) -> ParserResult<ast::ProgramNode> {
|
||||||
let mut stmts: Vec<ast::StmtNode> = Vec::new();
|
let mut stmts: Vec<ast::StmtNode> = Vec::new();
|
||||||
while !self.is_at_end() {
|
while !self.is_at_end() {
|
||||||
let stmt = self.parse_statement()?;
|
let stmt = self.parse_statement()?;
|
||||||
|
@ -73,7 +76,7 @@ impl Parser {
|
||||||
/// statement := "print" expression ";"
|
/// statement := "print" expression ";"
|
||||||
/// statement := declaration ";"
|
/// statement := declaration ";"
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_statement(&mut self) -> Result<ast::StmtNode, ParserError> {
|
fn parse_statement(&mut self) -> ParserResult<ast::StmtNode> {
|
||||||
if self.expect(&[TokenType::Var]).is_some() {
|
if self.expect(&[TokenType::Var]).is_some() {
|
||||||
self.parse_declaration()
|
self.parse_declaration()
|
||||||
} else if self.expect(&[TokenType::Print]).is_some() {
|
} else if self.expect(&[TokenType::Print]).is_some() {
|
||||||
|
@ -92,7 +95,7 @@ impl Parser {
|
||||||
/// declaration := "var" IDENTIFIER ";"
|
/// declaration := "var" IDENTIFIER ";"
|
||||||
/// declaration := "var" IDENTIFIER "=" expression ";"
|
/// declaration := "var" IDENTIFIER "=" expression ";"
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_declaration(&mut self) -> Result<ast::StmtNode, ParserError> {
|
fn parse_declaration(&mut self) -> ParserResult<ast::StmtNode> {
|
||||||
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(self.peek(), "expected variable name")),
|
_ => return Err(ParserError::new(self.peek(), "expected variable name")),
|
||||||
|
@ -110,10 +113,32 @@ impl Parser {
|
||||||
|
|
||||||
/// Parse the following rule:
|
/// Parse the following rule:
|
||||||
/// ```
|
/// ```
|
||||||
/// expression := equality
|
/// expression := assignment
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_expression(&mut self) -> Result<ast::ExprNode, ParserError> {
|
fn parse_expression(&mut self) -> ParserResult<ast::ExprNode> {
|
||||||
self.parse_equality()
|
self.parse_assignment()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse the following rule:
|
||||||
|
/// ```
|
||||||
|
/// assignment := IDENTIFIER "=" equality
|
||||||
|
/// assignment := equality
|
||||||
|
/// ```
|
||||||
|
fn parse_assignment(&mut self) -> ParserResult<ast::ExprNode> {
|
||||||
|
let expr = self.parse_equality()?;
|
||||||
|
if let Some(equals) = self.expect(&[TokenType::Equal]) {
|
||||||
|
let value = self.parse_assignment()?;
|
||||||
|
if let ast::ExprNode::Variable { name } = expr {
|
||||||
|
Ok(ast::ExprNode::Assignment {
|
||||||
|
name,
|
||||||
|
value: Box::new(value),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(ParserError::new(&equals, "invalid assignment target"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the following rule:
|
/// Parse the following rule:
|
||||||
|
@ -121,7 +146,7 @@ impl Parser {
|
||||||
/// equality := comparison "==" comparison
|
/// equality := comparison "==" comparison
|
||||||
/// equality := comparison "!=" comparison
|
/// equality := comparison "!=" comparison
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_equality(&mut self) -> Result<ast::ExprNode, ParserError> {
|
fn parse_equality(&mut self) -> ParserResult<ast::ExprNode> {
|
||||||
let mut expr = self.parse_comparison()?;
|
let mut expr = self.parse_comparison()?;
|
||||||
while let Some(operator) = self.expect(&[TokenType::BangEqual, TokenType::EqualEqual]) {
|
while let Some(operator) = self.expect(&[TokenType::BangEqual, TokenType::EqualEqual]) {
|
||||||
let right = self.parse_comparison()?;
|
let right = self.parse_comparison()?;
|
||||||
|
@ -139,7 +164,7 @@ impl Parser {
|
||||||
/// comparison := term comparison_operator term
|
/// comparison := term comparison_operator term
|
||||||
/// comparison_operator := "<" | "<=" | ">" | ">="
|
/// comparison_operator := "<" | "<=" | ">" | ">="
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_comparison(&mut self) -> Result<ast::ExprNode, ParserError> {
|
fn parse_comparison(&mut self) -> ParserResult<ast::ExprNode> {
|
||||||
let mut expr = self.parse_term()?;
|
let mut expr = self.parse_term()?;
|
||||||
while let Some(operator) = self.expect(&[
|
while let Some(operator) = self.expect(&[
|
||||||
TokenType::Greater,
|
TokenType::Greater,
|
||||||
|
@ -162,7 +187,7 @@ impl Parser {
|
||||||
/// term := factor "+" factor
|
/// term := factor "+" factor
|
||||||
/// term := factor "-" factor
|
/// term := factor "-" factor
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_term(&mut self) -> Result<ast::ExprNode, ParserError> {
|
fn parse_term(&mut self) -> ParserResult<ast::ExprNode> {
|
||||||
let mut expr = self.parse_factor()?;
|
let mut expr = self.parse_factor()?;
|
||||||
while let Some(operator) = self.expect(&[TokenType::Minus, TokenType::Plus]) {
|
while let Some(operator) = self.expect(&[TokenType::Minus, TokenType::Plus]) {
|
||||||
let right = self.parse_factor()?;
|
let right = self.parse_factor()?;
|
||||||
|
@ -180,7 +205,7 @@ impl Parser {
|
||||||
/// factor := unary "*" unary
|
/// factor := unary "*" unary
|
||||||
/// factor := unary "/" unary
|
/// factor := unary "/" unary
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_factor(&mut self) -> Result<ast::ExprNode, ParserError> {
|
fn parse_factor(&mut self) -> ParserResult<ast::ExprNode> {
|
||||||
let mut expr = self.parse_unary()?;
|
let mut expr = self.parse_unary()?;
|
||||||
while let Some(operator) = self.expect(&[TokenType::Slash, TokenType::Star]) {
|
while let Some(operator) = self.expect(&[TokenType::Slash, TokenType::Star]) {
|
||||||
let right = self.parse_unary()?;
|
let right = self.parse_unary()?;
|
||||||
|
@ -199,7 +224,7 @@ impl Parser {
|
||||||
/// unary := "!" unary
|
/// unary := "!" unary
|
||||||
/// unary := primary
|
/// unary := primary
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_unary(&mut self) -> Result<ast::ExprNode, ParserError> {
|
fn parse_unary(&mut self) -> ParserResult<ast::ExprNode> {
|
||||||
if let Some(operator) = self.expect(&[TokenType::Bang, TokenType::Minus]) {
|
if let Some(operator) = self.expect(&[TokenType::Bang, TokenType::Minus]) {
|
||||||
Ok(ast::ExprNode::Unary {
|
Ok(ast::ExprNode::Unary {
|
||||||
operator,
|
operator,
|
||||||
|
@ -216,7 +241,7 @@ impl Parser {
|
||||||
/// primary := FALSE | TRUE | NIL | STRING | NUMBER
|
/// primary := FALSE | TRUE | NIL | STRING | NUMBER
|
||||||
/// primary := IDENTIFIER
|
/// primary := IDENTIFIER
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_primary(&mut self) -> Result<ast::ExprNode, ParserError> {
|
fn parse_primary(&mut self) -> ParserResult<ast::ExprNode> {
|
||||||
if self.expect(&[TokenType::LeftParen]).is_some() {
|
if self.expect(&[TokenType::LeftParen]).is_some() {
|
||||||
let expr = self.parse_expression()?;
|
let expr = self.parse_expression()?;
|
||||||
self.consume(&TokenType::RightParen, "expected ')' after expression")?;
|
self.consume(&TokenType::RightParen, "expected ')' after expression")?;
|
||||||
|
@ -257,7 +282,7 @@ impl Parser {
|
||||||
|
|
||||||
/// Consume a token of a given type. If no matching token is found, a
|
/// Consume a token of a given type. If no matching token is found, a
|
||||||
/// parse error is returned instead. Otherwise the read pointer is moved.
|
/// parse error is returned instead. Otherwise the read pointer is moved.
|
||||||
fn consume(&mut self, token_type: &TokenType, error: &str) -> Result<&Token, ParserError> {
|
fn consume(&mut self, token_type: &TokenType, error: &str) -> ParserResult<&Token> {
|
||||||
if self.check(token_type) {
|
if self.check(token_type) {
|
||||||
Ok(self.advance())
|
Ok(self.advance())
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue