diff --git a/src/backend/interpreter.rs b/src/backend/interpreter.rs index 99e4676..fa24c1f 100755 --- a/src/backend/interpreter.rs +++ b/src/backend/interpreter.rs @@ -2,8 +2,9 @@ use crate::{ backend::environment::EnvironmentStack, common::{ ast::{AstNode, Expr, NodeId}, - base_value::{BaseValue, NativeFunction, Number, Truthy}, + base_value::{BaseValue, NativeFunction, Number, Struct, Truthy}, lox_result::{LoxError, LoxResult, runtime_error}, + types::Type, }, frontend::{source_registry::SourceSlice, tokens::TokenType}, }; @@ -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 { diff --git a/src/common/ast.rs b/src/common/ast.rs index fdfab03..38fd0ad 100755 --- a/src/common/ast.rs +++ b/src/common/ast.rs @@ -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, @@ -83,6 +86,9 @@ pub enum Expr { increment: Box, body: Box, }, + Struct { + fields: Box>, + }, } // 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 = 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::>() - .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::>() - .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 { diff --git a/src/logging/display_ast.rs b/src/logging/display_ast.rs index 1b24380..2460f49 100755 --- a/src/logging/display_ast.rs +++ b/src/logging/display_ast.rs @@ -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 = 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) + } + } } } } diff --git a/src/middleend/visit_ast.rs b/src/middleend/visit_ast.rs index 75be11e..224154a 100644 --- a/src/middleend/visit_ast.rs +++ b/src/middleend/visit_ast.rs @@ -136,6 +136,8 @@ pub fn walk_expr(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(()), } }