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    Output {
111        expr: Box<SpannedExpr>,
112    },
113
114    Call {
115        func: Box<SpannedExpr>,
116        args: Vec<SpannedExpr>,
117    },
118
119    Access {
120        expr: Box<SpannedExpr>,
121        index: Box<SpannedExpr>,
122    },
123
124    DotAccess {
125        expr: Box<SpannedExpr>,
126        field: String,
127    },
128
129    BinaryOp {
130        op: BinaryOp,
131        left: Box<SpannedExpr>,
132        right: Box<SpannedExpr>,
133    },
134
135    UnaryOp {
136        op: UnaryOp,
137        expr: Box<SpannedExpr>,
138    },
139
140    PostfixOp {
141        op: PostfixOp,
142        expr: Box<SpannedExpr>,
143    },
144
145    // Special
146    Spread(Box<SpannedExpr>),
147}
148
149#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
150pub struct RecordEntry {
151    pub key: RecordKey,
152    pub value: SpannedExpr,
153}
154
155#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
156pub enum RecordKey {
157    Static(String),
158    Dynamic(Box<SpannedExpr>),
159    Shorthand(String),
160    Spread(Box<SpannedExpr>),
161}
162
163#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
164pub enum DoStatement {
165    Expression(SpannedExpr),
166    Comment(String),
167}
168
169#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
170pub enum BinaryOp {
171    // Arithmetic
172    Add,
173    Subtract,
174    Multiply,
175    Divide,
176    Modulo,
177    Power,
178
179    // Comparison (with broadcasting)
180    Equal,
181    NotEqual,
182    Less,
183    LessEq,
184    Greater,
185    GreaterEq,
186
187    // Comparison (without broadcasting)
188    DotEqual,
189    DotNotEqual,
190    DotLess,
191    DotLessEq,
192    DotGreater,
193    DotGreaterEq,
194
195    // Logical
196    And,
197    NaturalAnd,
198    Or,
199    NaturalOr,
200
201    // Special
202    Via,
203    Into,
204    Where,
205    Coalesce,
206}
207
208#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
209pub enum UnaryOp {
210    Negate,
211    Not,
212    Invert,
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
216pub enum PostfixOp {
217    Factorial,
218}