Introduce NodeId for AST and synthetic slices
This commit is contained in:
+46
-42
@@ -53,7 +53,6 @@ impl Parser {
|
||||
self.var_statement()
|
||||
}
|
||||
(TokenType::Identifier, TokenType::Colon) => self.var_statement(),
|
||||
(TokenType::Identifier, TokenType::Equal) => self.assignment_statement(),
|
||||
(TokenType::If, _) => self.if_statement(),
|
||||
(TokenType::While, _) => self.while_statement(),
|
||||
(TokenType::For, _) => self.for_statement(),
|
||||
@@ -68,7 +67,7 @@ impl Parser {
|
||||
let variable = self.var_statement()?;
|
||||
let condition = self.expression()?;
|
||||
self.consume(TokenType::Semicolon, "Expected ';' after for condition")?;
|
||||
let increment = self.assignment_statement()?;
|
||||
let increment = self.expression_statement()?;
|
||||
let body = self.statement(Some("loop".to_string()))?;
|
||||
|
||||
let end_slice = self.previous().source_slice.clone();
|
||||
@@ -260,8 +259,8 @@ impl Parser {
|
||||
}
|
||||
|
||||
let body = self.statement(None)?;
|
||||
let node = AstNode {
|
||||
node: Expr::Literal {
|
||||
let node = AstNode::new(
|
||||
Expr::Literal {
|
||||
value: BaseValue::Function(LoxFunction {
|
||||
parameters,
|
||||
return_type: None,
|
||||
@@ -270,8 +269,8 @@ impl Parser {
|
||||
guard,
|
||||
}),
|
||||
},
|
||||
source_slice: combine_position.clone(),
|
||||
};
|
||||
combine_position.clone(),
|
||||
);
|
||||
Ok(AstNode::new(
|
||||
Stmt::VarDeclaration {
|
||||
name: name_lexeme,
|
||||
@@ -294,12 +293,12 @@ impl Parser {
|
||||
}
|
||||
// todo: make type annotation
|
||||
}
|
||||
let mut value = AstNode {
|
||||
node: Expr::Literal {
|
||||
let mut value = AstNode::new(
|
||||
Expr::Literal {
|
||||
value: BaseValue::Nil,
|
||||
},
|
||||
source_slice: start_slice.clone(),
|
||||
};
|
||||
start_slice.clone(),
|
||||
);
|
||||
if self.peek().token_type == TokenType::Equal {
|
||||
self.advance();
|
||||
value = self.expression()?;
|
||||
@@ -323,31 +322,6 @@ impl Parser {
|
||||
combined_slice,
|
||||
))
|
||||
}
|
||||
fn assignment_statement(&mut self) -> LoxResult<AstNode<Stmt>> {
|
||||
let start_slice = self.peek().source_slice.clone();
|
||||
let name = self.consume(TokenType::Identifier, "Expect variable name.")?;
|
||||
let name_lexeme = name.lexeme.clone();
|
||||
self.consume(TokenType::Equal, "Expect '=' after variable name.")?;
|
||||
let value = self.expression()?;
|
||||
let semicolon = self.consume(
|
||||
TokenType::Semicolon,
|
||||
"Expect ';' after variable declaration.",
|
||||
)?;
|
||||
let end_slice = semicolon.source_slice.clone();
|
||||
let combined_slice = SourceSlice::from_positions(
|
||||
start_slice.source_id,
|
||||
start_slice.start_position,
|
||||
end_slice.end_position,
|
||||
);
|
||||
Ok(AstNode::new(
|
||||
Stmt::VarAssigment {
|
||||
name: name_lexeme,
|
||||
value: Box::new(value),
|
||||
return_value: Box::new(BaseValue::Nil),
|
||||
},
|
||||
combined_slice,
|
||||
))
|
||||
}
|
||||
|
||||
fn print_statement(&mut self) -> LoxResult<AstNode<Stmt>> {
|
||||
// consume the print keyword
|
||||
@@ -441,12 +415,12 @@ impl Parser {
|
||||
source_slice,
|
||||
}) => {
|
||||
if message == "Expect expression." {
|
||||
AstNode {
|
||||
node: Expr::Literal {
|
||||
AstNode::new(
|
||||
Expr::Literal {
|
||||
value: BaseValue::Nil,
|
||||
},
|
||||
source_slice: start_slice.clone(),
|
||||
}
|
||||
start_slice.clone(),
|
||||
)
|
||||
} else {
|
||||
return Err(LoxError::ParseError {
|
||||
message,
|
||||
@@ -479,7 +453,34 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn expression(&mut self) -> LoxResult<AstNode<Expr>> {
|
||||
self.or_and()
|
||||
self.assignment()
|
||||
}
|
||||
|
||||
fn assignment(&mut self) -> LoxResult<AstNode<Expr>> {
|
||||
let expr = self.or_and()?;
|
||||
if self.peek().token_type == TokenType::Equal {
|
||||
self.advance(); // consume '='
|
||||
// Right-associative: `a = b = c` parses as `a = (b = c)`.
|
||||
let value = self.assignment()?;
|
||||
let combined_slice = SourceSlice::from_positions(
|
||||
expr.source_slice.source_id,
|
||||
expr.source_slice.start_position.clone(),
|
||||
value.source_slice.end_position.clone(),
|
||||
);
|
||||
let target_slice = expr.source_slice.clone();
|
||||
match expr.node {
|
||||
Expr::Identifier { name } => Ok(AstNode::new(
|
||||
Expr::Assign {
|
||||
name,
|
||||
value: Box::new(value),
|
||||
},
|
||||
combined_slice,
|
||||
)),
|
||||
_ => parse_error(target_slice, "Invalid assignment target."),
|
||||
}
|
||||
} else {
|
||||
Ok(expr)
|
||||
}
|
||||
}
|
||||
|
||||
fn or_and(&mut self) -> LoxResult<AstNode<Expr>> {
|
||||
@@ -978,8 +979,11 @@ mod tests {
|
||||
fn parses_assignment_statement() {
|
||||
let stmts = parse_ok("x = 5;");
|
||||
match &stmts[0].node {
|
||||
Stmt::VarAssigment { name, .. } => assert_eq!(name, "x"),
|
||||
other => panic!("expected assignment statement, got {:?}", other),
|
||||
Stmt::Expression { expression, .. } => match &expression.node {
|
||||
Expr::Assign { name, .. } => assert_eq!(name, "x"),
|
||||
other => panic!("expected assign expression, got {:?}", other),
|
||||
},
|
||||
other => panic!("expected expression statement, got {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user