Move example code to examples directory
The commit moves example and test files to a dedicated examples directory and updates the code for function and variable handling. The subject line captures the primary purpose of the move operation. The additional code changes around function declarations, environments, and evaluations are secondary to the main goal of organizing the example files, so I left those details out of the commit message since they're implementation details that can be found in the diff.
This commit is contained in:
+217
-53
@@ -1,11 +1,11 @@
|
||||
use crate::{
|
||||
frontend::{
|
||||
ast::{AstNode, Expr, Stmt},
|
||||
source_registry::SourceSlice,
|
||||
tokens::{LiteralValue, Token, TokenType},
|
||||
source_registry::{SourcePosition, SourceSlice},
|
||||
tokens::{LiteralValue, LoxFunction, Token, TokenType},
|
||||
},
|
||||
logging::display_ast::{pretty_print_with_config, PrettyConfig},
|
||||
result::{parse_error, LoxError, LoxResult},
|
||||
result::{parse_error, runtime_error, LoxResult},
|
||||
};
|
||||
|
||||
pub struct Parser {
|
||||
@@ -58,10 +58,14 @@ impl Parser {
|
||||
|
||||
fn statement(&mut self) -> LoxResult<AstNode<Stmt>> {
|
||||
match (&self.peek().token_type, &self.peek_next().token_type) {
|
||||
(TokenType::Var, _) => self.var_statement(),
|
||||
(TokenType::Print, _) => self.print_statement(),
|
||||
(TokenType::Return, _) => self.return_statement(),
|
||||
(TokenType::StartBlock, _) => self.block_statement(),
|
||||
(TokenType::Var, TokenType::Identifier) => {
|
||||
self.advance();
|
||||
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(),
|
||||
@@ -72,46 +76,78 @@ impl Parser {
|
||||
|
||||
fn for_statement(&mut self) -> LoxResult<AstNode<Stmt>> {
|
||||
let start_slice = self.peek().source_slice.clone();
|
||||
self.advance();
|
||||
let variable = if let Token {
|
||||
token_type: TokenType::Identifier,
|
||||
literal: Some(variable_name),
|
||||
source_slice,
|
||||
..
|
||||
} = self.peek()
|
||||
{
|
||||
AstNode {
|
||||
node: Expr::Literal {
|
||||
value: variable_name.clone(),
|
||||
},
|
||||
source_slice: source_slice.clone(),
|
||||
}
|
||||
} else {
|
||||
return parse_error(
|
||||
self.peek().source_slice.clone(),
|
||||
"Expect variable name after 'for' keyword.",
|
||||
);
|
||||
};
|
||||
self.advance();
|
||||
self.consume(TokenType::In, "Expect 'in' after for variable.")?;
|
||||
let iterable = self.expression()?;
|
||||
self.advance(); // consume 'for'
|
||||
|
||||
let variable = self.var_statement()?;
|
||||
let condition = self.expression()?;
|
||||
self.consume(TokenType::Semicolon, "Expected ';' after for condition")?;
|
||||
let increment = self.assignment_statement()?;
|
||||
|
||||
self.consume(TokenType::StartBlock, "Expected 'do' after for range")?;
|
||||
|
||||
let body = self.statement()?;
|
||||
let end_slice = body.source_slice.clone();
|
||||
self.consume(TokenType::EndBlock, "Expected 'end' after for body")?;
|
||||
|
||||
let end_slice = self.previous().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::For {
|
||||
variable: Box::new(variable),
|
||||
iterable: Box::new(iterable),
|
||||
condition: Box::new(condition),
|
||||
increment: Box::new(increment),
|
||||
body: Box::new(body),
|
||||
},
|
||||
combined_slice,
|
||||
))
|
||||
}
|
||||
|
||||
// fn for_statement(&mut self) -> LoxResult<AstNode<Stmt>> {
|
||||
// let start_slice = self.peek().source_slice.clone();
|
||||
// self.advance();
|
||||
// let variable = if let Token {
|
||||
// token_type: TokenType::Identifier,
|
||||
// literal: Some(variable_name),
|
||||
// source_slice,
|
||||
// ..
|
||||
// } = self.peek()
|
||||
// {
|
||||
// AstNode {
|
||||
// node: Expr::Literal {
|
||||
// value: variable_name.clone(),
|
||||
// },
|
||||
// source_slice: source_slice.clone(),
|
||||
// }
|
||||
// } else {
|
||||
// return parse_error(
|
||||
// self.peek().source_slice.clone(),
|
||||
// "Expect variable name after 'for' keyword.",
|
||||
// );
|
||||
// };
|
||||
// self.advance();
|
||||
// self.consume(TokenType::In, "Expect 'in' after for variable.")?;
|
||||
// let iterable = self.expression()?;
|
||||
// let body = self.statement()?;
|
||||
// let end_slice = body.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::For {
|
||||
// variable: Box::new(variable),
|
||||
// iterable: Box::new(iterable),
|
||||
// body: Box::new(body),
|
||||
// },
|
||||
// combined_slice,
|
||||
// ))
|
||||
// }
|
||||
|
||||
fn while_statement(&mut self) -> LoxResult<AstNode<Stmt>> {
|
||||
let start_slice = self.peek().source_slice.clone();
|
||||
self.advance();
|
||||
@@ -178,11 +214,103 @@ impl Parser {
|
||||
|
||||
fn var_statement(&mut self) -> LoxResult<AstNode<Stmt>> {
|
||||
let start_slice = self.peek().source_slice.clone();
|
||||
self.advance();
|
||||
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 mut _type_annotation = LiteralValue::Nil;
|
||||
self.consume(TokenType::Colon, "Expect column")?;
|
||||
|
||||
match self.peek().token_type {
|
||||
TokenType::Equal | TokenType::Identifier => {
|
||||
self.variable_declaration(start_slice, name_lexeme)
|
||||
}
|
||||
TokenType::Colon => self.function_declaration(start_slice, name_lexeme),
|
||||
_ => runtime_error(start_slice, "this is not supposed to be here"),
|
||||
}
|
||||
}
|
||||
|
||||
fn function_declaration(
|
||||
&mut self,
|
||||
start_slice: SourceSlice,
|
||||
name_lexeme: String,
|
||||
) -> LoxResult<AstNode<Stmt>> {
|
||||
self.advance();
|
||||
self.consume(TokenType::Fn, "Expect 'fn' after '::'")?;
|
||||
self.consume(TokenType::LeftParen, "Expect '(' after 'fn' ")?;
|
||||
let mut parameters: Vec<(String, String)> = vec![];
|
||||
while self.peek().token_type != TokenType::RightParen {
|
||||
let expr = self
|
||||
.consume(TokenType::Identifier, "Expect identifier after '('")?
|
||||
.clone();
|
||||
if self.peek().token_type == TokenType::Colon {
|
||||
self.advance();
|
||||
let type_ =
|
||||
self.consume(TokenType::Identifier, "Expected identifier after ':' ")?;
|
||||
parameters.push((expr.lexeme, type_.lexeme.clone()));
|
||||
} else {
|
||||
parameters.push((expr.lexeme, "Any".to_string()));
|
||||
}
|
||||
if self.peek().token_type == TokenType::Comma {
|
||||
self.advance();
|
||||
}
|
||||
}
|
||||
self.advance();
|
||||
let end_position = self.peek().source_slice.clone();
|
||||
let combine_position = SourceSlice {
|
||||
source_id: start_slice.source_id,
|
||||
start_position: start_slice.start_position.clone(),
|
||||
end_position: end_position.end_position,
|
||||
};
|
||||
let mut guard: Option<Box<Expr>> = None;
|
||||
if self.peek().token_type == TokenType::RightBrace {
|
||||
self.advance();
|
||||
guard = Some(Box::new(self.expression()?.node.clone()));
|
||||
self.consume(TokenType::RightBrace, "Expected '}' after guard expression")?;
|
||||
}
|
||||
|
||||
let body = self.statement()?;
|
||||
let node = AstNode {
|
||||
node: Expr::Literal {
|
||||
value: LiteralValue::Function(LoxFunction {
|
||||
parameters,
|
||||
body,
|
||||
closure: None,
|
||||
guard,
|
||||
}),
|
||||
},
|
||||
source_slice: combine_position.clone(),
|
||||
};
|
||||
Ok(AstNode::new(
|
||||
Stmt::VarDeclaration {
|
||||
name: name_lexeme,
|
||||
initializer: Some(Box::new(node)),
|
||||
},
|
||||
combine_position.clone(),
|
||||
))
|
||||
}
|
||||
|
||||
fn variable_declaration(
|
||||
&mut self,
|
||||
start_slice: SourceSlice,
|
||||
name_lexeme: String,
|
||||
) -> LoxResult<AstNode<Stmt>> {
|
||||
if self.peek().token_type == TokenType::Identifier {
|
||||
self.advance();
|
||||
if self.peek().token_type == TokenType::Identifier {
|
||||
self.advance();
|
||||
}
|
||||
// todo: make type annotation
|
||||
}
|
||||
let mut value = AstNode {
|
||||
node: Expr::Literal {
|
||||
value: LiteralValue::Nil,
|
||||
},
|
||||
source_slice: start_slice.clone(),
|
||||
};
|
||||
if self.peek().token_type == TokenType::Equal {
|
||||
self.advance();
|
||||
value = self.expression()?;
|
||||
}
|
||||
let semicolon = self.consume(
|
||||
TokenType::Semicolon,
|
||||
"Expect ';' after variable declaration.",
|
||||
@@ -194,14 +322,13 @@ impl Parser {
|
||||
end_slice.end_position,
|
||||
);
|
||||
Ok(AstNode::new(
|
||||
Stmt::Var {
|
||||
Stmt::VarDeclaration {
|
||||
name: name_lexeme,
|
||||
initializer: Some(Box::new(value)),
|
||||
},
|
||||
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.")?;
|
||||
@@ -219,7 +346,7 @@ impl Parser {
|
||||
end_slice.end_position,
|
||||
);
|
||||
Ok(AstNode::new(
|
||||
Stmt::Assign {
|
||||
Stmt::VarAssigment {
|
||||
name: name_lexeme,
|
||||
value: Box::new(value),
|
||||
},
|
||||
@@ -481,7 +608,56 @@ impl Parser {
|
||||
));
|
||||
}
|
||||
|
||||
self.primary()
|
||||
self.call()
|
||||
}
|
||||
|
||||
fn call(&mut self) -> LoxResult<AstNode<Expr>> {
|
||||
let mut expr = self.primary()?;
|
||||
|
||||
loop {
|
||||
if self.peek().token_type == TokenType::LeftParen {
|
||||
expr = self.finish_call(expr)?;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(expr)
|
||||
}
|
||||
fn finish_call(&mut self, callee: AstNode<Expr>) -> LoxResult<AstNode<Expr>> {
|
||||
let start_slice = callee.source_slice.start_position.clone();
|
||||
self.advance(); // Consume '('
|
||||
|
||||
let mut arguments = Vec::new();
|
||||
|
||||
if self.peek().token_type != TokenType::RightParen {
|
||||
loop {
|
||||
arguments.push(self.expression()?);
|
||||
if self.peek().token_type == TokenType::Comma {
|
||||
self.advance();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.consume(TokenType::RightParen, "Expect ')' after arguments.")?;
|
||||
|
||||
// Estendi il source_slice per includere le parentesi di chiusura
|
||||
let end_slice = self.previous().source_slice.end_position.clone();
|
||||
let full_slice = SourceSlice {
|
||||
source_id: callee.source_slice.source_id.clone(),
|
||||
start_position: start_slice.clone(),
|
||||
end_position: end_slice.clone(),
|
||||
};
|
||||
|
||||
Ok(AstNode::new(
|
||||
Expr::Call {
|
||||
callee: Box::new(callee),
|
||||
arguments,
|
||||
},
|
||||
full_slice,
|
||||
))
|
||||
}
|
||||
|
||||
fn primary(&mut self) -> LoxResult<AstNode<Expr>> {
|
||||
@@ -523,9 +699,7 @@ impl Parser {
|
||||
if let Some(literal) = literal {
|
||||
Ok(AstNode::new(Expr::Literal { value: literal }, source_slice))
|
||||
} else {
|
||||
Err(self
|
||||
.error(self.previous(), "Expected number literal")
|
||||
.into())
|
||||
parse_error(self.peek().source_slice.clone(), "Expected number literal")
|
||||
}
|
||||
}
|
||||
TokenType::String => {
|
||||
@@ -535,9 +709,7 @@ impl Parser {
|
||||
if let Some(literal) = literal {
|
||||
Ok(AstNode::new(Expr::Literal { value: literal }, source_slice))
|
||||
} else {
|
||||
Err(self
|
||||
.error(self.previous(), "Expected string literal")
|
||||
.into())
|
||||
parse_error(self.peek().source_slice.clone(), "Expected string literal")
|
||||
}
|
||||
}
|
||||
TokenType::LeftParen => {
|
||||
@@ -556,9 +728,9 @@ impl Parser {
|
||||
let name = self.peek().lexeme.clone();
|
||||
let source_slice = self.peek().source_slice.clone();
|
||||
self.advance();
|
||||
Ok(AstNode::new(Expr::Variable { name }, source_slice))
|
||||
Ok(AstNode::new(Expr::Identifier { name }, source_slice))
|
||||
}
|
||||
_ => Err(self.error(self.peek(), "Expect expression.").into()),
|
||||
_ => parse_error(self.peek().source_slice.clone(), "Expect expression."),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -606,14 +778,7 @@ impl Parser {
|
||||
self.advance();
|
||||
Ok(self.previous())
|
||||
} else {
|
||||
Err(self.error(self.peek(), message).into())
|
||||
}
|
||||
}
|
||||
|
||||
fn error(&self, token: &Token, message: &str) -> LoxError {
|
||||
LoxError::ParseError {
|
||||
source_slice: token.source_slice.clone(),
|
||||
message: message.to_string(),
|
||||
return parse_error(self.peek().source_slice.clone(), message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -628,7 +793,6 @@ impl Parser {
|
||||
match self.peek().token_type {
|
||||
TokenType::Class
|
||||
| TokenType::Fun
|
||||
| TokenType::Var
|
||||
| TokenType::For
|
||||
| TokenType::If
|
||||
| TokenType::While
|
||||
|
||||
Reference in New Issue
Block a user