Switch interpreter to use new base value types
The commit changes the interpreter and related code to use the new `BaeValue` and `Number` types, moving away from direct floats. The main changes include: - Replace LiteralValue with BaeValue across the codebase - Add Number enum for type-safe numeric values - Move AST definitions to common module - Update operators to handle new numeric types - Add 'is' token type and parser support Switch to common base_value library for value types This commit represents a significant refactoring to switch the interpreter to use a new shared base value type system. The main changes include: 1. Move value types to a new common/base_value.rs module 2. Add richer numeric type support with promotion rules 3. Update interpreter to use new BaseValue enum 4. Move AST types to common module for sharing 5. Consolidate value operations like Add, Sub etc 6. Add proper test coverage for numeric operations The commit improves type safety and adds more robust numeric handling while keeping the interpreter's core logic clean.
This commit is contained in:
@@ -1,344 +0,0 @@
|
||||
use crate::frontend::{
|
||||
source_registry::SourceSlice,
|
||||
tokens::{LiteralValue, TokenType},
|
||||
};
|
||||
use std::fmt::{Debug, Display};
|
||||
/*
|
||||
* grammar:
|
||||
* program -> statement* EOF
|
||||
* statement -> expression_statement
|
||||
* | print_statement
|
||||
* | var_statement
|
||||
* | block_statement
|
||||
* | assignment_statement
|
||||
* | if_statement
|
||||
*
|
||||
* expression_statement -> expression ";"
|
||||
* print_statement -> "print" expression ";"
|
||||
* var_statement -> ("var")? IDENTIFIER (":" IDENTIFIER)? (("=" expression)? ";")| function_declaration
|
||||
* function_declaration -> "::" "(" parameters? ")" ("->" IDENTIFIER)? block_statement
|
||||
* parameters -> ( IDENTIFIER (":" IDENTIFIER)? ("," IDENTIFIER (":" IDENTIFIER)? )* )
|
||||
* assignment_statement -> IDENTIFIER "=" expression ";"
|
||||
* block_statement -> "do" statement* "end"
|
||||
* if_statement -> "if" expression "then" statement ("elif" expression "then" statement)* ("else" statement)? "end"
|
||||
* while_statement -> "while" expression "do" statement "end"
|
||||
*
|
||||
* expression -> assignment
|
||||
* assignment -> IDENTIFIER "=" assignment | logical_or
|
||||
* logical_or -> logical_and (("or" logical_and)*
|
||||
* logical_and -> equality (("and" equality)*
|
||||
* equality -> comparison (("==" | "!=") comparison)*
|
||||
* comparison -> term ((">" | ">=" | "<" | "<=") term)*
|
||||
* term -> factor (("+" | "-") factor)*
|
||||
* factor -> unary (("*" | "/") unary)*
|
||||
* unary -> ("!" | "-") unary | call
|
||||
* call -> primary ("(" arguments ")")*
|
||||
* arguments -> expression ("," expression)*
|
||||
* primary -> NUMBER | STRING | "true" | "false" | "nil" | "(" expression ")" | IDENTIFIER
|
||||
*/
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum Expr {
|
||||
Literal {
|
||||
value: LiteralValue,
|
||||
},
|
||||
Binary {
|
||||
left: Box<AstNode<Expr>>,
|
||||
operator: TokenType,
|
||||
right: Box<AstNode<Expr>>,
|
||||
},
|
||||
Unary {
|
||||
operator: TokenType,
|
||||
operand: Box<AstNode<Expr>>,
|
||||
},
|
||||
Grouping {
|
||||
expression: Box<AstNode<Expr>>,
|
||||
},
|
||||
Identifier {
|
||||
name: String,
|
||||
},
|
||||
Call {
|
||||
callee: Box<AstNode<Expr>>,
|
||||
arguments: Vec<AstNode<Expr>>,
|
||||
},
|
||||
}
|
||||
|
||||
// Implementazione Display per Expr (per debugging)
|
||||
impl std::fmt::Display for Expr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Expr::Literal { value } => write!(f, "Literal {}", value),
|
||||
Expr::Binary {
|
||||
left,
|
||||
operator,
|
||||
right,
|
||||
} => write!(f, "Binary ({} {} {})", left.node, operator, right.node),
|
||||
Expr::Unary { operator, operand } => write!(f, "Unary ({} {})", operator, operand.node),
|
||||
Expr::Grouping { expression } => write!(f, "Grouping (group {})", expression.node),
|
||||
Expr::Identifier { name } => write!(f, "Identifier (variable {})", name),
|
||||
Expr::Call { callee, arguments } => write!(
|
||||
f,
|
||||
"Call ({}({}))",
|
||||
callee.node,
|
||||
arguments
|
||||
.iter()
|
||||
.map(|arg| arg.node.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Expr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Expr::Literal { value } => write!(f, "{:?}", value),
|
||||
Expr::Binary {
|
||||
left,
|
||||
operator,
|
||||
right,
|
||||
} => write!(f, "({:?} {:?} {:?})", operator, left.node, right.node),
|
||||
Expr::Unary { operator, operand } => write!(f, "({:?} {:?})", operator, operand.node),
|
||||
Expr::Grouping { expression } => write!(f, "(group {:?})", expression.node),
|
||||
Expr::Identifier { name } => write!(f, "(variable {:?})", name),
|
||||
Expr::Call { callee, arguments } => write!(
|
||||
f,
|
||||
"Call ({}({}))",
|
||||
callee.node,
|
||||
arguments
|
||||
.iter()
|
||||
.map(|arg| arg.node.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum Stmt {
|
||||
Expression {
|
||||
expression: Box<AstNode<Expr>>,
|
||||
},
|
||||
Print {
|
||||
expression: Box<AstNode<Expr>>,
|
||||
},
|
||||
Stmt {
|
||||
expression: Box<AstNode<Expr>>,
|
||||
},
|
||||
VarDeclaration {
|
||||
name: String,
|
||||
initializer: Option<Box<AstNode<Expr>>>,
|
||||
},
|
||||
VarAssigment {
|
||||
name: String,
|
||||
value: Box<AstNode<Expr>>,
|
||||
},
|
||||
Return {
|
||||
expression: Box<AstNode<Expr>>,
|
||||
},
|
||||
Block {
|
||||
statements: Box<Vec<AstNode<Stmt>>>,
|
||||
},
|
||||
If {
|
||||
condition: Box<AstNode<Expr>>,
|
||||
then_branch: Box<AstNode<Stmt>>,
|
||||
elif_branch: Vec<(Box<AstNode<Expr>>, Box<AstNode<Stmt>>)>,
|
||||
else_branch: Option<Box<AstNode<Stmt>>>,
|
||||
},
|
||||
While {
|
||||
condition: Box<AstNode<Expr>>,
|
||||
body: Box<AstNode<Stmt>>,
|
||||
},
|
||||
For {
|
||||
variable: Box<AstNode<Stmt>>,
|
||||
condition: Box<AstNode<Expr>>,
|
||||
increment: Box<AstNode<Stmt>>,
|
||||
body: Box<AstNode<Stmt>>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Display for Stmt {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Stmt::Expression { expression } => write!(f, "Expression ({})", expression.node),
|
||||
Stmt::If {
|
||||
condition,
|
||||
then_branch,
|
||||
elif_branch,
|
||||
else_branch,
|
||||
} => {
|
||||
let mut result = format!("IF ({}) {{\n{}\n}}", condition.node, then_branch.node);
|
||||
for (condition, branch) in elif_branch {
|
||||
result.push_str(&format!(
|
||||
" ELIF ({}) {{\n{}\n}}",
|
||||
condition.node, branch.node
|
||||
));
|
||||
}
|
||||
if let Some(else_branch) = else_branch {
|
||||
result.push_str(&format!(" ELSE {{\n{}\n}}", else_branch.node));
|
||||
}
|
||||
write!(f, "IfStmt {}", result)
|
||||
}
|
||||
Stmt::Print { expression } => write!(f, "Print({});", expression.node),
|
||||
Stmt::Stmt { expression } => write!(f, "Stmt({});", expression.node),
|
||||
Stmt::VarDeclaration { name, initializer } => match initializer {
|
||||
Some(init) => write!(f, "Var({} = {});", name, init.node),
|
||||
None => write!(f, "Var({});", name),
|
||||
},
|
||||
Stmt::VarAssigment { name, value } => write!(f, "Assign({} = {});", name, value.node),
|
||||
Stmt::Return { expression } => write!(f, "Return({});", expression.node),
|
||||
Stmt::Block { statements } => write!(
|
||||
f,
|
||||
"Block([\n{}\n])",
|
||||
statements
|
||||
.iter()
|
||||
.map(|stmt| format!("\t \t{}", stmt.node))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
),
|
||||
Stmt::While { condition, body } => {
|
||||
write!(f, "While({}) {{\n{}\n}}", condition.node, body.node)
|
||||
}
|
||||
Stmt::For {
|
||||
variable,
|
||||
condition,
|
||||
increment,
|
||||
body,
|
||||
} => write!(
|
||||
f,
|
||||
"For({} = {} in {}) {{\n{}\n}}",
|
||||
variable.node, condition.node, increment.node, body.node
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Stmt {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Stmt::Expression { expression } => write!(f, " Expression ({:?})", expression.node),
|
||||
Stmt::If {
|
||||
condition,
|
||||
then_branch,
|
||||
elif_branch,
|
||||
else_branch,
|
||||
} => {
|
||||
let mut result =
|
||||
format!("IF ({:?}) {{\n{:?}\n}}", condition.node, then_branch.node);
|
||||
for (condition, branch) in elif_branch {
|
||||
result.push_str(&format!(
|
||||
" ELIF ({:?}) {{\n{:?}\n}}",
|
||||
condition.node, branch.node
|
||||
));
|
||||
}
|
||||
if let Some(else_branch) = else_branch {
|
||||
result.push_str(&format!(" ELSE {{\n{:?}\n}}", else_branch.node));
|
||||
}
|
||||
write!(f, "IfStmt {:?}", result)
|
||||
}
|
||||
Stmt::Print { expression } => write!(f, "Print({:?});", expression.node),
|
||||
Stmt::Stmt { expression } => write!(f, "Stmt({:?});", expression.node),
|
||||
Stmt::VarDeclaration { name, initializer } => match initializer {
|
||||
Some(init) => write!(f, "Var({:?} = {:?});", name, init.node),
|
||||
None => write!(f, "Var({:?});", name),
|
||||
},
|
||||
Stmt::VarAssigment { name, value } => {
|
||||
write!(f, "Assign({:?} = {:?});", name, value.node)
|
||||
}
|
||||
Stmt::Return { expression } => write!(f, "Return({:?});", expression.node),
|
||||
Stmt::Block { statements } => write!(
|
||||
f,
|
||||
"Block([\n{:?}\n])",
|
||||
statements
|
||||
.iter()
|
||||
.map(|stmt| format!("{:?}", stmt.node))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\t\t\n")
|
||||
),
|
||||
Stmt::While { condition, body } => {
|
||||
write!(f, "While({:?}) {{\n{:?}\n}}", condition.node, body.node)
|
||||
}
|
||||
Stmt::For {
|
||||
variable,
|
||||
condition,
|
||||
increment,
|
||||
body,
|
||||
} => write!(
|
||||
f,
|
||||
"For({:?} = {:?} in {:?}) {{\n{:?}\n}}",
|
||||
variable.node, condition.node, increment.node, body.node
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AstNodeKind {
|
||||
fn kind(&self) -> &'static str;
|
||||
}
|
||||
|
||||
impl AstNodeKind for Expr {
|
||||
fn kind(&self) -> &'static str {
|
||||
match self {
|
||||
Expr::Literal { value: _ } => "literal",
|
||||
Expr::Binary {
|
||||
left: _,
|
||||
operator: _,
|
||||
right: _,
|
||||
} => "binary expression",
|
||||
Expr::Unary { .. } => "unary expression",
|
||||
Expr::Grouping { .. } => "grouping expression",
|
||||
Expr::Identifier { .. } => "variable expression",
|
||||
Expr::Call { .. } => "call expression",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AstNodeKind for Stmt {
|
||||
fn kind(&self) -> &'static str {
|
||||
match self {
|
||||
Stmt::Expression { .. } => "expression",
|
||||
Stmt::VarDeclaration { .. } => "variable declaration",
|
||||
Stmt::VarAssigment { .. } => "assignment",
|
||||
Stmt::Return { .. } => "return statement",
|
||||
Stmt::Block { .. } => "block statement",
|
||||
Stmt::If { .. } => "if statement",
|
||||
Stmt::Print { .. } => "print statement",
|
||||
Stmt::Stmt { .. } => "statement",
|
||||
Stmt::While { .. } => "while statement",
|
||||
Stmt::For { .. } => "for statement",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Default)]
|
||||
pub struct AstNode<T: AstNodeKind + Debug + Display> {
|
||||
pub node: T,
|
||||
pub source_slice: SourceSlice,
|
||||
}
|
||||
|
||||
impl<T: AstNodeKind + Debug + Display> Display for AstNode<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"AstNode \n{{ \n\tnode: {},\n\tsource_slice: {}, \n}}",
|
||||
self.node, self.source_slice
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AstNodeKind + Debug + Display> Debug for AstNode<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"AstNode \n{{ \n\tnode: {:?},\n\tsource_slice: {:?}, \n}}",
|
||||
self.node, self.source_slice
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AstNodeKind + Debug + Display> AstNode<T> {
|
||||
pub fn new(node: T, source_slice: SourceSlice) -> Self {
|
||||
AstNode { node, source_slice }
|
||||
}
|
||||
}
|
||||
+63
-28
@@ -1,7 +1,7 @@
|
||||
use crate::common::base_value::{BaseValue, Number};
|
||||
use crate::common::lox_result::{lexical_error, LoxError, LoxResult};
|
||||
use crate::frontend::source_registry::{SourceId, SourcePosition, SourceSlice};
|
||||
use crate::frontend::tokens::{LiteralValue, Token, TokenType};
|
||||
use crate::logging::display_token::TokenPrettyPrintExt;
|
||||
use crate::result::{LoxError, LoxResult};
|
||||
use crate::frontend::tokens::{Token, TokenType};
|
||||
|
||||
pub struct Lexer {
|
||||
input: String,
|
||||
@@ -77,8 +77,6 @@ impl Lexer {
|
||||
}
|
||||
}
|
||||
tokens.push(self.make_token(TokenType::Eof));
|
||||
println!("Tokens:");
|
||||
tokens.iter().for_each(|val| println!("{}", val.pretty()));
|
||||
Ok(tokens)
|
||||
}
|
||||
|
||||
@@ -119,7 +117,7 @@ impl Lexer {
|
||||
),
|
||||
)
|
||||
}
|
||||
fn make_token_with_literal(&self, token_type: TokenType, literal: LiteralValue) -> Token {
|
||||
fn make_token_with_literal(&self, token_type: TokenType, literal: BaseValue) -> Token {
|
||||
let text = self.input[self.start_char..self.current_char].to_string();
|
||||
Token::new_complete(
|
||||
token_type,
|
||||
@@ -186,14 +184,14 @@ impl Lexer {
|
||||
self.advance();
|
||||
}
|
||||
if self.is_at_end() {
|
||||
return Err(LoxError::LexicalError {
|
||||
source_slice: SourceSlice::from_positions(
|
||||
return lexical_error(
|
||||
SourceSlice::from_positions(
|
||||
self.source_id.clone(),
|
||||
self.start_pos.clone(),
|
||||
self.end_pos.clone(),
|
||||
),
|
||||
message: "Unterminated comment".to_string(),
|
||||
});
|
||||
"Unterminated comment".to_string(),
|
||||
);
|
||||
} else {
|
||||
self.advance(); // consuma '*'
|
||||
self.advance(); // consuma '/'
|
||||
@@ -237,30 +235,67 @@ impl Lexer {
|
||||
self.advance();
|
||||
Ok(Some(self.make_token_with_literal(
|
||||
TokenType::String,
|
||||
LiteralValue::String(self.input[self.start_char..self.current_char].to_string()),
|
||||
BaseValue::String(self.input[self.start_char..self.current_char].to_string()),
|
||||
)))
|
||||
}
|
||||
|
||||
fn number(&mut self) -> LoxResult<Option<Token>> {
|
||||
// Leggi la parte intera
|
||||
while self.peek().is_digit(10) {
|
||||
self.advance();
|
||||
}
|
||||
if self.peek() == '.' && self.peek_next().is_digit(10) {
|
||||
self.advance();
|
||||
|
||||
// Controlla se c'è una parte decimale
|
||||
let has_decimal = if self.peek() == '.' && self.peek_next().is_digit(10) {
|
||||
self.advance(); // consuma il '.'
|
||||
while self.peek().is_digit(10) {
|
||||
self.advance();
|
||||
}
|
||||
}
|
||||
Ok(Some(
|
||||
self.make_token_with_literal(
|
||||
TokenType::Number,
|
||||
LiteralValue::Number(
|
||||
self.input[self.start_char..self.current_char]
|
||||
.parse()
|
||||
.unwrap(),
|
||||
),
|
||||
),
|
||||
))
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// Controlla se c'è un suffisso (f o u)
|
||||
let suffix = if self.peek() == 'f' || self.peek() == 'u' {
|
||||
let s = self.peek();
|
||||
self.advance();
|
||||
Some(s)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let num_str = &self.input[self.start_char..self.current_char];
|
||||
let num_str_without_suffix = if suffix.is_some() {
|
||||
&num_str[..num_str.len() - 1]
|
||||
} else {
|
||||
num_str
|
||||
};
|
||||
|
||||
// Determina il tipo di numero basandosi sul contenuto e suffisso
|
||||
let number_value = match suffix {
|
||||
Some('f') => {
|
||||
// Float esplicito con suffisso 'f'
|
||||
Number::F64(num_str_without_suffix.parse().unwrap())
|
||||
}
|
||||
Some('u') => {
|
||||
// Unsigned esplicito con suffisso 'u'
|
||||
Number::U128(num_str_without_suffix.parse().unwrap())
|
||||
}
|
||||
_ if has_decimal => {
|
||||
// Float implicito (contiene un punto decimale)
|
||||
Number::F64(num_str.parse().unwrap())
|
||||
}
|
||||
_ => {
|
||||
// Intero con segno di default
|
||||
Number::I32(num_str.parse().unwrap())
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Some(self.make_token_with_literal(
|
||||
TokenType::Number,
|
||||
BaseValue::Number(number_value),
|
||||
)))
|
||||
}
|
||||
|
||||
fn identifier(&mut self) -> LoxResult<Option<Token>> {
|
||||
@@ -270,18 +305,18 @@ impl Lexer {
|
||||
let text = self.input[self.start_char..self.current_char].to_string();
|
||||
match get_keyword_token(&text) {
|
||||
Some(TokenType::True) => Ok(Some(
|
||||
self.make_token_with_literal(TokenType::True, LiteralValue::Boolean(true)),
|
||||
self.make_token_with_literal(TokenType::True, BaseValue::Boolean(true)),
|
||||
)),
|
||||
Some(TokenType::False) => Ok(Some(
|
||||
self.make_token_with_literal(TokenType::False, LiteralValue::Boolean(false)),
|
||||
self.make_token_with_literal(TokenType::False, BaseValue::Boolean(false)),
|
||||
)),
|
||||
Some(TokenType::Nil) => Ok(Some(
|
||||
self.make_token_with_literal(TokenType::Nil, LiteralValue::Nil),
|
||||
self.make_token_with_literal(TokenType::Nil, BaseValue::Nil),
|
||||
)),
|
||||
Some(token_type) => Ok(Some(self.make_token(token_type))),
|
||||
None => Ok(Some(self.make_token_with_literal(
|
||||
TokenType::Identifier,
|
||||
LiteralValue::String(text.clone()),
|
||||
BaseValue::String(text.clone()),
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
pub mod ast;
|
||||
pub mod lexer;
|
||||
pub mod parser;
|
||||
pub mod source_registry;
|
||||
|
||||
+47
-31
@@ -1,11 +1,13 @@
|
||||
use crate::{
|
||||
frontend::{
|
||||
common::{
|
||||
ast::{AstNode, Expr, Stmt},
|
||||
source_registry::{SourcePosition, SourceSlice},
|
||||
tokens::{LiteralValue, LoxFunction, Token, TokenType},
|
||||
base_value::{BaseValue, LoxFunction},
|
||||
lox_result::{parse_error, runtime_error, LoxResult},
|
||||
},
|
||||
frontend::{
|
||||
source_registry::SourceSlice,
|
||||
tokens::{Token, TokenType},
|
||||
},
|
||||
logging::display_ast::{pretty_print_with_config, PrettyConfig},
|
||||
result::{parse_error, runtime_error, LoxResult},
|
||||
};
|
||||
|
||||
pub struct Parser {
|
||||
@@ -21,30 +23,14 @@ impl Parser {
|
||||
pub fn parse(&mut self) -> LoxResult<Vec<AstNode<Stmt>>> {
|
||||
let mut statements = Vec::new();
|
||||
let mut errors = Vec::new();
|
||||
println!("\n \n ++++++++++++++++++++++++++++++++++++\nStarting parsing");
|
||||
// Con configurazione personalizzata
|
||||
let config = PrettyConfig {
|
||||
indent: " ".to_string(),
|
||||
max_depth: None,
|
||||
show_positions: false,
|
||||
..Default::default()
|
||||
};
|
||||
while !self.is_at_end() {
|
||||
match self.statement() {
|
||||
Ok(stmt) => {
|
||||
println!(
|
||||
"Parsed Successfully: {}",
|
||||
pretty_print_with_config(&stmt.node, &config)
|
||||
);
|
||||
|
||||
statements.push(stmt.clone());
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
errors.push(err);
|
||||
let old_current = self.current;
|
||||
self.synchronize();
|
||||
println!("Synchronized from {} to {}", old_current, self.current);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,7 +203,7 @@ impl Parser {
|
||||
let name = self.consume(TokenType::Identifier, "Expect variable name.")?;
|
||||
let name_lexeme = name.lexeme.clone();
|
||||
|
||||
let mut _type_annotation = LiteralValue::Nil;
|
||||
let mut _type_annotation = BaseValue::Nil;
|
||||
self.consume(TokenType::Colon, "Expect column")?;
|
||||
|
||||
match self.peek().token_type {
|
||||
@@ -254,16 +240,18 @@ impl Parser {
|
||||
self.advance();
|
||||
}
|
||||
}
|
||||
self.advance();
|
||||
self.consume(TokenType::RightParen, "Expected ')' after parameters")?;
|
||||
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();
|
||||
if self.peek().token_type == TokenType::LeftBrace {
|
||||
self.consume(TokenType::LeftBrace, "Expected '{' after guard expression")?;
|
||||
println!("ho trovato una guradia");
|
||||
guard = Some(Box::new(self.expression()?.node.clone()));
|
||||
self.consume(TokenType::RightBrace, "Expected '}' after guard expression")?;
|
||||
}
|
||||
@@ -271,7 +259,7 @@ impl Parser {
|
||||
let body = self.statement()?;
|
||||
let node = AstNode {
|
||||
node: Expr::Literal {
|
||||
value: LiteralValue::Function(LoxFunction {
|
||||
value: BaseValue::Function(LoxFunction {
|
||||
parameters,
|
||||
body,
|
||||
closure: None,
|
||||
@@ -303,7 +291,7 @@ impl Parser {
|
||||
}
|
||||
let mut value = AstNode {
|
||||
node: Expr::Literal {
|
||||
value: LiteralValue::Nil,
|
||||
value: BaseValue::Nil,
|
||||
},
|
||||
source_slice: start_slice.clone(),
|
||||
};
|
||||
@@ -453,9 +441,36 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn or_and(&mut self) -> LoxResult<AstNode<Expr>> {
|
||||
let mut expr = self.equality()?;
|
||||
let mut expr = self.logical_is()?;
|
||||
|
||||
while [TokenType::Or, TokenType::And].contains(&self.peek().token_type) {
|
||||
let start_slice = expr.source_slice.clone();
|
||||
let operator = self.peek().token_type.clone();
|
||||
self.advance();
|
||||
let right = self.logical_is()?;
|
||||
let end_slice = right.source_slice.clone();
|
||||
let combined_slice = SourceSlice::from_positions(
|
||||
start_slice.source_id,
|
||||
start_slice.start_position,
|
||||
end_slice.end_position,
|
||||
);
|
||||
expr = AstNode::new(
|
||||
Expr::Binary {
|
||||
left: Box::new(expr),
|
||||
operator,
|
||||
right: Box::new(right),
|
||||
},
|
||||
combined_slice,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn logical_is(&mut self) -> LoxResult<AstNode<Expr>> {
|
||||
let mut expr = self.equality()?;
|
||||
|
||||
while self.peek().token_type == TokenType::Is {
|
||||
let start_slice = expr.source_slice.clone();
|
||||
let operator = self.peek().token_type.clone();
|
||||
self.advance();
|
||||
@@ -478,6 +493,7 @@ impl Parser {
|
||||
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn equality(&mut self) -> LoxResult<AstNode<Expr>> {
|
||||
let mut expr = self.comparison()?;
|
||||
|
||||
@@ -667,7 +683,7 @@ impl Parser {
|
||||
self.advance();
|
||||
Ok(AstNode::new(
|
||||
Expr::Literal {
|
||||
value: LiteralValue::Boolean(false),
|
||||
value: BaseValue::Boolean(false),
|
||||
},
|
||||
source_slice,
|
||||
))
|
||||
@@ -677,7 +693,7 @@ impl Parser {
|
||||
self.advance();
|
||||
Ok(AstNode::new(
|
||||
Expr::Literal {
|
||||
value: LiteralValue::Boolean(true),
|
||||
value: BaseValue::Boolean(true),
|
||||
},
|
||||
source_slice,
|
||||
))
|
||||
@@ -687,7 +703,7 @@ impl Parser {
|
||||
self.advance();
|
||||
Ok(AstNode::new(
|
||||
Expr::Literal {
|
||||
value: LiteralValue::Nil,
|
||||
value: BaseValue::Nil,
|
||||
},
|
||||
source_slice,
|
||||
))
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::{
|
||||
io::ErrorKind,
|
||||
};
|
||||
|
||||
use crate::result::{LoxError, LoxResult};
|
||||
use crate::common::lox_result::{io_error, LoxError, LoxResult};
|
||||
|
||||
pub struct SourceRegistry {
|
||||
pub sources: Vec<SourceFile>,
|
||||
@@ -147,7 +147,7 @@ impl SourceRegistry {
|
||||
format!("Failed to read '{}': {}", path, error)
|
||||
}
|
||||
};
|
||||
Err(LoxError::IoError { message: error_msg })
|
||||
io_error(error_msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-64
@@ -1,67 +1,6 @@
|
||||
use std::fmt;
|
||||
|
||||
use crate::{
|
||||
backend::environment::EnvironmentStack,
|
||||
frontend::{
|
||||
ast::{AstNode, Expr, Stmt},
|
||||
source_registry::SourceSlice,
|
||||
},
|
||||
result::{runtime_error, LoxResult},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum LiteralValue {
|
||||
Identifier(String),
|
||||
String(String),
|
||||
Number(f64),
|
||||
Boolean(bool),
|
||||
Nil,
|
||||
Function(LoxFunction),
|
||||
NativeFunction(NativeFunction),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct LoxFunction {
|
||||
pub parameters: Vec<(String, String)>,
|
||||
pub body: AstNode<Stmt>,
|
||||
pub closure: Option<EnvironmentStack>,
|
||||
pub guard: Option<Box<Expr>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct NativeFunction {
|
||||
pub arity: usize,
|
||||
pub function: fn(&[LiteralValue]) -> LiteralValue,
|
||||
}
|
||||
|
||||
impl NativeFunction {
|
||||
pub fn new(arity: usize, function: fn(&[LiteralValue]) -> LiteralValue) -> Self {
|
||||
NativeFunction { arity, function }
|
||||
}
|
||||
}
|
||||
|
||||
impl LiteralValue {
|
||||
pub fn is_callable(&self) -> bool {
|
||||
match self {
|
||||
LiteralValue::Function(..) | LiteralValue::NativeFunction(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for LiteralValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
LiteralValue::Identifier(id) => write!(f, "{}", id),
|
||||
LiteralValue::String(s) => write!(f, "{}", s),
|
||||
LiteralValue::Number(n) => write!(f, "{}", n),
|
||||
LiteralValue::Boolean(b) => write!(f, "{}", b),
|
||||
LiteralValue::Nil => write!(f, "nil"),
|
||||
LiteralValue::Function(..) => write!(f, "<fn lox function>"),
|
||||
LiteralValue::NativeFunction(..) => write!(f, "<native native function>"),
|
||||
}
|
||||
}
|
||||
}
|
||||
use crate::{common::base_value::BaseValue, frontend::source_registry::SourceSlice};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum TokenType {
|
||||
@@ -115,6 +54,7 @@ pub enum TokenType {
|
||||
Nil,
|
||||
Or,
|
||||
In,
|
||||
Is,
|
||||
Print,
|
||||
Return,
|
||||
Super,
|
||||
@@ -178,6 +118,7 @@ impl fmt::Display for TokenType {
|
||||
TokenType::In => write!(f, "in"),
|
||||
TokenType::Colon => write!(f, ":"),
|
||||
TokenType::Fn => write!(f, "fn"),
|
||||
TokenType::Is => write!(f, "is"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,7 +127,7 @@ impl fmt::Display for TokenType {
|
||||
pub struct Token {
|
||||
pub token_type: TokenType,
|
||||
pub lexeme: String,
|
||||
pub literal: Option<LiteralValue>,
|
||||
pub literal: Option<BaseValue>,
|
||||
pub source_slice: SourceSlice,
|
||||
}
|
||||
|
||||
@@ -202,7 +143,7 @@ impl Token {
|
||||
pub fn new_complete(
|
||||
token_type: TokenType,
|
||||
lexeme: String,
|
||||
literal: Option<LiteralValue>,
|
||||
literal: Option<BaseValue>,
|
||||
source_slice: SourceSlice,
|
||||
) -> Self {
|
||||
Token {
|
||||
|
||||
Reference in New Issue
Block a user