Skip to main content

konjure_lang/
ast.rs

1//! Source-preserving syntax nodes used by the parser and interpreter.
2use serde::{Deserialize, Serialize};
3use std::collections::BTreeMap;
4
5/// Byte offsets in a named UTF-8 source module. End is exclusive.
6#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
7#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
8pub struct Span {
9    /// Source module name. `main` and `builtin` are reserved.
10    pub module: String,
11    /// Inclusive UTF-8 byte offset.
12    pub start: usize,
13    /// Exclusive UTF-8 byte offset.
14    pub end: usize,
15}
16impl Span {
17    /// Construct a source range. Parser and diagnostic consumers validate its offsets.
18    pub fn new(module: impl Into<String>, start: usize, end: usize) -> Self {
19        Self {
20            module: module.into(),
21            start,
22            end,
23        }
24    }
25}
26/// A portable diagnostic. The source is retained by [`crate::Program`].
27#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
28pub struct Diagnostic {
29    /// Stable machine-readable diagnostic category.
30    pub code: String,
31    /// Human-readable reason the operation was rejected.
32    pub message: String,
33    /// Exact source range of this construct.
34    pub span: Span,
35    /// Exact SDK data-error case, retained independently from the host diagnostic category.
36    #[serde(default, skip_serializing_if = "Option::is_none")]
37    pub data_error: Option<String>,
38}
39impl Diagnostic {
40    /// Construct a structured diagnostic without rendering or external I/O.
41    pub fn new(code: impl Into<String>, message: impl Into<String>, span: Span) -> Self {
42        Self {
43            code: code.into(),
44            message: message.into(),
45            span,
46            data_error: None,
47        }
48    }
49}
50impl std::fmt::Display for Diagnostic {
51    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52        write!(
53            f,
54            "{}:{}..{}: {}: {}",
55            self.span.module, self.span.start, self.span.end, self.code, self.message
56        )
57    }
58}
59impl std::error::Error for Diagnostic {}
60
61/// Types have nominal class names and an explicit homogeneous list form.
62#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
63#[cfg_attr(feature = "typescript", ts(rename = "LanguageType"))]
64#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
65pub enum Type {
66    /// A builtin, class, or trait name. `Str` is text data; `Text` is a visible component.
67    Named(String),
68    /// A named type with explicit square-bracket arguments. Semantic validation
69    /// decides which constructors and arities are available.
70    Applied {
71        /// Constructor name, optionally qualified by an imported module.
72        name: String,
73        /// Type arguments in source order.
74        arguments: Vec<Type>,
75    },
76    /// An ordered collection or homogeneous list type.
77    List(Box<Type>),
78    /// A dense, rank-aware tensor type.
79    Tensor(Box<Type>),
80    /// A statically checked callable; argument and result types are invariant.
81    Function {
82        /// Types accepted in argument order.
83        parameters: Vec<Type>,
84        /// Required result type.
85        returns: Box<Type>,
86    },
87    /// A `ComponentReference[T]` created by `bind[T](entity)`.
88    ComponentReference(Box<Type>),
89}
90impl Type {
91    /// Construct a statically typed callable signature.
92    pub fn function(parameters: Vec<Type>, returns: Type) -> Self {
93        Self::Function {
94            parameters,
95            returns: Box::new(returns),
96        }
97    }
98    /// Construct a named type reference for a Rust host signature.
99    pub fn named(name: impl Into<String>) -> Self {
100        let name = name.into();
101        Self::Named(match name.as_str() {
102            "Number" => "f64".into(),
103            "String" => "Str".into(),
104            _ => name,
105        })
106    }
107}
108/// An explicitly typed function argument. Method `self` is implicit and absent here.
109#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
110pub struct Parameter {
111    /// Declared or referenced source identifier.
112    pub name: String,
113    /// Declared type, checked at parameter, field, and assignment boundaries.
114    pub ty: Type,
115    /// Exact source range of this construct.
116    pub span: Span,
117}
118/// A function body or trait method signature. Empty trait bodies specify required operations.
119#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
120pub struct Function {
121    /// Declared or referenced source identifier.
122    pub name: String,
123    /// Explicit arguments in declaration order; implicit method `self` is excluded.
124    pub parameters: Vec<Parameter>,
125    /// Required return value type; omitted runtime returns produce Unit.
126    pub returns: Type,
127    /// Statements evaluated in lexical source order.
128    pub body: Vec<Stmt>,
129    /// Exact source range of this construct.
130    pub span: Span,
131}
132/// A typed class field with an optional constant default expression.
133#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
134pub struct Field {
135    /// Declared or referenced source identifier.
136    pub name: String,
137    /// Declared type, checked at parameter, field, and assignment boundaries.
138    pub ty: Type,
139    /// Constant initializer used when the constructor omits this field.
140    pub default: Option<Expr>,
141    /// Exact source range of this construct.
142    pub span: Span,
143}
144/// A nominal value type. Constructing it does not implicitly create an ECS entity.
145#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
146pub struct Class {
147    /// Declared or referenced source identifier.
148    pub name: String,
149    /// Fields keyed or ordered according to the containing syntax node.
150    pub fields: Vec<Field>,
151    /// Inherent methods with an implicit mutable `self` receiver.
152    pub methods: Vec<Function>,
153    /// Exact source range of this construct.
154    pub span: Span,
155}
156/// One constructor case of an algebraic data type.
157#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
158pub struct EnumCase {
159    /// Declared case name.
160    pub name: String,
161    /// Constructor payload types in source order.
162    pub payload: Vec<Type>,
163    /// Exact source range of this construct.
164    pub span: Span,
165}
166/// A nominal algebraic data type and its constructor cases.
167#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
168pub struct Enum {
169    /// Declared type name.
170    pub name: String,
171    /// Constructor cases in source order.
172    pub cases: Vec<EnumCase>,
173    /// Exact source range of this construct.
174    pub span: Span,
175}
176/// A named set of method signatures implemented explicitly by classes.
177#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
178pub struct Trait {
179    /// Declared or referenced source identifier.
180    pub name: String,
181    /// Required or implemented method definitions.
182    pub methods: Vec<Function>,
183    /// Exact source range of this construct.
184    pub span: Span,
185}
186/// Methods attached to a class, optionally checked against a trait contract.
187#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
188pub struct Implementation {
189    /// The implemented trait, or None for inherent class methods.
190    pub trait_name: Option<String>,
191    /// Nominal class name, optionally qualified by an imported module.
192    pub class: String,
193    /// Required or implemented method definitions.
194    pub methods: Vec<Function>,
195    /// Exact source range of this construct.
196    pub span: Span,
197}
198/// A persistent typed component query with explicit lifecycle callbacks.
199#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
200pub struct System {
201    /// Declared or referenced source identifier.
202    pub name: String,
203    /// Mutable component bindings; a single `of T` selector binds implicit `self`.
204    pub bindings: Vec<Parameter>,
205    /// `init`, required `frame`, and `done` lifecycle functions.
206    pub callbacks: Vec<Function>,
207    /// Exact source range of this construct.
208    pub span: Span,
209}
210/// A module declaration or one-time initializer, retained in source order.
211#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
212pub enum Item {
213    /// Declare a pure data layout.
214    Class(Class),
215    /// Declare an algebraic data type.
216    Enum(Enum),
217    /// Declare a reusable function.
218    Function(Function),
219    /// Declare a method contract.
220    Trait(Trait),
221    /// Implement inherent or trait methods for a class.
222    Implementation(Implementation),
223    /// Declare a tick-driven ECS query.
224    System(System),
225    /// Link an explicitly supplied source module.
226    Import {
227        /// Source module name. `main` and `builtin` are reserved.
228        module: String,
229        /// Exact source range of this construct.
230        span: Span,
231    },
232    /// Make a module member accessible to importers.
233    Export {
234        /// Declared or referenced source identifier.
235        name: String,
236        /// Exact source range of this construct.
237        span: Span,
238    },
239    /// Run an initializer once during machine construction.
240    Statement(Stmt),
241}
242/// An expression and its original UTF-8 source location.
243#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
244pub struct Expr {
245    /// The syntax operation represented by this node.
246    pub kind: ExprKind,
247    /// Exact source range of this construct.
248    pub span: Span,
249}
250/// Expression syntax before runtime value and effect checks.
251#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
252pub enum ExprKind {
253    /// A numeric literal's exact source spelling; execution parses and validates it.
254    Number(String),
255    /// A numeric literal explicitly interpreted at a scalar dtype.
256    TypedLiteral {
257        /// Unsuffixed numeric literal, including a unary negative sign when present.
258        value: Box<Expr>,
259        /// Required numeric dtype.
260        ty: Type,
261    },
262    /// A Boolean literal.
263    Bool(bool),
264    /// A UTF-8 string literal.
265    Text(String),
266    /// The empty value `()`.
267    Unit,
268    /// Read a lexical binding or module global.
269    Name(String),
270    /// An ordered collection or homogeneous list type.
271    List(Vec<Expr>),
272    /// A nested list literal with an explicit scalar dtype, packed by the checker.
273    TensorLiteral {
274        /// Outer list values, retaining nested [`ExprKind::List`] structure.
275        values: Vec<Expr>,
276        /// Declared scalar dtype.
277        dtype: Type,
278    },
279    /// Select an expression result by structural patterns.
280    Match {
281        /// Scrutinee evaluated once before trying arms.
282        value: Box<Expr>,
283        /// Arms considered in source order.
284        arms: Vec<MatchArm>,
285    },
286    /// Propagate a result-like failure according to the enclosing function contract.
287    Propagate(Box<Expr>),
288    /// An explicit parenthesized assignment expression whose checked result can
289    /// carry recoverable data-operation failure.
290    Assign {
291        /// Writable location, including an indexed tensor or list access.
292        target: Box<Expr>,
293        /// Value assigned after the target location has been resolved.
294        value: Box<Expr>,
295    },
296    /// Construct a nominal class value.
297    Record {
298        /// Nominal class name, optionally qualified by an imported module.
299        class: String,
300        /// Fields keyed or ordered according to the containing syntax node.
301        fields: BTreeMap<String, Expr>,
302    },
303    /// Apply logical negation or numeric negation.
304    Unary {
305        /// Operator spelling, whose operand contract is checked by the interpreter.
306        op: String,
307        /// Operand, initializer, or assigned expression.
308        value: Box<Expr>,
309    },
310    /// Apply arithmetic, comparison, or short-circuit Boolean operations.
311    Binary {
312        /// Operator spelling, whose operand contract is checked by the interpreter.
313        op: String,
314        /// Left operand, evaluated first.
315        left: Box<Expr>,
316        /// Right operand; logical operators short-circuit its evaluation.
317        right: Box<Expr>,
318    },
319    /// Call a reusable function, constructor, or method.
320    Call {
321        /// Named function, constructor, or receiver method.
322        callee: Box<Expr>,
323        /// Argument expressions in left-to-right evaluation order.
324        arguments: Vec<Expr>,
325    },
326    /// A concrete ECS builtin function value such as `get[Transform]`.
327    TypedFunction {
328        /// Intrinsic name: `get`, `has`, `query`, or `bind`.
329        name: String,
330        /// Statically resolved component or query type.
331        ty: Type,
332    },
333    /// Call a typed ECS intrinsic such as `get[Transform](entity)`.
334    TypedCall {
335        /// Intrinsic name: `get`, `has`, or `query`.
336        name: String,
337        /// Statically resolved component or query type.
338        ty: Type,
339        /// Argument expressions in left-to-right evaluation order.
340        arguments: Vec<Expr>,
341    },
342    /// A typed method target such as `matrix.convert[f32]`, callable through
343    /// the ordinary [`ExprKind::Call`] form.
344    TypedMethod {
345        /// Receiver evaluated before method invocation.
346        object: Box<Expr>,
347        /// Method name.
348        method: String,
349        /// Statically supplied type argument.
350        ty: Type,
351    },
352    /// Read a class field.
353    Field {
354        /// Receiver expression.
355        object: Box<Expr>,
356        /// Selected class field name.
357        field: String,
358    },
359    /// Index or slice a collection or tensor.
360    Index {
361        /// Receiver expression.
362        object: Box<Expr>,
363        /// One or more NumPy-style index selectors.
364        indices: Vec<IndexExpr>,
365    },
366}
367/// A match arm retaining both its structural pattern and source expression.
368#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
369pub struct MatchArm {
370    /// Pattern tested against the scrutinee.
371    pub pattern: Pattern,
372    /// Value produced when the pattern matches.
373    pub value: Expr,
374    /// Exact source range of this construct.
375    pub span: Span,
376}
377/// Structural pattern syntax. Resolution and exhaustiveness are checker concerns.
378#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
379pub enum Pattern {
380    /// Matches any value without binding it.
381    Wildcard,
382    /// Binds a value to an identifier.
383    Binding(String),
384    /// Matches a scalar, text, Boolean, or unit literal.
385    Literal(Box<Expr>),
386    /// Matches an enum constructor with optional nested payload patterns.
387    Case {
388        /// Constructor name, optionally qualified by its enum name.
389        name: String,
390        /// Payload patterns in source order.
391        payload: Vec<Pattern>,
392    },
393    /// Matches a nominal record and its named fields.
394    Record {
395        /// Nominal record type name.
396        class: String,
397        /// Field patterns keyed by source field name.
398        fields: BTreeMap<String, Pattern>,
399    },
400}
401/// One selector in a collection or tensor indexing expression.
402#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
403pub enum IndexExpr {
404    /// Select a single position.
405    Index(Expr),
406    /// Select a range with optional start, stop, and step expressions.
407    Slice {
408        /// Inclusive start position, omitted when the range begins at the boundary.
409        start: Option<Box<Expr>>,
410        /// Exclusive stop position, omitted when the range ends at the boundary.
411        stop: Option<Box<Expr>>,
412        /// Optional stride, including negative strides.
413        step: Option<Box<Expr>>,
414    },
415    /// Insert a length-one axis (`None` or `newaxis`).
416    NewAxis,
417    /// Expand to the remaining tensor axes (`...`).
418    Ellipsis,
419}
420/// A statement and the source range used for execution tracing.
421#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
422pub struct Stmt {
423    /// The syntax operation represented by this node.
424    pub kind: StmtKind,
425    /// Exact source range of this construct.
426    pub span: Span,
427}
428/// Executable statement syntax with lexical binding and explicit control flow.
429#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
430pub enum StmtKind {
431    /// Introduce a lexical binding, with optional type annotation.
432    Let {
433        /// Declared or referenced source identifier.
434        name: String,
435        /// Declared type, checked at parameter, field, and assignment boundaries.
436        ty: Option<Type>,
437        /// Whether later assignment is permitted (`let mut`).
438        mutable: bool,
439        /// Operand, initializer, or assigned expression.
440        value: Expr,
441    },
442    /// Update an explicitly mutable binding or nested value.
443    Assign {
444        /// Variable, field, or list-element assignment destination.
445        target: Expr,
446        /// Operand, initializer, or assigned expression.
447        value: Expr,
448    },
449    /// Evaluate an expression for its state transition or result.
450    Expr(Expr),
451    /// Exit the current function with `ret`; no expression returns Unit.
452    Return(Option<Expr>),
453    /// Conditionally evaluate one branch.
454    If {
455        /// Condition expression, required to evaluate to Bool.
456        condition: Expr,
457        /// Statements evaluated when the condition is true.
458        then_body: Vec<Stmt>,
459        /// Statements evaluated when the condition is false.
460        else_body: Vec<Stmt>,
461    },
462    /// Repeat while a Bool condition is true; each iteration consumes fuel.
463    While {
464        /// Condition expression, required to evaluate to Bool.
465        condition: Expr,
466        /// Statements evaluated in lexical source order.
467        body: Vec<Stmt>,
468    },
469    /// Visit the elements of a list snapshot in order.
470    For {
471        /// Declared or referenced source identifier.
472        name: String,
473        /// List expression, snapshotted before the loop begins.
474        collection: Expr,
475        /// Statements evaluated in lexical source order.
476        body: Vec<Stmt>,
477    },
478    /// Exit the innermost loop.
479    Break,
480    /// Proceed to the next iteration of the innermost loop.
481    Continue,
482}