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:
Giulio Agostini
2025-10-07 14:28:24 +02:00
parent fa2e9178fb
commit c1ecd7d1f7
17 changed files with 1074 additions and 398 deletions
+63 -28
View File
@@ -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()),
))),
}
}