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}