blots_core/
ast.rs

1use crate::functions::BuiltInFunction;
2use crate::values::LambdaArg;
3use serde::{Deserialize, Serialize};
4
5/// Represents a source code location for error reporting
6#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
7pub struct Span {
8    pub start_byte: usize,
9    pub end_byte: usize,
10    pub start_line: usize,
11    pub start_col: usize,
12}
13
14impl Span {
15    pub fn new(start_byte: usize, end_byte: usize, start_line: usize, start_col: usize) -> Self {
16        Self {
17            start_byte,
18            end_byte,
19            start_line,
20            start_col,
21        }
22    }
23
24    /// Create a dummy span for cases where location info is unavailable
25    pub fn dummy() -> Self {
26        Self {
27            start_byte: 0,
28            end_byte: 0,
29            start_line: 1,
30            start_col: 1,
31        }
32    }
33}
34
35/// Wrapper type that attaches source location information to any AST node
36///
37/// Note: PartialEq is manually implemented to compare only the node content,
38/// ignoring spans. This ensures structural equality for AST nodes regardless
39/// of their source location.
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct Spanned<T> {
42    pub node: T,
43    pub span: Span,
44}
45
46impl<T: PartialEq> PartialEq for Spanned<T> {
47    fn eq(&self, other: &Self) -> bool {
48        // Only compare the node content, ignore the span
49        self.node == other.node
50    }
51}
52
53impl<T> Spanned<T> {
54    pub fn new(node: T, span: Span) -> Self {
55        Self { node, span }
56    }
57
58    pub fn dummy(node: T) -> Self {
59        Self {
60            node,
61            span: Span::dummy(),
62        }
63    }
64}
65
66/// Expression with source location information
67pub type SpannedExpr = Spanned<Expr>;
68
69#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
70pub enum Expr {
71    // Literals
72    Number(f64),
73    String(String),
74    Bool(bool),
75    Null,
76
77    // Variables and functions
78    Identifier(String),
79    InputReference(String),   // Shorthand for inputs.field (e.g., #field)
80    BuiltIn(BuiltInFunction), // Built-in function
81
82    // Collections
83    List(Vec<SpannedExpr>),
84    Record(Vec<RecordEntry>),
85
86    // Lambda
87    Lambda {
88        args: Vec<LambdaArg>,
89        body: Box<SpannedExpr>,
90    },
91
92    // Control flow
93    Conditional {
94        condition: Box<SpannedExpr>,
95        then_expr: Box<SpannedExpr>,
96        else_expr: Box<SpannedExpr>,
97    },
98
99    DoBlock {
100        statements: Vec<DoStatement>,
101        return_expr: Box<SpannedExpr>,
102    },
103
104    // Operations
105    Assignment {
106        ident: String,
107        value: Box<SpannedExpr>,
108    },
109
110    Call {
111        func: Box<SpannedExpr>,
112        args: Vec<SpannedExpr>,
113    },
114
115    Access {
116        expr: Box<SpannedExpr>,
117        index: Box<SpannedExpr>,
118    },
119
120    DotAccess {
121        expr: Box<SpannedExpr>,
122        field: String,
123    },
124
125    BinaryOp {
126        op: BinaryOp,
127        left: Box<SpannedExpr>,
128        right: Box<SpannedExpr>,
129    },
130
131    UnaryOp {
132        op: UnaryOp,
133        expr: Box<SpannedExpr>,
134    },
135
136    PostfixOp {
137        op: PostfixOp,
138        expr: Box<SpannedExpr>,
139    },
140
141    // Special
142    Spread(Box<SpannedExpr>),
143}
144
145#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
146pub struct RecordEntry {
147    pub key: RecordKey,
148    pub value: SpannedExpr,
149}
150
151#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
152pub enum RecordKey {
153    Static(String),
154    Dynamic(Box<SpannedExpr>),
155    Shorthand(String),
156    Spread(Box<SpannedExpr>),
157}
158
159#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
160pub enum DoStatement {
161    Expression(SpannedExpr),
162    Comment(String),
163}
164
165#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
166pub enum BinaryOp {
167    // Arithmetic
168    Add,
169    Subtract,
170    Multiply,
171    Divide,
172    Modulo,
173    Power,
174
175    // Comparison (with broadcasting)
176    Equal,
177    NotEqual,
178    Less,
179    LessEq,
180    Greater,
181    GreaterEq,
182
183    // Comparison (without broadcasting)
184    DotEqual,
185    DotNotEqual,
186    DotLess,
187    DotLessEq,
188    DotGreater,
189    DotGreaterEq,
190
191    // Logical
192    And,
193    NaturalAnd,
194    Or,
195    NaturalOr,
196
197    // Special
198    Via,
199    Into,
200    Coalesce,
201}
202
203#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
204pub enum UnaryOp {
205    Negate,
206    Not,
207    Invert,
208}
209
210#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
211pub enum PostfixOp {
212    Factorial,
213}