5 Commits
Author SHA1 Message Date
Giulio Agostini 2d59e748bf wip 2026-07-13 08:14:15 +02:00
fizban 956446c170 wip addin syntax parser 2026-07-13 07:51:24 +02:00
Giulio Agostini 52f0a5b8f1 Wip: struct parsign 2026-07-11 18:01:40 +02:00
Giulio Agostini 84a7bf453f removed waring (have remaind dead code for future feature) 2026-07-07 20:31:23 +02:00
Giulio Agostini 2c3267e8a4 Remove unused imports in parser.rs
Box return values in LoxError

- Box Return.value in LoxError
- Deref boxed value when assigning to ret
- Box value when constructing Return variants
- Update Cargo.toml edition to 2024 and add nightly toolchain
2026-07-07 07:23:44 +02:00
17 changed files with 239 additions and 192 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "rlox" name = "rlox"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2024"
[dependencies] [dependencies]
+52 -10
View File
@@ -2,35 +2,77 @@
* Syntax example: * Syntax example:
#+begin_src #+begin_src
funzione :: fn(parametro1: Number, parametro2: String): String do #this is what a struct delcaration shoul lool like
Point :: struct{
x: Numeric, # btw Numeric in my imagination is a Interface/Trai/Contrato comune to all numberic type
y: Numeric,
}
end Point.new :: fn(x:Numeric, y:Numeric) Self:
return Point{x,y}
Point.sum :: fn(self, other: Point) Self:
return Point{x: self.x+other.x, y: self.y+self.y}
@(entrypoint)
main :: fn(parametro1: Numeric, parametro2: String) Void :
a := Point.new(67, 420)
b := Point.new(42, 47)
a = a.sum(b)
print("par: {},{}", touple(parametro1, parametro2))
if parametro1 == 0:
print("What do you epexted to happen?")
else if parametro1 > 0:
for i in range(0,parametro1,1):
print("{}", parametro2)
else:
for i in range(0,parametro1,-1):
print("{}", parametro2)
range_gen := precook(range, args: [0,parametro1]);
match parametro1 is:
== 0 => print("{}", parametro2),
> 0 => forEach(range_gen(1), |x| print("{}", parametro2)),
< 0 => forEach(range_gen(-1), |x| print("{}", parametro2)),
_ => panic()
match a is:
Point(x > 100, y) => print("YEAAA :)"),
_ => print("NAIH :(")
#+end_src #+end_src
* Planning: * Planning:
allora quello che devo fare è: allora quello che devo fare è:
** TODO Controllare se ho finito la questione del retourn:labe ** TODO Controllare se ho finito la questione del return:label
** TODO Complete the use os source slice inside parser (many node has synthetic source slice or badly wrapped)
** TODO implement struct: ** TODO implement struct:
#+begin_src rlox #+begin_src rlox
Cosa :: struct{ Cosa :: struct{
field1: Number field1: Numeric
} }
#+end_src #+end_src
*** TODO update lexert *** TODO update lexer
*** TODO update ast *** TODO update ast
*** TODO update parser *** TODO update parser
** TODO implement partial function ... ** TODO implement partial function ...
#+begin_src rlox #+begin_src rlox
cosa := make(Cosa, feld1: 42) cosa := Cosa{feld1: 42}
function :: fn(self:Cosa, b: Number) -> Number function :: fn(self:Cosa, b: Numeric) -> Numeric
res := function(cosa,44) res := function(cosa,44)
#+end_src #+end_src
*** TODO ... to undericlty create method *** TODO ... to undirectly create method
#+begin_src rlox #+begin_src rlox
res := cosa.function(44) res := cosa.function(44);
#+end_src #+end_src
*** TODO ... to make pipeline *** TODO ... to make pipeline
#+begin_src rlox #+begin_src rlox
res := cosa |> function(44) res := cosa |> function(44);
#+end_src #+end_src
** TODO Understand what is a type system ** TODO Understand what is a type system
** TODO implement struct method:
#+begin_src rlox
Cosa.new :: fn(field1: Numeric):Self #+begin_src do
return Self{ field1 };
end;
#+end_src
+27
View File
@@ -0,0 +1,27 @@
Data :: struct {
number: Number,
string: String,
bool: Bool
};
Data.new :: fn(number: Number, string: String, bool: Bool) -> Self
do
return Self {
number: number,
string: string,
bool: bool
};
end;
Data.function :: fn(
self,
number: Number,
string: String,
bool: Bool,)
{number == 42} : Nil
do
self.number = number;
self.string = string;
self.bool = bool;
end;
+2
View File
@@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"
+16 -8
View File
@@ -2,8 +2,9 @@ use crate::{
backend::environment::EnvironmentStack, backend::environment::EnvironmentStack,
common::{ common::{
ast::{AstNode, Expr, NodeId}, ast::{AstNode, Expr, NodeId},
base_value::{BaseValue, NativeFunction, Number, Truthy}, base_value::{BaseValue, NativeFunction, Number, Struct, Truthy},
lox_result::{runtime_error, LoxError, LoxResult}, lox_result::{LoxError, LoxResult, runtime_error},
types::Type,
}, },
frontend::{source_registry::SourceSlice, tokens::TokenType}, frontend::{source_registry::SourceSlice, tokens::TokenType},
}; };
@@ -32,14 +33,14 @@ impl Interpreter {
let mut env = EnvironmentStack::new(); let mut env = EnvironmentStack::new();
let _ = env.declare( let _ = env.declare(
"clock".to_string(), "clock".to_string(),
BaseValue::NativeFunction(NativeFunction::new(Vec::default(), |_args| { BaseValue::NativeFunction(Box::new(NativeFunction::new(Vec::default(), |_args| {
BaseValue::Number(Number::U128( BaseValue::Number(Number::U128(
std::time::SystemTime::now() std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH) .duration_since(std::time::UNIX_EPOCH)
.unwrap() .unwrap()
.as_millis(), .as_millis(),
)) ))
})), }))),
); );
Self { Self {
enviorment: env, enviorment: env,
@@ -112,7 +113,7 @@ impl Interpreter {
match self.eval_expr(body) { match self.eval_expr(body) {
Ok(val) => ret = val, Ok(val) => ret = val,
Err(LoxError::Return { value, .. }) => { Err(LoxError::Return { value, .. }) => {
ret = value; ret = *value;
break; break;
} }
Err(err) => return Err(err), Err(err) => return Err(err),
@@ -136,7 +137,7 @@ impl Interpreter {
match self.eval_expr(body) { match self.eval_expr(body) {
Ok(val) => ret = val, Ok(val) => ret = val,
Err(LoxError::Return { value, .. }) => { Err(LoxError::Return { value, .. }) => {
ret = value; ret = *value;
break; break;
} }
Err(err) => return Err(err), Err(err) => return Err(err),
@@ -145,6 +146,13 @@ impl Interpreter {
} }
Ok(ret) Ok(ret)
} }
Expr::Struct { fields } => {
let fields: Vec<(String, Type)> = fields
.iter()
.map(|(name, ty)| (name.clone(), ty.clone()))
.collect();
Ok(BaseValue::Struct(Box::new(Struct { fields })))
}
}; };
// Give location-less runtime errors this node's span. // Give location-less runtime errors this node's span.
match result { match result {
@@ -217,7 +225,7 @@ impl Interpreter {
// Execute the function body // Execute the function body
let result = match self.eval_expr(&func.body) { let result = match self.eval_expr(&func.body) {
Ok(value) => Ok(value), Ok(value) => Ok(value),
Err(LoxError::Return { value, .. }) => Ok(value), Err(LoxError::Return { value, .. }) => Ok(*value),
Err(err) => Err(err), Err(err) => Err(err),
}; };
@@ -328,7 +336,7 @@ impl Interpreter {
result = Err(LoxError::Return { result = Err(LoxError::Return {
source_slice: statement.source_slice.clone(), source_slice: statement.source_slice.clone(),
value, value: Box::new(value),
return_label: "Hi".to_string(), return_label: "Hi".to_string(),
}); });
break; break;
+16 -92
View File
@@ -2,8 +2,11 @@ use crate::{
common::{base_value::BaseValue, types::Type}, common::{base_value::BaseValue, types::Type},
frontend::{source_registry::SourceSlice, tokens::TokenType}, frontend::{source_registry::SourceSlice, tokens::TokenType},
}; };
use std::fmt::{Debug, Display};
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::{
collections::HashMap,
fmt::{Debug, Display},
};
/// A unique identity for an AST node, assigned once at construction. /// A unique identity for an AST node, assigned once at construction.
/// ///
@@ -23,7 +26,7 @@ impl NodeId {
} }
} }
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq, Debug)]
pub enum Expr { pub enum Expr {
Literal { Literal {
value: Box<BaseValue>, value: Box<BaseValue>,
@@ -83,6 +86,9 @@ pub enum Expr {
increment: Box<AstNode>, increment: Box<AstNode>,
body: Box<AstNode>, body: Box<AstNode>,
}, },
Struct {
fields: Box<HashMap<String, Type>>,
},
} }
// Implementazione Display per Expr (per debugging) // Implementazione Display per Expr (per debugging)
@@ -164,100 +170,18 @@ impl std::fmt::Display for Expr {
"For({} = {} in {}) {{\n{}\n}}", "For({} = {} in {}) {{\n{}\n}}",
variable.node, condition.node, increment.node, body.node variable.node, condition.node, increment.node, body.node
), ),
Expr::Struct { fields } => {
let field_strs: Vec<String> = fields
.iter()
.map(|(k, v)| format!("{}: {:?}", k, v))
.collect();
write!(f, "Struct {{ {} }}", field_strs.join(", "))
}
} }
} }
} }
impl Debug for Expr { // Debug is derived on Expr via #[derive(Debug)] above.
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, "(Unary {:?} {:?}) ", operator, operand.node,)
}
Expr::Grouping { expression } => {
write!(f, "(Grouping {:?})", 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(", "),
),
Expr::Assign { name, value } => {
write!(f, "(assign {:?} {:?})", name, value.node,)
}
Expr::If {
condition,
then_branch,
elif_branches,
else_branch,
} => {
let mut result =
format!("IF ({:?}) {{\n{:?}\n}}", condition.node, then_branch.node,);
for (condition, branch) in elif_branches {
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)
}
Expr::Print { expression } => {
write!(f, "Print({:?});", expression.node,)
}
Expr::VarDeclaration {
name,
initializer,
var_type,
} => match initializer {
Some(init) => write!(f, "Var({:?}: {:?} = {:?});", name, var_type, init.node,),
None => write!(f, "Var({:?}: {:?});", name, var_type,),
},
Expr::Return { expression, label } => {
write!(f, "Return({:?}, {}) ;", expression.node, label,)
}
Expr::Block { label, statements } => write!(
f,
"Block [{}] ([\n{:?}\n])",
label,
statements
.iter()
.map(|stmt| format!("{:?}", stmt.node))
.collect::<Vec<_>>()
.join("\t\t\n"),
),
Expr::While { condition, body } => {
write!(f, "While({:?}) {{\n{:?}\n}}", condition.node, body.node,)
}
Expr::For {
variable,
condition,
increment,
body,
} => write!(
f,
"For({:?} = {:?} in {:?}) {{\n{:?}\n}} ",
variable.node, condition.node, increment.node, body.node,
),
}
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct AstNode { pub struct AstNode {
+16 -16
View File
@@ -2,8 +2,9 @@ use core::fmt;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Display; use std::fmt::Display;
use std::ops::{Add, Div, Mul, Not, Rem, Sub}; use std::ops::{Add, Div, Mul, Not, Rem, Sub};
use std::ptr::fn_addr_eq;
use crate::common::lox_result::{runtime_error, LoxResult}; use crate::common::lox_result::{LoxResult, runtime_error};
use crate::common::types::Type; use crate::common::types::Type;
use crate::{ use crate::{
backend::environment::EnvironmentStack, common::ast::AstNode, backend::environment::EnvironmentStack, common::ast::AstNode,
@@ -270,9 +271,9 @@ pub enum BaseValue {
Number(Number), Number(Number),
Boolean(bool), Boolean(bool),
Nil, Nil,
Function(LoxFunction), Function(Box<LoxFunction>),
NativeFunction(NativeFunction), NativeFunction(Box<NativeFunction>),
Struct(Struct), Struct(Box<Struct>),
} }
struct Dict { struct Dict {
@@ -284,18 +285,12 @@ struct ReturnValue {
value: Type, value: Type,
} }
impl ReturnValue {
pub fn new(label: Vec<String>, value: Type) -> Self {
Self { label, value }
}
}
impl BaseValue { impl BaseValue {
pub fn is_callable(&self) -> bool { pub fn is_callable(&self) -> bool {
match self { matches!(
BaseValue::Function(..) | BaseValue::NativeFunction(..) => true, self,
_ => false, BaseValue::Function(..) | BaseValue::NativeFunction(..)
} )
} }
} }
@@ -350,11 +345,16 @@ impl LoxFunction {
} }
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone)]
pub struct NativeFunction { pub struct NativeFunction {
pub parameters: Vec<(String, Type)>, pub parameters: Vec<(String, Type)>,
pub function: fn(&[BaseValue]) -> BaseValue, pub function: fn(&[BaseValue]) -> BaseValue,
} }
impl PartialEq for NativeFunction {
fn eq(&self, other: &Self) -> bool {
self.parameters == other.parameters && fn_addr_eq(self.function, other.function)
}
}
impl NativeFunction { impl NativeFunction {
pub fn new(parameters: Vec<(String, Type)>, function: fn(&[BaseValue]) -> BaseValue) -> Self { pub fn new(parameters: Vec<(String, Type)>, function: fn(&[BaseValue]) -> BaseValue) -> Self {
@@ -367,7 +367,7 @@ impl NativeFunction {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Struct { pub struct Struct {
pub fields: Vec<(String, BaseValue)>, pub fields: Vec<(String, Type)>,
} }
// Trait implementations for BaseValue // Trait implementations for BaseValue
+1 -1
View File
@@ -28,7 +28,7 @@ pub enum LoxError {
}, },
Return { Return {
source_slice: SourceSlice, source_slice: SourceSlice,
value: BaseValue, value: Box<BaseValue>,
return_label: String, return_label: String,
}, },
} }
+10 -10
View File
@@ -1,5 +1,5 @@
use crate::common::base_value::{BaseValue, Number}; use crate::common::base_value::{BaseValue, Number};
use crate::common::lox_result::{lexical_error, LoxError, LoxResult}; use crate::common::lox_result::{LoxError, LoxResult, lexical_error};
use crate::frontend::source_registry::{SourceId, SourcePosition, SourceSlice}; use crate::frontend::source_registry::{SourceId, SourcePosition, SourceSlice};
use crate::frontend::tokens::{Token, TokenType}; use crate::frontend::tokens::{Token, TokenType};
@@ -102,7 +102,7 @@ impl Lexer {
token_type, token_type,
text, text,
SourceSlice::from_positions( SourceSlice::from_positions(
self.source_id.clone(), self.source_id,
self.start_pos.clone(), self.start_pos.clone(),
self.end_pos.clone(), self.end_pos.clone(),
), ),
@@ -115,7 +115,7 @@ impl Lexer {
text, text,
Some(literal), Some(literal),
SourceSlice::from_positions( SourceSlice::from_positions(
self.source_id.clone(), self.source_id,
self.start_pos.clone(), self.start_pos.clone(),
self.end_pos.clone(), self.end_pos.clone(),
), ),
@@ -174,7 +174,7 @@ impl Lexer {
if self.is_at_end() { if self.is_at_end() {
return lexical_error( return lexical_error(
SourceSlice::from_positions( SourceSlice::from_positions(
self.source_id.clone(), self.source_id,
self.start_pos.clone(), self.start_pos.clone(),
self.end_pos.clone(), self.end_pos.clone(),
), ),
@@ -190,11 +190,11 @@ impl Lexer {
(' ', _) | ('\r', _) | ('\t', _) => Ok(None), (' ', _) | ('\r', _) | ('\t', _) => Ok(None),
('\n', _) => Ok(None), ('\n', _) => Ok(None),
('"', _) => self.string(), ('"', _) => self.string(),
(c, _) if c.is_digit(10) => self.number(), (c, _) if c.is_ascii_digit() => self.number(),
(c, _) if c.is_alphanumeric() || c == '_' => self.identifier(), (c, _) if c.is_alphanumeric() || c == '_' => self.identifier(),
_ => Err(LoxError::LexicalError { _ => Err(LoxError::LexicalError {
source_slice: SourceSlice::from_positions( source_slice: SourceSlice::from_positions(
self.source_id.clone(), self.source_id,
self.start_pos.clone(), self.start_pos.clone(),
self.end_pos.clone(), self.end_pos.clone(),
), ),
@@ -210,7 +210,7 @@ impl Lexer {
if self.is_at_end() { if self.is_at_end() {
return Err(LoxError::LexicalError { return Err(LoxError::LexicalError {
source_slice: SourceSlice::from_positions( source_slice: SourceSlice::from_positions(
self.source_id.clone(), self.source_id,
self.start_pos.clone(), self.start_pos.clone(),
self.end_pos.clone(), self.end_pos.clone(),
), ),
@@ -226,14 +226,14 @@ impl Lexer {
fn number(&mut self) -> LoxResult<Option<Token>> { fn number(&mut self) -> LoxResult<Option<Token>> {
// Leggi la parte intera // Leggi la parte intera
while self.peek().is_digit(10) { while self.peek().is_ascii_digit() {
self.advance(); self.advance();
} }
// Controlla se c'è una parte decimale // Controlla se c'è una parte decimale
let has_decimal = if self.peek() == '.' && self.peek_next().is_digit(10) { let has_decimal = if self.peek() == '.' && self.peek_next().is_ascii_digit() {
self.advance(); // consuma il '.' self.advance(); // consuma il '.'
while self.peek().is_digit(10) { while self.peek().is_ascii_digit() {
self.advance(); self.advance();
} }
true true
+34 -21
View File
@@ -1,7 +1,7 @@
use crate::{ use crate::{
common::{ common::{
ast::{AstNode, Expr}, ast::{AstNode, Expr},
base_value::{BaseValue, LoxFunction}, base_value::{BaseValue, LoxFunction, Struct},
lox_result::{parse_error, runtime_error, LoxResult}, lox_result::{parse_error, runtime_error, LoxResult},
types::Type, types::Type,
}, },
@@ -224,10 +224,31 @@ impl Parser {
} }
fn struct_declaration(&mut self, start_slice: SourceSlice) -> LoxResult<AstNode> { fn struct_declaration(&mut self, start_slice: SourceSlice) -> LoxResult<AstNode> {
self.consume(TokenType::Struct, "Expect 'struct' after '::'")?;
self.consume(TokenType::LeftBrace, "Expect '{' after 'struct'")?; self.consume(TokenType::LeftBrace, "Expect '{' after 'struct'")?;
let mut fields: Vec<(String, Type)> = vec![];
todo!() while self.peek().token_type != TokenType::RightBrace {
let field_name = self
.consume(TokenType::Identifier, "Expect identifier after '{'")?
.clone();
self.consume(TokenType::Colon, "Expect ':' after field name")?;
let field_type = self
.consume_type_name("Expect type name after ':'")?
.clone();
self.consume(TokenType::Comma, "Expect ',' after field type")?;
fields.push((field_name.lexeme, Type::Unresolved(field_type)));
}
let end_slice = self
.consume(TokenType::RightBrace, "Expect '}' after struct fields")?
.source_slice
.clone();
let source_slice = SourceSlice::from_source_slices(start_slice, end_slice);
Ok(AstNode::new_expression(
Expr::Literal {
value: Box::new(BaseValue::Struct(Box::new(Struct { fields }))),
},
source_slice,
"Struct".to_string(),
))
} }
fn function_declaration(&mut self, start_slice: SourceSlice) -> LoxResult<AstNode> { fn function_declaration(&mut self, start_slice: SourceSlice) -> LoxResult<AstNode> {
@@ -269,13 +290,13 @@ impl Parser {
let body = self.statement()?; let body = self.statement()?;
Ok(AstNode::new_expression( Ok(AstNode::new_expression(
Expr::Literal { Expr::Literal {
value: Box::new(BaseValue::Function(LoxFunction { value: Box::new(BaseValue::Function(Box::new(LoxFunction {
parameters, parameters,
return_type: Type::Unresolved(return_type.clone()), return_type: Type::Unresolved(return_type.clone()),
body, body,
closure: None, closure: None,
guard, guard,
})), }))),
}, },
combine_position.clone(), combine_position.clone(),
return_type.clone(), return_type.clone(),
@@ -328,11 +349,7 @@ impl Parser {
start_slice.start_position, start_slice.start_position,
end_slice.end_position, end_slice.end_position,
); );
let label_str = if let Some(label) = label { let label_str = label.unwrap_or_default();
label
} else {
String::default()
};
Ok(AstNode::new_statement( Ok(AstNode::new_statement(
Expr::Block { Expr::Block {
statements: Box::new(statements), statements: Box::new(statements),
@@ -351,7 +368,7 @@ impl Parser {
let combined_slice = SourceSlice::from_source_slices(start_slice, end_slice); let combined_slice = SourceSlice::from_source_slices(start_slice, end_slice);
expr.is_statement = true; expr.is_statement = true;
expr.source_slice = combined_slice; expr.source_slice = combined_slice;
return Ok(expr); Ok(expr)
} }
fn return_statement(&mut self, label: Option<String>) -> LoxResult<AstNode> { fn return_statement(&mut self, label: Option<String>) -> LoxResult<AstNode> {
@@ -374,11 +391,7 @@ impl Parser {
let semicolon = self.consume(TokenType::Semicolon, "Expect ';' after return value.")?; let semicolon = self.consume(TokenType::Semicolon, "Expect ';' after return value.")?;
let end_slice = semicolon.source_slice.clone(); let end_slice = semicolon.source_slice.clone();
let combined_slice = SourceSlice::from_source_slices(start_slice, end_slice); let combined_slice = SourceSlice::from_source_slices(start_slice, end_slice);
let label_str = if let Some(label) = label { let label_str = label.unwrap_or_default();
label
} else {
String::default()
};
Ok(AstNode::new_statement( Ok(AstNode::new_statement(
Expr::Return { Expr::Return {
expression: Box::new(expr), expression: Box::new(expr),
@@ -653,7 +666,7 @@ impl Parser {
// Estendi il source_slice per includere le parentesi di chiusura // Estendi il source_slice per includere le parentesi di chiusura
let end_slice = self.previous().source_slice.end_position.clone(); let end_slice = self.previous().source_slice.end_position.clone();
let full_slice = SourceSlice { let full_slice = SourceSlice {
source_id: callee.source_slice.source_id.clone(), source_id: callee.source_slice.source_id,
start_position: start_slice.clone(), start_position: start_slice.clone(),
end_position: end_slice.clone(), end_position: end_slice.clone(),
}; };
@@ -779,7 +792,7 @@ impl Parser {
fn peek(&self) -> &Token { fn peek(&self) -> &Token {
if self.is_at_end() { if self.is_at_end() {
&self.tokens.last().unwrap() self.tokens.last().unwrap()
} else { } else {
&self.tokens[self.current] &self.tokens[self.current]
} }
@@ -787,7 +800,7 @@ impl Parser {
fn peek_next(&self) -> &Token { fn peek_next(&self) -> &Token {
if self.is_at_end() { if self.is_at_end() {
&self.peek() self.peek()
} else { } else {
&self.tokens[self.current + 1] &self.tokens[self.current + 1]
} }
@@ -806,7 +819,7 @@ impl Parser {
self.advance(); self.advance();
Ok(self.previous()) Ok(self.previous())
} else { } else {
return parse_error(self.peek().source_slice.clone(), message); parse_error(self.peek().source_slice.clone(), message)
} }
} }
+7 -1
View File
@@ -4,7 +4,7 @@ use std::{
io::ErrorKind, io::ErrorKind,
}; };
use crate::common::lox_result::{io_error, LoxResult}; use crate::common::lox_result::{LoxResult, io_error};
pub struct SourceRegistry { pub struct SourceRegistry {
pub sources: Vec<SourceFile>, pub sources: Vec<SourceFile>,
@@ -226,3 +226,9 @@ impl SourceRegistry {
line_of_code line_of_code
} }
} }
impl Default for SourceRegistry {
fn default() -> Self {
Self::new()
}
}
+6
View File
@@ -5,6 +5,9 @@ use crate::{common::base_value::BaseValue, frontend::source_registry::SourceSlic
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum TokenType { pub enum TokenType {
// Single character tokens // Single character tokens
Space,
Tab,
NewLine,
LeftParen, LeftParen,
RightParen, RightParen,
LeftBrace, LeftBrace,
@@ -70,6 +73,9 @@ pub enum TokenType {
impl fmt::Display for TokenType { impl fmt::Display for TokenType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
TokenType::Space => write!(f, "/s"),
TokenType::Tab => write!(f, "/t"),
TokenType::NewLine => write!(f, "/n"),
TokenType::Bang => write!(f, "!"), TokenType::Bang => write!(f, "!"),
TokenType::BangEqual => write!(f, "!="), TokenType::BangEqual => write!(f, "!="),
TokenType::Equal => write!(f, "="), TokenType::Equal => write!(f, "="),
+22 -1
View File
@@ -117,7 +117,7 @@ impl PrettyContext {
} }
fn should_truncate(&self) -> bool { fn should_truncate(&self) -> bool {
self.config.max_depth.map_or(false, |max| self.depth >= max) self.config.max_depth.is_some_and(|max| self.depth >= max)
} }
} }
@@ -414,6 +414,27 @@ impl PrettyPrint for Expr {
body.pretty_print(&ctx.child_context(true), f)?; body.pretty_print(&ctx.child_context(true), f)?;
writeln!(f, "{}}}", ctx.child_context(true).indent()) writeln!(f, "{}}}", ctx.child_context(true).indent())
} }
Expr::Struct { fields } => {
if ctx.config.compact {
let field_strs: Vec<String> = fields
.iter()
.map(|(k, v)| format!("{}: {:?}", k, v))
.collect();
write!(f, "struct {{ {} }}", field_strs.join(", "))
} else {
writeln!(f, "{}Struct {{", indent)?;
for (name, ty) in fields.iter() {
writeln!(
f,
"{}{}: {:?},",
ctx.child_context(false).indent(),
name,
ty
)?;
}
write!(f, "{}}}", indent)
}
}
} }
} }
} }
+10 -5
View File
@@ -102,17 +102,17 @@ impl Token {
} }
None => { None => {
if config.colored { if config.colored {
format!("{}", self.colored_type()) self.colored_type().to_string()
} else { } else {
format!("{}", self.token_type_symbol()) self.token_type_symbol().to_string()
} }
} }
} }
} else { } else {
if config.colored { if config.colored {
format!("{}", self.colored_type()) self.colored_type().to_string()
} else { } else {
format!("{}", self.token_type_symbol()) self.token_type_symbol().to_string()
} }
} }
} }
@@ -148,6 +148,9 @@ impl Token {
fn token_type_symbol(&self) -> &'static str { fn token_type_symbol(&self) -> &'static str {
match self.token_type { match self.token_type {
TokenType::Space => "SPC",
TokenType::Tab => "TAB",
TokenType::NewLine => "NEL",
TokenType::LeftParen => "(", TokenType::LeftParen => "(",
TokenType::RightParen => ")", TokenType::RightParen => ")",
TokenType::LeftBrace => "{", TokenType::LeftBrace => "{",
@@ -256,7 +259,9 @@ impl Token {
| TokenType::Dot | TokenType::Dot
| TokenType::Semicolon => ("\x1b[37m", self.token_type_symbol()), | TokenType::Semicolon => ("\x1b[37m", self.token_type_symbol()),
TokenType::StartBlock | TokenType::EndBlock => ("\x1b[35m", self.token_type_symbol()), TokenType::StartBlock | TokenType::EndBlock => ("\x1b[35m", self.token_type_symbol()),
TokenType::Eof => ("\x1b[33m", self.token_type_symbol()), TokenType::Eof | TokenType::Space | TokenType::Tab | TokenType::NewLine => {
("\x1b[33m", self.token_type_symbol())
}
TokenType::In => ("\x1b[36m", self.token_type_symbol()), TokenType::In => ("\x1b[36m", self.token_type_symbol()),
}; };
+12 -21
View File
@@ -33,12 +33,10 @@ fn main() -> LoxResult<()> {
println!("running {file_path:?}"); println!("running {file_path:?}");
let mut lox = LoxInterpreter::new(debug); let mut lox = LoxInterpreter::new(debug);
let res = match file_path { match file_path {
Some(path) => lox.run_file(&path, stage), Some(path) => lox.run_file(&path, stage),
None => lox.run_prompt(stage), None => lox.run_prompt(stage),
}; }
res
} }
fn parse_args(args: &[String]) -> (ExecutionStage, Option<String>, bool) { fn parse_args(args: &[String]) -> (ExecutionStage, Option<String>, bool) {
@@ -140,13 +138,12 @@ impl LoxInterpreter {
match self.source_registry.add_source_string(line.to_string()) { match self.source_registry.add_source_string(line.to_string()) {
Ok(source_id) => { Ok(source_id) => {
match self.process_source(source_id, stage, self.debug) { if let Ok(result) = self.process_source(source_id, stage, self.debug) {
Ok(result) => match stage { match stage {
ExecutionStage::Tokens => println!("Tokens: {}", result), ExecutionStage::Tokens => println!("Tokens: {}", result),
ExecutionStage::Ast => println!("AST: {}", result), ExecutionStage::Ast => println!("AST: {}", result),
ExecutionStage::Full => println!("Result: {}", result), ExecutionStage::Full => println!("Result: {}", result),
}, }
Err(_) => {} // Errore già stampato in process_source
} }
} }
Err(e) => eprintln!("Error: {}", e), Err(e) => eprintln!("Error: {}", e),
@@ -167,9 +164,8 @@ impl LoxInterpreter {
let source_content = self.source_registry.get_by_id(source_id).content.clone(); let source_content = self.source_registry.get_by_id(source_id).content.clone();
let mut lexer = Lexer::new(source_content, source_id); let mut lexer = Lexer::new(source_content, source_id);
lexer.scans_tokens().or_else(|err| { lexer.scans_tokens().inspect_err(|err| {
err.print_with_context(&self.source_registry); err.print_with_context(&self.source_registry);
Err(err)
}) })
} }
@@ -177,9 +173,8 @@ impl LoxInterpreter {
fn parse_to_ast(&self, source_id: SourceId) -> LoxResult<Vec<AstNode>> { fn parse_to_ast(&self, source_id: SourceId) -> LoxResult<Vec<AstNode>> {
let tokens = self.tokenize(source_id)?; let tokens = self.tokenize(source_id)?;
Parser::new(tokens).parse().or_else(|err| { Parser::new(tokens).parse().inspect_err(|err| {
err.print_with_context(&self.source_registry); err.print_with_context(&self.source_registry);
Err(err)
}) })
} }
@@ -196,9 +191,8 @@ impl LoxInterpreter {
if debug { if debug {
println!("Executing statement {}: {:?}", index, stmt); println!("Executing statement {}: {:?}", index, stmt);
} }
result = Some(interpreter.evaluate(stmt.clone()).or_else(|err| { result = Some(interpreter.evaluate(stmt.clone()).inspect_err(|err| {
err.print_with_context(&self.source_registry); err.print_with_context(&self.source_registry);
Err(err)
})?); })?);
} }
@@ -231,9 +225,8 @@ impl LoxInterpreter {
let mut lexer = Lexer::new(source_content, source_id); let mut lexer = Lexer::new(source_content, source_id);
// Stage 1: Tokenization // Stage 1: Tokenization
let tokens = lexer.scans_tokens().or_else(|err| { let tokens = lexer.scans_tokens().inspect_err(|err| {
err.print_with_context(&self.source_registry); err.print_with_context(&self.source_registry);
Err(err)
})?; })?;
// Se debug è attivo, mostra sempre i tokens // Se debug è attivo, mostra sempre i tokens
@@ -247,9 +240,8 @@ impl LoxInterpreter {
} }
// Stage 2: Parsing // Stage 2: Parsing
let ast = Parser::new(tokens).parse().or_else(|err| { let ast = Parser::new(tokens).parse().inspect_err(|err| {
err.print_with_context(&self.source_registry); err.print_with_context(&self.source_registry);
Err(err)
})?; })?;
// Se debug è attivo, mostra sempre l'AST // Se debug è attivo, mostra sempre l'AST
@@ -272,9 +264,8 @@ impl LoxInterpreter {
if debug { if debug {
println!("Executing statement {}: {:?}", index, stmt); println!("Executing statement {}: {:?}", index, stmt);
} }
result = Some(interpreter.evaluate(stmt.clone()).or_else(|err| { result = Some(interpreter.evaluate(stmt.clone()).inspect_err(|err| {
err.print_with_context(&self.source_registry); err.print_with_context(&self.source_registry);
Err(err)
})?); })?);
} }
@@ -295,7 +286,7 @@ fn format_tokens(tokens: &[crate::frontend::tokens::Token]) -> String {
} }
fn format_ast(ast: &[AstNode]) -> String { fn format_ast(ast: &[AstNode]) -> String {
use crate::logging::display_ast::{pretty_print_with_config, PrettyConfig}; use crate::logging::display_ast::{PrettyConfig, pretty_print_with_config};
let config = PrettyConfig { let config = PrettyConfig {
indent: " ".to_string(), indent: " ".to_string(),
+4 -4
View File
@@ -52,12 +52,12 @@ impl<T> ScopeStack<T> {
/// Update an existing binding in the innermost scope (no-op if absent). /// Update an existing binding in the innermost scope (no-op if absent).
pub fn set_local(&mut self, name: &str, state: T) { pub fn set_local(&mut self, name: &str, state: T) {
if let Some(scope) = self.scopes.last_mut() { if let Some(scope) = self.scopes.last_mut()
if let Some(slot) = scope.get_mut(name) { && let Some(slot) = scope.get_mut(name)
{
*slot = state; *slot = state;
} }
} }
}
/// Look up `name` in the innermost scope only. /// Look up `name` in the innermost scope only.
pub fn get_local(&self, name: &str) -> Option<&T> { pub fn get_local(&self, name: &str) -> Option<&T> {
@@ -68,7 +68,7 @@ impl<T> ScopeStack<T> {
pub fn declared_in_current(&self, name: &str) -> bool { pub fn declared_in_current(&self, name: &str) -> bool {
self.scopes self.scopes
.last() .last()
.map_or(false, |scope| scope.contains_key(name)) .is_some_and(|scope| scope.contains_key(name))
} }
/// Distance (in scopes) from the innermost scope to the one declaring /// Distance (in scopes) from the innermost scope to the one declaring
+2
View File
@@ -136,6 +136,8 @@ pub fn walk_expr<V: Visitor>(visitor: &mut V, expr: &AstNode) -> LoxResult<()> {
visitor.visit_expr(increment)?; visitor.visit_expr(increment)?;
visitor.visit_expr(body) visitor.visit_expr(body)
} }
// Struct declarations carry only type information, no child expressions.
Expr::Struct { .. } => Ok(()),
} }
} }