1use crate::Span;
8#[allow(unused_imports)]
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
17pub struct Program {
18 pub space: SpaceDecl,
19 pub tests: Vec<TestsBlock>,
20 pub span: Span,
21}
22
23#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
25pub struct SpaceDecl {
26 pub name: Ident,
27 pub body: SpaceBody,
28 pub span: Span,
29}
30
31#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
36pub struct SpaceBody {
37 pub types: Vec<TypeDecl>,
38 pub state: StateBlock,
39 pub capabilities: Option<CapabilitiesBlock>,
40 pub credentials: Option<CredentialsBlock>,
41 pub derived: Option<DerivedBlock>,
42 pub invariants: Vec<InvariantDecl>,
43 pub actions: Vec<ActionDecl>,
44 pub views: Vec<ViewDecl>,
45 pub update: Option<UpdateDecl>,
46 pub handle_event: Option<HandleEventDecl>,
47 pub span: Span,
48}
49
50#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
56pub struct Ident {
57 pub name: String,
58 pub span: Span,
59}
60
61impl Ident {
62 pub fn new(name: impl Into<String>, span: Span) -> Self {
63 Self {
64 name: name.into(),
65 span,
66 }
67 }
68}
69
70#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
76pub struct TypeDecl {
77 pub name: Ident,
78 pub body: TypeDeclBody,
79 pub span: Span,
80}
81
82#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
84pub enum TypeDeclBody {
85 SumType(Vec<VariantDef>),
87 Alias(TypeAnnotation),
89}
90
91#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
93pub struct VariantDef {
94 pub name: Ident,
95 pub params: Vec<Param>,
96 pub span: Span,
97}
98
99#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
105pub struct StateBlock {
106 pub fields: Vec<StateField>,
107 pub span: Span,
108}
109
110#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
112pub struct StateField {
113 pub name: Ident,
114 pub type_ann: TypeAnnotation,
115 pub default: Expr,
116 pub span: Span,
117}
118
119#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
121pub struct CapabilitiesBlock {
122 pub required: Vec<Ident>,
123 pub optional: Vec<Ident>,
124 pub span: Span,
125}
126
127#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
129pub struct CredentialsBlock {
130 pub fields: Vec<CredentialField>,
131 pub span: Span,
132}
133
134#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
136pub struct CredentialField {
137 pub name: Ident,
138 pub type_ann: TypeAnnotation,
139 pub span: Span,
140}
141
142#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
144pub struct DerivedBlock {
145 pub fields: Vec<DerivedField>,
146 pub span: Span,
147}
148
149#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
151pub struct DerivedField {
152 pub name: Ident,
153 pub type_ann: TypeAnnotation,
154 pub value: Expr,
155 pub span: Span,
156}
157
158#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
164pub struct InvariantDecl {
165 pub name: Ident,
166 pub condition: Expr,
167 pub span: Span,
168}
169
170#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
176pub struct ActionDecl {
177 pub name: Ident,
178 pub params: Vec<Param>,
179 pub body: Block,
180 pub span: Span,
181}
182
183#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
185pub struct Param {
186 pub name: Ident,
187 pub type_ann: TypeAnnotation,
188 pub span: Span,
189}
190
191#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
193pub struct Block {
194 pub stmts: Vec<Stmt>,
195 pub span: Span,
196}
197
198#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
204pub struct ViewDecl {
205 pub name: Ident,
206 pub params: Vec<Param>,
207 pub body: UIBlock,
208 pub span: Span,
209}
210
211#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
213pub struct UIBlock {
214 pub elements: Vec<UIElement>,
215 pub span: Span,
216}
217
218#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
220pub enum UIElement {
221 Component(ComponentExpr),
223 Let(LetBinding),
225 If(UIIf),
227 For(UIFor),
229}
230
231#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
233pub struct ComponentExpr {
234 pub name: Ident,
235 pub props: Vec<PropAssign>,
236 pub children: Option<UIBlock>,
237 pub span: Span,
238}
239
240#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
242pub struct PropAssign {
243 pub name: Ident,
244 pub value: Expr,
245 pub span: Span,
246}
247
248#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
250pub struct UIIf {
251 pub condition: Expr,
252 pub then_block: UIBlock,
253 pub else_block: Option<UIElse>,
254 pub span: Span,
255}
256
257#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
259pub enum UIElse {
260 ElseIf(Box<UIIf>),
261 Block(UIBlock),
262}
263
264#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
266pub struct UIFor {
267 pub item: Ident,
268 pub index: Option<Ident>,
269 pub iterable: Expr,
270 pub body: UIBlock,
271 pub span: Span,
272}
273
274#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
280pub struct UpdateDecl {
281 pub param: Param,
282 pub body: Block,
283 pub span: Span,
284}
285
286#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
288pub struct HandleEventDecl {
289 pub param: Param,
290 pub body: Block,
291 pub span: Span,
292}
293
294#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
300pub struct TestsBlock {
301 pub cases: Vec<TestCase>,
302 pub span: Span,
303}
304
305#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
307pub struct TestCase {
308 pub description: String,
309 pub with_responses: Option<WithResponses>,
310 pub body: Block,
311 pub span: Span,
312}
313
314#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
316pub struct WithResponses {
317 pub mappings: Vec<ResponseMapping>,
318 pub span: Span,
319}
320
321#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
323pub struct ResponseMapping {
324 pub module: Ident,
325 pub function: Ident,
326 pub args: Vec<Expr>,
327 pub response: Expr,
328 pub span: Span,
329}
330
331#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
337pub enum Stmt {
338 Set(SetStmt),
340 Let(LetBinding),
342 If(IfExpr),
344 For(ForExpr),
346 Match(MatchExpr),
348 Return(ReturnStmt),
350 Assert(AssertStmt),
352 Expr(ExprStmt),
354}
355
356#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
358pub struct SetStmt {
359 pub target: Vec<Ident>,
361 pub value: Expr,
362 pub span: Span,
363}
364
365#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
367pub struct LetBinding {
368 pub name: Option<Ident>,
370 pub type_ann: Option<TypeAnnotation>,
371 pub value: Expr,
372 pub span: Span,
373}
374
375#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
377pub struct ReturnStmt {
378 pub span: Span,
379}
380
381#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
383pub struct AssertStmt {
384 pub condition: Expr,
385 pub message: Option<String>,
386 pub span: Span,
387}
388
389#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
391pub struct ExprStmt {
392 pub expr: Expr,
393 pub span: Span,
394}
395
396#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
402pub struct Expr {
403 pub kind: ExprKind,
404 pub span: Span,
405}
406
407impl Expr {
408 pub fn new(kind: ExprKind, span: Span) -> Self {
409 Self { kind, span }
410 }
411}
412
413#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
415pub enum ExprKind {
416 NumberLit(f64),
419 StringLit(String),
421 StringInterpolation(Vec<StringPart>),
423 BoolLit(bool),
425 NilLit,
427 ListLit(Vec<Expr>),
429 RecordLit(Vec<RecordEntry>),
431
432 Identifier(String),
435 Call { name: Ident, args: Vec<Expr> },
437 QualifiedCall {
439 module: Ident,
440 function: Ident,
441 args: Vec<Expr>,
442 },
443 FieldAccess { object: Box<Expr>, field: Ident },
445 MethodCall {
447 object: Box<Expr>,
448 method: Ident,
449 args: Vec<Expr>,
450 },
451
452 Binary {
455 left: Box<Expr>,
456 op: BinOp,
457 right: Box<Expr>,
458 },
459 Unary { op: UnaryOp, operand: Box<Expr> },
461 ResultUnwrap(Box<Expr>),
463 NilCoalesce { left: Box<Expr>, right: Box<Expr> },
465
466 If(Box<IfExpr>),
469 For(Box<ForExpr>),
471 Match(Box<MatchExpr>),
473
474 Lambda(Box<LambdaExpr>),
477
478 Paren(Box<Expr>),
481}
482
483#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
485pub enum StringPart {
486 Literal(String),
488 Expr(Expr),
490}
491
492#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
494pub enum RecordEntry {
495 Field { name: Ident, value: Expr },
497 Spread(Expr),
499}
500
501#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
505pub enum BinOp {
506 Or,
508 And,
509 Eq,
511 NotEq,
512 Less,
513 Greater,
514 LessEq,
515 GreaterEq,
516 Add,
518 Sub,
519 Mul,
520 Div,
521 Mod,
522}
523
524impl BinOp {
525 pub fn as_str(&self) -> &'static str {
527 match self {
528 BinOp::Or => "or",
529 BinOp::And => "and",
530 BinOp::Eq => "==",
531 BinOp::NotEq => "!=",
532 BinOp::Less => "<",
533 BinOp::Greater => ">",
534 BinOp::LessEq => "<=",
535 BinOp::GreaterEq => ">=",
536 BinOp::Add => "+",
537 BinOp::Sub => "-",
538 BinOp::Mul => "*",
539 BinOp::Div => "/",
540 BinOp::Mod => "%",
541 }
542 }
543}
544
545#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
547pub enum UnaryOp {
548 Neg,
550 Not,
552}
553
554#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
558pub struct IfExpr {
559 pub condition: Expr,
560 pub then_block: Block,
561 pub else_branch: Option<ElseBranch>,
562 pub span: Span,
563}
564
565#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
567pub enum ElseBranch {
568 ElseIf(Box<IfExpr>),
570 Block(Block),
572}
573
574#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
576pub struct ForExpr {
577 pub item: Ident,
578 pub index: Option<Ident>,
579 pub iterable: Expr,
580 pub body: Block,
581 pub span: Span,
582}
583
584#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
586pub struct MatchExpr {
587 pub subject: Expr,
588 pub arms: Vec<MatchArm>,
589 pub span: Span,
590}
591
592#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
594pub struct MatchArm {
595 pub pattern: Pattern,
596 pub body: MatchArmBody,
597 pub span: Span,
598}
599
600#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
602pub enum MatchArmBody {
603 Expr(Expr),
604 Block(Block),
605}
606
607#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
609pub enum Pattern {
610 Variant { name: Ident, bindings: Vec<Ident> },
612 Wildcard(Span),
614}
615
616#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
620pub struct LambdaExpr {
621 pub params: Vec<Param>,
622 pub body: Block,
623 pub span: Span,
624}
625
626#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
632pub struct TypeAnnotation {
633 pub kind: TypeKind,
634 pub span: Span,
635}
636
637impl TypeAnnotation {
638 pub fn new(kind: TypeKind, span: Span) -> Self {
639 Self { kind, span }
640 }
641}
642
643impl std::fmt::Display for TypeAnnotation {
644 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
645 write!(f, "{}", self.kind)
646 }
647}
648
649impl std::fmt::Display for TypeKind {
650 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
651 match self {
652 TypeKind::Number => write!(f, "number"),
653 TypeKind::String => write!(f, "string"),
654 TypeKind::Bool => write!(f, "bool"),
655 TypeKind::Nil => write!(f, "nil"),
656 TypeKind::Any => write!(f, "any"),
657 TypeKind::Color => write!(f, "color"),
658 TypeKind::Surface => write!(f, "Surface"),
659 TypeKind::InputEvent => write!(f, "InputEvent"),
660 TypeKind::List(inner) => write!(f, "list<{}>", inner),
661 TypeKind::Record(fields) => {
662 write!(f, "{{ ")?;
663 for (i, field) in fields.iter().enumerate() {
664 if i > 0 {
665 write!(f, ", ")?;
666 }
667 if field.optional {
668 write!(f, "{}?: {}", field.name.name, field.type_ann)?;
669 } else {
670 write!(f, "{}: {}", field.name.name, field.type_ann)?;
671 }
672 }
673 write!(f, " }}")
674 }
675 TypeKind::Result(ok, err) => write!(f, "Result<{}, {}>", ok, err),
676 TypeKind::Function { params, ret } => {
677 write!(f, "(")?;
678 for (i, p) in params.iter().enumerate() {
679 if i > 0 {
680 write!(f, ", ")?;
681 }
682 write!(f, "{}", p)?;
683 }
684 write!(f, ") -> {}", ret)
685 }
686 TypeKind::Named(name) => write!(f, "{}", name),
687 }
688 }
689}
690
691#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
693pub enum TypeKind {
694 Number,
696 String,
698 Bool,
700 Nil,
702 Any,
704 Color,
706 Surface,
708 InputEvent,
710 List(Box<TypeAnnotation>),
712 Record(Vec<RecordTypeField>),
714 Result(Box<TypeAnnotation>, Box<TypeAnnotation>),
716 Function {
718 params: Vec<TypeAnnotation>,
719 ret: Box<TypeAnnotation>,
720 },
721 Named(String),
723}
724
725#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
727pub struct RecordTypeField {
728 pub name: Ident,
729 pub optional: bool,
730 pub type_ann: TypeAnnotation,
731 pub span: Span,
732}