Skip to main content

aura_lang/eval/
value.rs

1//! Runtime values (SPEC §4.1). Immutable containers in Arc: cloning is O(1).
2//! Value is parameterized by the source's lifetime: names and function AST bodies are zero-copy.
3
4use indexmap::IndexMap;
5use std::fmt;
6use std::sync::Arc;
7
8use super::env::WeakEnv;
9use crate::parser::ast::{LambdaBody, SchemaField, Stmt};
10
11#[derive(Debug, Clone)]
12pub enum Value<'a> {
13    Null,
14    Bool(bool),
15    Int(i64),
16    Float(f64),
17    Str(Arc<str>),
18    List(Arc<Vec<Value<'a>>>),
19    /// IndexMap: key order = declaration order (deterministic JSON).
20    Object(Arc<IndexMap<String, Value<'a>>>),
21    Schema(Arc<SchemaDef<'a>>),
22    /// D18: a declared enum — a closed set of allowed string values.
23    Enum(Arc<EnumDef<'a>>),
24    Function(Arc<FunctionDef<'a>>),
25}
26
27/// D18. Members keep declaration order so diagnostics list them predictably.
28#[derive(Debug, Clone, PartialEq)]
29pub struct EnumDef<'a> {
30    pub name: &'a str,
31    pub members: Vec<&'a str>,
32}
33
34#[derive(Debug, Clone, PartialEq)]
35pub struct SchemaDef<'a> {
36    pub name: &'a str,
37    pub fields: Vec<SchemaField<'a>>,
38    /// D18: for each field typed by an enum, the enum resolved **at declaration
39    /// time** — so an imported schema validates against the enum that was in
40    /// scope in its own module, not one that happens to exist at the call site.
41    pub field_enums: std::collections::HashMap<&'a str, Arc<EnumDef<'a>>>,
42}
43
44pub struct FunctionDef<'a> {
45    pub params: Vec<&'a str>,
46    pub body: FuncBody<'a>,
47    /// Lexical closure (SPEC §4.2). A `WeakEnv` to avoid the env<->function
48    /// Arc cycle; the interpreter's env arena keeps the target env alive.
49    pub closure: WeakEnv<'a>,
50    /// D1xD12: the function runs with the capabilities of its origin module,
51    /// not the caller's - an exported package function does not gain the root's rights.
52    pub defined_in_root: bool,
53}
54
55#[derive(Clone)]
56pub enum FuncBody<'a> {
57    Lambda(LambdaBody<'a>),
58    /// A `def` body — statements (D17), like a block.
59    Block(Vec<Stmt<'a>>),
60}
61
62impl fmt::Debug for FunctionDef<'_> {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        write!(f, "<fn({})>", self.params.join(", "))
65    }
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
69pub enum TypeTag {
70    Null,
71    Bool,
72    Int,
73    Float,
74    Str,
75    List,
76    Object,
77    Schema,
78    Enum,
79    Function,
80}
81
82impl<'a> Value<'a> {
83    pub fn tag(&self) -> TypeTag {
84        match self {
85            Value::Null => TypeTag::Null,
86            Value::Bool(_) => TypeTag::Bool,
87            Value::Int(_) => TypeTag::Int,
88            Value::Float(_) => TypeTag::Float,
89            Value::Str(_) => TypeTag::Str,
90            Value::List(_) => TypeTag::List,
91            Value::Object(_) => TypeTag::Object,
92            Value::Schema(_) => TypeTag::Schema,
93            Value::Enum(_) => TypeTag::Enum,
94            Value::Function(_) => TypeTag::Function,
95        }
96    }
97
98    pub fn type_name(&self) -> &'static str {
99        match self.tag() {
100            TypeTag::Null => "Null",
101            TypeTag::Bool => "Bool",
102            TypeTag::Int => "Int",
103            TypeTag::Float => "Float",
104            TypeTag::Str => "String",
105            TypeTag::List => "List",
106            TypeTag::Object => "Object",
107            TypeTag::Schema => "Schema",
108            TypeTag::Enum => "Enum",
109            TypeTag::Function => "Function",
110        }
111    }
112
113    pub fn object(map: IndexMap<String, Value<'a>>) -> Self {
114        Value::Object(Arc::new(map))
115    }
116
117    pub fn list(items: Vec<Value<'a>>) -> Self {
118        Value::List(Arc::new(items))
119    }
120
121    pub fn str(s: impl AsRef<str>) -> Self {
122        Value::Str(Arc::from(s.as_ref()))
123    }
124}
125
126/// Structural equality; Int == Float compares by mathematical value;
127/// Function/Schema compare by Arc identity (SPEC §4.1).
128impl PartialEq for Value<'_> {
129    fn eq(&self, other: &Self) -> bool {
130        use Value::*;
131        match (self, other) {
132            (Null, Null) => true,
133            (Bool(a), Bool(b)) => a == b,
134            (Int(a), Int(b)) => a == b,
135            (Float(a), Float(b)) => a == b,
136            (Int(a), Float(b)) | (Float(b), Int(a)) => *a as f64 == *b,
137            (Str(a), Str(b)) => a == b,
138            (List(a), List(b)) => a == b,
139            (Object(a), Object(b)) => a == b,
140            (Schema(a), Schema(b)) => Arc::ptr_eq(a, b),
141            (Function(a), Function(b)) => Arc::ptr_eq(a, b),
142            _ => false,
143        }
144    }
145}