Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d59e748bf | ||
|
|
956446c170 | ||
|
|
52f0a5b8f1 | ||
|
|
84a7bf453f | ||
|
|
2c3267e8a4 | ||
|
|
2498b3b345 |
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rlox"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
|
||||
+52
-10
@@ -2,35 +2,77 @@
|
||||
|
||||
* Syntax example:
|
||||
#+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
|
||||
|
||||
* Planning:
|
||||
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:
|
||||
#+begin_src rlox
|
||||
Cosa :: struct{
|
||||
field1: Number
|
||||
field1: Numeric
|
||||
}
|
||||
#+end_src
|
||||
*** TODO update lexert
|
||||
*** TODO update lexer
|
||||
*** TODO update ast
|
||||
*** TODO update parser
|
||||
** TODO implement partial function ...
|
||||
#+begin_src rlox
|
||||
cosa := make(Cosa, feld1: 42)
|
||||
function :: fn(self:Cosa, b: Number) -> Number
|
||||
cosa := Cosa{feld1: 42}
|
||||
function :: fn(self:Cosa, b: Numeric) -> Numeric
|
||||
res := function(cosa,44)
|
||||
#+end_src
|
||||
*** TODO ... to undericlty create method
|
||||
*** TODO ... to undirectly create method
|
||||
#+begin_src rlox
|
||||
res := cosa.function(44)
|
||||
res := cosa.function(44);
|
||||
#+end_src
|
||||
*** TODO ... to make pipeline
|
||||
#+begin_src rlox
|
||||
res := cosa |> function(44)
|
||||
res := cosa |> function(44);
|
||||
#+end_src
|
||||
** 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
|
||||
|
||||
@@ -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;
|
||||
@@ -0,0 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
@@ -2,8 +2,9 @@ use crate::{
|
||||
backend::environment::EnvironmentStack,
|
||||
common::{
|
||||
ast::{AstNode, Expr, NodeId},
|
||||
base_value::{BaseValue, NativeFunction, Number, Truthy},
|
||||
lox_result::{runtime_error, LoxError, LoxResult},
|
||||
base_value::{BaseValue, NativeFunction, Number, Struct, Truthy},
|
||||
lox_result::{LoxError, LoxResult, runtime_error},
|
||||
types::Type,
|
||||
},
|
||||
frontend::{source_registry::SourceSlice, tokens::TokenType},
|
||||
};
|
||||
@@ -32,14 +33,14 @@ impl Interpreter {
|
||||
let mut env = EnvironmentStack::new();
|
||||
let _ = env.declare(
|
||||
"clock".to_string(),
|
||||
BaseValue::NativeFunction(NativeFunction::new(Vec::default(), |_args| {
|
||||
BaseValue::NativeFunction(Box::new(NativeFunction::new(Vec::default(), |_args| {
|
||||
BaseValue::Number(Number::U128(
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis(),
|
||||
))
|
||||
})),
|
||||
}))),
|
||||
);
|
||||
Self {
|
||||
enviorment: env,
|
||||
@@ -112,7 +113,7 @@ impl Interpreter {
|
||||
match self.eval_expr(body) {
|
||||
Ok(val) => ret = val,
|
||||
Err(LoxError::Return { value, .. }) => {
|
||||
ret = value;
|
||||
ret = *value;
|
||||
break;
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
@@ -136,7 +137,7 @@ impl Interpreter {
|
||||
match self.eval_expr(body) {
|
||||
Ok(val) => ret = val,
|
||||
Err(LoxError::Return { value, .. }) => {
|
||||
ret = value;
|
||||
ret = *value;
|
||||
break;
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
@@ -145,6 +146,13 @@ impl Interpreter {
|
||||
}
|
||||
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.
|
||||
match result {
|
||||
@@ -217,7 +225,7 @@ impl Interpreter {
|
||||
// Execute the function body
|
||||
let result = match self.eval_expr(&func.body) {
|
||||
Ok(value) => Ok(value),
|
||||
Err(LoxError::Return { value, .. }) => Ok(value),
|
||||
Err(LoxError::Return { value, .. }) => Ok(*value),
|
||||
Err(err) => Err(err),
|
||||
};
|
||||
|
||||
@@ -328,7 +336,7 @@ impl Interpreter {
|
||||
|
||||
result = Err(LoxError::Return {
|
||||
source_slice: statement.source_slice.clone(),
|
||||
value,
|
||||
value: Box::new(value),
|
||||
return_label: "Hi".to_string(),
|
||||
});
|
||||
break;
|
||||
|
||||
+16
-92
@@ -2,8 +2,11 @@ use crate::{
|
||||
common::{base_value::BaseValue, types::Type},
|
||||
frontend::{source_registry::SourceSlice, tokens::TokenType},
|
||||
};
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::{Debug, Display},
|
||||
};
|
||||
|
||||
/// 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 {
|
||||
Literal {
|
||||
value: Box<BaseValue>,
|
||||
@@ -83,6 +86,9 @@ pub enum Expr {
|
||||
increment: Box<AstNode>,
|
||||
body: Box<AstNode>,
|
||||
},
|
||||
Struct {
|
||||
fields: Box<HashMap<String, Type>>,
|
||||
},
|
||||
}
|
||||
|
||||
// Implementazione Display per Expr (per debugging)
|
||||
@@ -164,100 +170,18 @@ impl std::fmt::Display for Expr {
|
||||
"For({} = {} in {}) {{\n{}\n}}",
|
||||
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 {
|
||||
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,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
// Debug is derived on Expr via #[derive(Debug)] above.
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AstNode {
|
||||
|
||||
+16
-16
@@ -2,8 +2,9 @@ use core::fmt;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
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::{
|
||||
backend::environment::EnvironmentStack, common::ast::AstNode,
|
||||
@@ -270,9 +271,9 @@ pub enum BaseValue {
|
||||
Number(Number),
|
||||
Boolean(bool),
|
||||
Nil,
|
||||
Function(LoxFunction),
|
||||
NativeFunction(NativeFunction),
|
||||
Struct(Struct),
|
||||
Function(Box<LoxFunction>),
|
||||
NativeFunction(Box<NativeFunction>),
|
||||
Struct(Box<Struct>),
|
||||
}
|
||||
|
||||
struct Dict {
|
||||
@@ -284,18 +285,12 @@ struct ReturnValue {
|
||||
value: Type,
|
||||
}
|
||||
|
||||
impl ReturnValue {
|
||||
pub fn new(label: Vec<String>, value: Type) -> Self {
|
||||
Self { label, value }
|
||||
}
|
||||
}
|
||||
|
||||
impl BaseValue {
|
||||
pub fn is_callable(&self) -> bool {
|
||||
match self {
|
||||
BaseValue::Function(..) | BaseValue::NativeFunction(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(
|
||||
self,
|
||||
BaseValue::Function(..) | BaseValue::NativeFunction(..)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,11 +345,16 @@ impl LoxFunction {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NativeFunction {
|
||||
pub parameters: Vec<(String, Type)>,
|
||||
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 {
|
||||
pub fn new(parameters: Vec<(String, Type)>, function: fn(&[BaseValue]) -> BaseValue) -> Self {
|
||||
@@ -367,7 +367,7 @@ impl NativeFunction {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Struct {
|
||||
pub fields: Vec<(String, BaseValue)>,
|
||||
pub fields: Vec<(String, Type)>,
|
||||
}
|
||||
|
||||
// Trait implementations for BaseValue
|
||||
|
||||
@@ -28,7 +28,7 @@ pub enum LoxError {
|
||||
},
|
||||
Return {
|
||||
source_slice: SourceSlice,
|
||||
value: BaseValue,
|
||||
value: Box<BaseValue>,
|
||||
return_label: String,
|
||||
},
|
||||
}
|
||||
|
||||
+10
-10
@@ -1,5 +1,5 @@
|
||||
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::tokens::{Token, TokenType};
|
||||
|
||||
@@ -102,7 +102,7 @@ impl Lexer {
|
||||
token_type,
|
||||
text,
|
||||
SourceSlice::from_positions(
|
||||
self.source_id.clone(),
|
||||
self.source_id,
|
||||
self.start_pos.clone(),
|
||||
self.end_pos.clone(),
|
||||
),
|
||||
@@ -115,7 +115,7 @@ impl Lexer {
|
||||
text,
|
||||
Some(literal),
|
||||
SourceSlice::from_positions(
|
||||
self.source_id.clone(),
|
||||
self.source_id,
|
||||
self.start_pos.clone(),
|
||||
self.end_pos.clone(),
|
||||
),
|
||||
@@ -174,7 +174,7 @@ impl Lexer {
|
||||
if self.is_at_end() {
|
||||
return lexical_error(
|
||||
SourceSlice::from_positions(
|
||||
self.source_id.clone(),
|
||||
self.source_id,
|
||||
self.start_pos.clone(),
|
||||
self.end_pos.clone(),
|
||||
),
|
||||
@@ -190,11 +190,11 @@ impl Lexer {
|
||||
(' ', _) | ('\r', _) | ('\t', _) => Ok(None),
|
||||
('\n', _) => Ok(None),
|
||||
('"', _) => 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(),
|
||||
_ => Err(LoxError::LexicalError {
|
||||
source_slice: SourceSlice::from_positions(
|
||||
self.source_id.clone(),
|
||||
self.source_id,
|
||||
self.start_pos.clone(),
|
||||
self.end_pos.clone(),
|
||||
),
|
||||
@@ -210,7 +210,7 @@ impl Lexer {
|
||||
if self.is_at_end() {
|
||||
return Err(LoxError::LexicalError {
|
||||
source_slice: SourceSlice::from_positions(
|
||||
self.source_id.clone(),
|
||||
self.source_id,
|
||||
self.start_pos.clone(),
|
||||
self.end_pos.clone(),
|
||||
),
|
||||
@@ -226,14 +226,14 @@ impl Lexer {
|
||||
|
||||
fn number(&mut self) -> LoxResult<Option<Token>> {
|
||||
// Leggi la parte intera
|
||||
while self.peek().is_digit(10) {
|
||||
while self.peek().is_ascii_digit() {
|
||||
self.advance();
|
||||
}
|
||||
|
||||
// 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 '.'
|
||||
while self.peek().is_digit(10) {
|
||||
while self.peek().is_ascii_digit() {
|
||||
self.advance();
|
||||
}
|
||||
true
|
||||
|
||||
+34
-21
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
common::{
|
||||
ast::{AstNode, Expr},
|
||||
base_value::{BaseValue, LoxFunction},
|
||||
base_value::{BaseValue, LoxFunction, Struct},
|
||||
lox_result::{parse_error, runtime_error, LoxResult},
|
||||
types::Type,
|
||||
},
|
||||
@@ -224,10 +224,31 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn struct_declaration(&mut self, start_slice: SourceSlice) -> LoxResult<AstNode> {
|
||||
self.consume(TokenType::Struct, "Expect 'struct' after '::'")?;
|
||||
self.consume(TokenType::LeftBrace, "Expect '{' after 'struct'")?;
|
||||
|
||||
todo!()
|
||||
let mut fields: Vec<(String, Type)> = vec![];
|
||||
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> {
|
||||
@@ -269,13 +290,13 @@ impl Parser {
|
||||
let body = self.statement()?;
|
||||
Ok(AstNode::new_expression(
|
||||
Expr::Literal {
|
||||
value: Box::new(BaseValue::Function(LoxFunction {
|
||||
value: Box::new(BaseValue::Function(Box::new(LoxFunction {
|
||||
parameters,
|
||||
return_type: Type::Unresolved(return_type.clone()),
|
||||
body,
|
||||
closure: None,
|
||||
guard,
|
||||
})),
|
||||
}))),
|
||||
},
|
||||
combine_position.clone(),
|
||||
return_type.clone(),
|
||||
@@ -328,11 +349,7 @@ impl Parser {
|
||||
start_slice.start_position,
|
||||
end_slice.end_position,
|
||||
);
|
||||
let label_str = if let Some(label) = label {
|
||||
label
|
||||
} else {
|
||||
String::default()
|
||||
};
|
||||
let label_str = label.unwrap_or_default();
|
||||
Ok(AstNode::new_statement(
|
||||
Expr::Block {
|
||||
statements: Box::new(statements),
|
||||
@@ -351,7 +368,7 @@ impl Parser {
|
||||
let combined_slice = SourceSlice::from_source_slices(start_slice, end_slice);
|
||||
expr.is_statement = true;
|
||||
expr.source_slice = combined_slice;
|
||||
return Ok(expr);
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
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 end_slice = semicolon.source_slice.clone();
|
||||
let combined_slice = SourceSlice::from_source_slices(start_slice, end_slice);
|
||||
let label_str = if let Some(label) = label {
|
||||
label
|
||||
} else {
|
||||
String::default()
|
||||
};
|
||||
let label_str = label.unwrap_or_default();
|
||||
Ok(AstNode::new_statement(
|
||||
Expr::Return {
|
||||
expression: Box::new(expr),
|
||||
@@ -653,7 +666,7 @@ impl Parser {
|
||||
// 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(),
|
||||
source_id: callee.source_slice.source_id,
|
||||
start_position: start_slice.clone(),
|
||||
end_position: end_slice.clone(),
|
||||
};
|
||||
@@ -779,7 +792,7 @@ impl Parser {
|
||||
|
||||
fn peek(&self) -> &Token {
|
||||
if self.is_at_end() {
|
||||
&self.tokens.last().unwrap()
|
||||
self.tokens.last().unwrap()
|
||||
} else {
|
||||
&self.tokens[self.current]
|
||||
}
|
||||
@@ -787,7 +800,7 @@ impl Parser {
|
||||
|
||||
fn peek_next(&self) -> &Token {
|
||||
if self.is_at_end() {
|
||||
&self.peek()
|
||||
self.peek()
|
||||
} else {
|
||||
&self.tokens[self.current + 1]
|
||||
}
|
||||
@@ -806,7 +819,7 @@ impl Parser {
|
||||
self.advance();
|
||||
Ok(self.previous())
|
||||
} else {
|
||||
return parse_error(self.peek().source_slice.clone(), message);
|
||||
parse_error(self.peek().source_slice.clone(), message)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::{
|
||||
io::ErrorKind,
|
||||
};
|
||||
|
||||
use crate::common::lox_result::{io_error, LoxResult};
|
||||
use crate::common::lox_result::{LoxResult, io_error};
|
||||
|
||||
pub struct SourceRegistry {
|
||||
pub sources: Vec<SourceFile>,
|
||||
@@ -226,3 +226,9 @@ impl SourceRegistry {
|
||||
line_of_code
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SourceRegistry {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ use crate::{common::base_value::BaseValue, frontend::source_registry::SourceSlic
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum TokenType {
|
||||
// Single character tokens
|
||||
Space,
|
||||
Tab,
|
||||
NewLine,
|
||||
LeftParen,
|
||||
RightParen,
|
||||
LeftBrace,
|
||||
@@ -70,6 +73,9 @@ pub enum TokenType {
|
||||
impl fmt::Display for TokenType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
TokenType::Space => write!(f, "/s"),
|
||||
TokenType::Tab => write!(f, "/t"),
|
||||
TokenType::NewLine => write!(f, "/n"),
|
||||
TokenType::Bang => write!(f, "!"),
|
||||
TokenType::BangEqual => write!(f, "!="),
|
||||
TokenType::Equal => write!(f, "="),
|
||||
|
||||
@@ -117,7 +117,7 @@ impl PrettyContext {
|
||||
}
|
||||
|
||||
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)?;
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,17 +102,17 @@ impl Token {
|
||||
}
|
||||
None => {
|
||||
if config.colored {
|
||||
format!("{}", self.colored_type())
|
||||
self.colored_type().to_string()
|
||||
} else {
|
||||
format!("{}", self.token_type_symbol())
|
||||
self.token_type_symbol().to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if config.colored {
|
||||
format!("{}", self.colored_type())
|
||||
self.colored_type().to_string()
|
||||
} 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 {
|
||||
match self.token_type {
|
||||
TokenType::Space => "SPC",
|
||||
TokenType::Tab => "TAB",
|
||||
TokenType::NewLine => "NEL",
|
||||
TokenType::LeftParen => "(",
|
||||
TokenType::RightParen => ")",
|
||||
TokenType::LeftBrace => "{",
|
||||
@@ -256,7 +259,9 @@ impl Token {
|
||||
| TokenType::Dot
|
||||
| TokenType::Semicolon => ("\x1b[37m", 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()),
|
||||
};
|
||||
|
||||
|
||||
+12
-21
@@ -33,12 +33,10 @@ fn main() -> LoxResult<()> {
|
||||
println!("running {file_path:?}");
|
||||
let mut lox = LoxInterpreter::new(debug);
|
||||
|
||||
let res = match file_path {
|
||||
match file_path {
|
||||
Some(path) => lox.run_file(&path, stage),
|
||||
None => lox.run_prompt(stage),
|
||||
};
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
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()) {
|
||||
Ok(source_id) => {
|
||||
match self.process_source(source_id, stage, self.debug) {
|
||||
Ok(result) => match stage {
|
||||
if let Ok(result) = self.process_source(source_id, stage, self.debug) {
|
||||
match stage {
|
||||
ExecutionStage::Tokens => println!("Tokens: {}", result),
|
||||
ExecutionStage::Ast => println!("AST: {}", result),
|
||||
ExecutionStage::Full => println!("Result: {}", result),
|
||||
},
|
||||
Err(_) => {} // Errore già stampato in process_source
|
||||
}
|
||||
}
|
||||
}
|
||||
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 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(err)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -177,9 +173,8 @@ impl LoxInterpreter {
|
||||
fn parse_to_ast(&self, source_id: SourceId) -> LoxResult<Vec<AstNode>> {
|
||||
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(err)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -196,9 +191,8 @@ impl LoxInterpreter {
|
||||
if debug {
|
||||
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(err)
|
||||
})?);
|
||||
}
|
||||
|
||||
@@ -231,9 +225,8 @@ impl LoxInterpreter {
|
||||
let mut lexer = Lexer::new(source_content, source_id);
|
||||
|
||||
// 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(err)
|
||||
})?;
|
||||
|
||||
// Se debug è attivo, mostra sempre i tokens
|
||||
@@ -247,9 +240,8 @@ impl LoxInterpreter {
|
||||
}
|
||||
|
||||
// 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(err)
|
||||
})?;
|
||||
|
||||
// Se debug è attivo, mostra sempre l'AST
|
||||
@@ -272,9 +264,8 @@ impl LoxInterpreter {
|
||||
if debug {
|
||||
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(err)
|
||||
})?);
|
||||
}
|
||||
|
||||
@@ -295,7 +286,7 @@ fn format_tokens(tokens: &[crate::frontend::tokens::Token]) -> 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 {
|
||||
indent: " ".to_string(),
|
||||
|
||||
@@ -52,10 +52,10 @@ impl<T> ScopeStack<T> {
|
||||
|
||||
/// Update an existing binding in the innermost scope (no-op if absent).
|
||||
pub fn set_local(&mut self, name: &str, state: T) {
|
||||
if let Some(scope) = self.scopes.last_mut() {
|
||||
if let Some(slot) = scope.get_mut(name) {
|
||||
*slot = state;
|
||||
}
|
||||
if let Some(scope) = self.scopes.last_mut()
|
||||
&& let Some(slot) = scope.get_mut(name)
|
||||
{
|
||||
*slot = state;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ impl<T> ScopeStack<T> {
|
||||
pub fn declared_in_current(&self, name: &str) -> bool {
|
||||
self.scopes
|
||||
.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
|
||||
|
||||
@@ -136,6 +136,8 @@ pub fn walk_expr<V: Visitor>(visitor: &mut V, expr: &AstNode) -> LoxResult<()> {
|
||||
visitor.visit_expr(increment)?;
|
||||
visitor.visit_expr(body)
|
||||
}
|
||||
// Struct declarations carry only type information, no child expressions.
|
||||
Expr::Struct { .. } => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user