1use serde::Serialize;
12
13use crate::Span;
14
15#[derive(Debug, Clone, Serialize)]
21pub struct Module {
22 pub span: Span,
23 pub version: Option<u32>,
25 pub declarations: Vec<Decl>,
26}
27
28#[derive(Debug, Clone, Serialize)]
33pub enum Decl {
34 Use(UseDecl),
35 Block(BlockDecl),
36 Default(DefaultDecl),
37 Variant(VariantDecl),
38 Deferred(DeferredDecl),
39 OpenQuestion(OpenQuestionDecl),
40 Invariant(InvariantDecl),
41}
42
43#[derive(Debug, Clone, Serialize)]
45pub struct UseDecl {
46 pub span: Span,
47 pub path: StringLiteral,
48 pub alias: Option<Ident>,
49}
50
51#[derive(Debug, Clone, Serialize)]
53pub struct BlockDecl {
54 pub span: Span,
55 pub kind: BlockKind,
56 pub name: Option<Ident>,
58 pub items: Vec<BlockItem>,
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
62pub enum BlockKind {
63 Entity,
64 ExternalEntity,
65 Value,
66 Enum,
67 Given,
68 Config,
69 Rule,
70 Surface,
71 Actor,
72 Contract,
73 Invariant,
74}
75
76#[derive(Debug, Clone, Serialize)]
78pub struct DefaultDecl {
79 pub span: Span,
80 pub type_name: Option<Ident>,
81 pub name: Ident,
82 pub value: Expr,
83}
84
85#[derive(Debug, Clone, Serialize)]
87pub struct VariantDecl {
88 pub span: Span,
89 pub name: Ident,
90 pub base: Expr,
91 pub items: Vec<BlockItem>,
92}
93
94#[derive(Debug, Clone, Serialize)]
102pub struct DeferredDecl {
103 pub span: Span,
104 pub path: Expr,
105 pub location_hint: Option<StringLiteral>,
106}
107
108#[derive(Debug, Clone, Serialize)]
110pub struct OpenQuestionDecl {
111 pub span: Span,
112 pub text: StringLiteral,
113}
114
115#[derive(Debug, Clone, Serialize)]
117pub struct InvariantDecl {
118 pub span: Span,
119 pub name: Ident,
120 pub body: Expr,
121}
122
123#[derive(Debug, Clone, Serialize)]
129pub struct TransitionEdge {
130 pub span: Span,
131 pub from: Ident,
132 pub to: Ident,
133}
134
135#[derive(Debug, Clone, Serialize)]
137pub struct TransitionGraph {
138 pub span: Span,
139 pub field: Ident,
140 pub edges: Vec<TransitionEdge>,
141 pub terminal: Vec<Ident>,
142}
143
144#[derive(Debug, Clone, Serialize)]
150pub struct WhenClause {
151 pub span: Span,
152 pub status_field: Ident,
153 pub qualifying_states: Vec<Ident>,
154}
155
156#[derive(Debug, Clone, Serialize)]
161pub struct BlockItem {
162 pub span: Span,
163 pub kind: BlockItemKind,
164}
165
166#[derive(Debug, Clone, Serialize)]
167pub enum BlockItemKind {
168 Clause { keyword: String, value: Expr },
170 Assignment { name: Ident, value: Expr },
172 ParamAssignment {
174 name: Ident,
175 params: Vec<Ident>,
176 value: Expr,
177 },
178 Let { name: Ident, value: Expr },
180 EnumVariant { name: Ident, backtick_quoted: bool },
182 ForBlock {
184 binding: ForBinding,
185 collection: Expr,
186 filter: Option<Expr>,
187 items: Vec<BlockItem>,
188 },
189 IfBlock {
191 branches: Vec<CondBlockBranch>,
192 else_items: Option<Vec<BlockItem>>,
193 },
194 PathAssignment { path: Expr, value: Expr },
196 OpenQuestion { text: StringLiteral },
198 ContractsClause {
200 entries: Vec<ContractBinding>,
201 },
202 Annotation(Annotation),
204 InvariantBlock { name: Ident, body: Expr },
206 TransitionsBlock(TransitionGraph),
208 FieldWithWhen {
210 name: Ident,
211 value: Expr,
212 when_clause: WhenClause,
213 },
214}
215
216#[derive(Debug, Clone, Serialize)]
222pub enum ContractDirection {
223 Demands,
224 Fulfils,
225}
226
227#[derive(Debug, Clone, Serialize)]
229pub struct ContractBinding {
230 pub direction: ContractDirection,
231 pub qualifier: Option<String>,
234 pub name: Ident,
235 pub span: Span,
236}
237
238#[derive(Debug, Clone, Serialize)]
244pub enum AnnotationKind {
245 Invariant,
246 Guidance,
247 Guarantee,
248}
249
250#[derive(Debug, Clone, Serialize)]
252pub struct Annotation {
253 pub kind: AnnotationKind,
254 pub name: Option<Ident>,
255 pub body: Vec<String>,
256 pub span: Span,
257}
258
259#[derive(Debug, Clone, Serialize)]
264pub enum Expr {
265 Ident(Ident),
267
268 StringLiteral(StringLiteral),
270
271 BacktickLiteral { span: Span, value: String },
273
274 NumberLiteral { span: Span, value: String },
276
277 BoolLiteral { span: Span, value: bool },
279
280 Null { span: Span },
282
283 Now { span: Span },
285
286 This { span: Span },
288
289 Within { span: Span },
291
292 DurationLiteral { span: Span, value: String },
294
295 SetLiteral { span: Span, elements: Vec<Expr> },
297
298 ObjectLiteral { span: Span, fields: Vec<NamedArg> },
300
301 GenericType {
303 span: Span,
304 name: Box<Expr>,
305 args: Vec<Expr>,
306 },
307
308 MemberAccess {
310 span: Span,
311 object: Box<Expr>,
312 field: Ident,
313 },
314
315 OptionalAccess {
317 span: Span,
318 object: Box<Expr>,
319 field: Ident,
320 },
321
322 NullCoalesce {
324 span: Span,
325 left: Box<Expr>,
326 right: Box<Expr>,
327 },
328
329 Call {
331 span: Span,
332 function: Box<Expr>,
333 args: Vec<CallArg>,
334 },
335
336 JoinLookup {
338 span: Span,
339 entity: Box<Expr>,
340 fields: Vec<JoinField>,
341 },
342
343 BinaryOp {
345 span: Span,
346 left: Box<Expr>,
347 op: BinaryOp,
348 right: Box<Expr>,
349 },
350
351 Comparison {
353 span: Span,
354 left: Box<Expr>,
355 op: ComparisonOp,
356 right: Box<Expr>,
357 },
358
359 LogicalOp {
361 span: Span,
362 left: Box<Expr>,
363 op: LogicalOp,
364 right: Box<Expr>,
365 },
366
367 Not { span: Span, operand: Box<Expr> },
369
370 In {
372 span: Span,
373 element: Box<Expr>,
374 collection: Box<Expr>,
375 },
376
377 NotIn {
379 span: Span,
380 element: Box<Expr>,
381 collection: Box<Expr>,
382 },
383
384 Exists { span: Span, operand: Box<Expr> },
386
387 NotExists { span: Span, operand: Box<Expr> },
389
390 Where {
392 span: Span,
393 source: Box<Expr>,
394 condition: Box<Expr>,
395 },
396
397 With {
399 span: Span,
400 source: Box<Expr>,
401 predicate: Box<Expr>,
402 },
403
404 Pipe {
406 span: Span,
407 left: Box<Expr>,
408 right: Box<Expr>,
409 },
410
411 Lambda {
413 span: Span,
414 param: Box<Expr>,
415 body: Box<Expr>,
416 },
417
418 Conditional {
420 span: Span,
421 branches: Vec<CondBranch>,
422 else_body: Option<Box<Expr>>,
423 },
424
425 For {
427 span: Span,
428 binding: ForBinding,
429 collection: Box<Expr>,
430 filter: Option<Box<Expr>>,
431 body: Box<Expr>,
432 },
433
434 ProjectionMap {
436 span: Span,
437 source: Box<Expr>,
438 field: Ident,
439 },
440
441 TransitionsTo {
443 span: Span,
444 subject: Box<Expr>,
445 new_state: Box<Expr>,
446 },
447
448 Becomes {
450 span: Span,
451 subject: Box<Expr>,
452 new_state: Box<Expr>,
453 },
454
455 Binding {
457 span: Span,
458 name: Ident,
459 value: Box<Expr>,
460 },
461
462 WhenGuard {
464 span: Span,
465 action: Box<Expr>,
466 condition: Box<Expr>,
467 },
468
469 TypeOptional {
471 span: Span,
472 inner: Box<Expr>,
473 },
474
475 LetExpr {
477 span: Span,
478 name: Ident,
479 value: Box<Expr>,
480 },
481
482 QualifiedName(QualifiedName),
484
485 Block { span: Span, items: Vec<Expr> },
487
488}
489
490impl Expr {
491 pub fn span(&self) -> Span {
492 match self {
493 Expr::Ident(id) => id.span,
494 Expr::StringLiteral(s) => s.span,
495 Expr::BacktickLiteral { span, .. }
496 | Expr::NumberLiteral { span, .. }
497 | Expr::BoolLiteral { span, .. }
498 | Expr::Null { span }
499 | Expr::Now { span }
500 | Expr::This { span }
501 | Expr::Within { span }
502 | Expr::DurationLiteral { span, .. }
503 | Expr::SetLiteral { span, .. }
504 | Expr::ObjectLiteral { span, .. }
505 | Expr::GenericType { span, .. }
506 | Expr::MemberAccess { span, .. }
507 | Expr::OptionalAccess { span, .. }
508 | Expr::NullCoalesce { span, .. }
509 | Expr::Call { span, .. }
510 | Expr::JoinLookup { span, .. }
511 | Expr::BinaryOp { span, .. }
512 | Expr::Comparison { span, .. }
513 | Expr::LogicalOp { span, .. }
514 | Expr::Not { span, .. }
515 | Expr::In { span, .. }
516 | Expr::NotIn { span, .. }
517 | Expr::Exists { span, .. }
518 | Expr::NotExists { span, .. }
519 | Expr::Where { span, .. }
520 | Expr::With { span, .. }
521 | Expr::Pipe { span, .. }
522 | Expr::Lambda { span, .. }
523 | Expr::Conditional { span, .. }
524 | Expr::For { span, .. }
525 | Expr::ProjectionMap { span, .. }
526 | Expr::TransitionsTo { span, .. }
527 | Expr::Becomes { span, .. }
528 | Expr::Binding { span, .. }
529 | Expr::WhenGuard { span, .. }
530 | Expr::TypeOptional { span, .. }
531 | Expr::LetExpr { span, .. }
532 | Expr::Block { span, .. } => *span,
533 Expr::QualifiedName(q) => q.span,
534 }
535 }
536}
537
538#[derive(Debug, Clone, Serialize)]
539pub struct CondBranch {
540 pub span: Span,
541 pub condition: Expr,
542 pub body: Expr,
543}
544
545#[derive(Debug, Clone, Serialize)]
547pub struct CondBlockBranch {
548 pub span: Span,
549 pub condition: Expr,
550 pub items: Vec<BlockItem>,
551}
552
553#[derive(Debug, Clone, Serialize)]
556pub enum ForBinding {
557 Single(Ident),
558 Destructured(Vec<Ident>, Span),
559}
560
561#[derive(Debug, Clone, Serialize)]
566pub struct Ident {
567 pub span: Span,
568 pub name: String,
569}
570
571#[derive(Debug, Clone, Serialize)]
572pub struct QualifiedName {
573 pub span: Span,
574 pub qualifier: Option<String>,
575 pub name: String,
576}
577
578#[derive(Debug, Clone, Serialize)]
579pub struct StringLiteral {
580 pub span: Span,
581 pub parts: Vec<StringPart>,
582}
583
584impl StringLiteral {
585 pub fn text(&self) -> String {
589 let mut s = String::new();
590 for part in &self.parts {
591 if let StringPart::Text(t) = part {
592 s.push_str(t);
593 }
594 }
595 s
596 }
597}
598
599#[derive(Debug, Clone, Serialize)]
600pub enum StringPart {
601 Text(String),
602 Interpolation(Ident),
603}
604
605#[derive(Debug, Clone, Serialize)]
606pub struct NamedArg {
607 pub span: Span,
608 pub name: Ident,
609 pub value: Expr,
610}
611
612#[derive(Debug, Clone, Serialize)]
613pub enum CallArg {
614 Positional(Expr),
615 Named(NamedArg),
616}
617
618#[derive(Debug, Clone, Serialize)]
619pub struct JoinField {
620 pub span: Span,
621 pub field: Ident,
622 pub value: Option<Expr>,
624}
625
626#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
627pub enum BinaryOp {
628 Add,
629 Sub,
630 Mul,
631 Div,
632}
633
634#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
635pub enum ComparisonOp {
636 Eq,
637 NotEq,
638 Lt,
639 LtEq,
640 Gt,
641 GtEq,
642}
643
644#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
645pub enum LogicalOp {
646 And,
647 Or,
648 Implies,
649}