use serde::Serialize;
use crate::Span;
#[derive(Debug, Clone, Serialize)]
pub struct Module {
pub span: Span,
pub version: Option<u32>,
pub declarations: Vec<Decl>,
}
#[derive(Debug, Clone, Serialize)]
pub enum Decl {
Use(UseDecl),
Block(BlockDecl),
Default(DefaultDecl),
Variant(VariantDecl),
Deferred(DeferredDecl),
OpenQuestion(OpenQuestionDecl),
Invariant(InvariantDecl),
}
#[derive(Debug, Clone, Serialize)]
pub struct UseDecl {
pub span: Span,
pub path: StringLiteral,
pub alias: Option<Ident>,
}
#[derive(Debug, Clone, Serialize)]
pub struct BlockDecl {
pub span: Span,
pub kind: BlockKind,
pub name: Option<Ident>,
pub items: Vec<BlockItem>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum BlockKind {
Entity,
ExternalEntity,
Value,
Enum,
Given,
Config,
Rule,
Surface,
Actor,
Contract,
Invariant,
}
#[derive(Debug, Clone, Serialize)]
pub struct DefaultDecl {
pub span: Span,
pub type_alias: Option<Ident>,
pub type_name: Option<Ident>,
pub name: Ident,
pub value: Expr,
}
#[derive(Debug, Clone, Serialize)]
pub struct VariantDecl {
pub span: Span,
pub name: Ident,
pub base: Expr,
pub items: Vec<BlockItem>,
}
#[derive(Debug, Clone, Serialize)]
pub struct DeferredDecl {
pub span: Span,
pub path: Expr,
pub location_hint: Option<StringLiteral>,
}
#[derive(Debug, Clone, Serialize)]
pub struct OpenQuestionDecl {
pub span: Span,
pub text: StringLiteral,
}
#[derive(Debug, Clone, Serialize)]
pub struct InvariantDecl {
pub span: Span,
pub name: Ident,
pub body: Expr,
}
#[derive(Debug, Clone, Serialize)]
pub struct TransitionEdge {
pub span: Span,
pub from: Ident,
pub to: Ident,
}
#[derive(Debug, Clone, Serialize)]
pub struct TransitionGraph {
pub span: Span,
pub field: Ident,
pub edges: Vec<TransitionEdge>,
pub terminal: Vec<Ident>,
}
#[derive(Debug, Clone, Serialize)]
pub struct WhenClause {
pub span: Span,
pub status_field: Ident,
pub qualifying_states: Vec<Ident>,
}
#[derive(Debug, Clone, Serialize)]
pub struct BlockItem {
pub span: Span,
pub kind: BlockItemKind,
}
#[derive(Debug, Clone, Serialize)]
pub enum BlockItemKind {
Clause { keyword: String, value: Expr },
Assignment { name: Ident, value: Expr },
ParamAssignment {
name: Ident,
params: Vec<Ident>,
value: Expr,
},
Let { name: Ident, value: Expr },
EnumVariant { name: Ident, backtick_quoted: bool },
ForBlock {
binding: ForBinding,
collection: Expr,
filter: Option<Expr>,
items: Vec<BlockItem>,
},
IfBlock {
branches: Vec<CondBlockBranch>,
else_items: Option<Vec<BlockItem>>,
},
PathAssignment { path: Expr, value: Expr },
OpenQuestion { text: StringLiteral },
ContractsClause {
entries: Vec<ContractBinding>,
},
Annotation(Annotation),
InvariantBlock { name: Ident, body: Expr },
TransitionsBlock(TransitionGraph),
FieldWithWhen {
name: Ident,
value: Expr,
when_clause: WhenClause,
},
}
#[derive(Debug, Clone, Serialize)]
pub enum ContractDirection {
Demands,
Fulfils,
}
#[derive(Debug, Clone, Serialize)]
pub struct ContractBinding {
pub direction: ContractDirection,
pub qualifier: Option<String>,
pub name: Ident,
pub span: Span,
}
#[derive(Debug, Clone, Serialize)]
pub enum AnnotationKind {
Invariant,
Guidance,
Guarantee,
}
#[derive(Debug, Clone, Serialize)]
pub struct Annotation {
pub kind: AnnotationKind,
pub name: Option<Ident>,
pub body: Vec<String>,
pub span: Span,
}
#[derive(Debug, Clone, Serialize)]
pub enum Expr {
Ident(Ident),
StringLiteral(StringLiteral),
BacktickLiteral { span: Span, value: String },
NumberLiteral { span: Span, value: String },
BoolLiteral { span: Span, value: bool },
Null { span: Span },
Now { span: Span },
This { span: Span },
Within { span: Span },
DurationLiteral { span: Span, value: String },
SetLiteral { span: Span, elements: Vec<Expr> },
ListLiteral { span: Span, elements: Vec<Expr> },
ObjectLiteral { span: Span, fields: Vec<NamedArg> },
GenericType {
span: Span,
name: Box<Expr>,
args: Vec<Expr>,
},
MemberAccess {
span: Span,
object: Box<Expr>,
field: Ident,
},
OptionalAccess {
span: Span,
object: Box<Expr>,
field: Ident,
},
NullCoalesce {
span: Span,
left: Box<Expr>,
right: Box<Expr>,
},
Call {
span: Span,
function: Box<Expr>,
args: Vec<CallArg>,
},
JoinLookup {
span: Span,
entity: Box<Expr>,
fields: Vec<JoinField>,
},
BinaryOp {
span: Span,
left: Box<Expr>,
op: BinaryOp,
right: Box<Expr>,
},
Comparison {
span: Span,
left: Box<Expr>,
op: ComparisonOp,
right: Box<Expr>,
},
LogicalOp {
span: Span,
left: Box<Expr>,
op: LogicalOp,
right: Box<Expr>,
},
Not { span: Span, operand: Box<Expr> },
In {
span: Span,
element: Box<Expr>,
collection: Box<Expr>,
},
NotIn {
span: Span,
element: Box<Expr>,
collection: Box<Expr>,
},
Exists { span: Span, operand: Box<Expr> },
NotExists { span: Span, operand: Box<Expr> },
Where {
span: Span,
source: Box<Expr>,
condition: Box<Expr>,
},
With {
span: Span,
source: Box<Expr>,
predicate: Box<Expr>,
},
Pipe {
span: Span,
left: Box<Expr>,
right: Box<Expr>,
},
Lambda {
span: Span,
param: Box<Expr>,
body: Box<Expr>,
},
Conditional {
span: Span,
branches: Vec<CondBranch>,
else_body: Option<Box<Expr>>,
},
For {
span: Span,
binding: ForBinding,
collection: Box<Expr>,
filter: Option<Box<Expr>>,
body: Box<Expr>,
},
ProjectionMap {
span: Span,
source: Box<Expr>,
field: Ident,
},
TransitionsTo {
span: Span,
subject: Box<Expr>,
new_state: Box<Expr>,
},
Becomes {
span: Span,
subject: Box<Expr>,
new_state: Box<Expr>,
},
Binding {
span: Span,
name: Ident,
value: Box<Expr>,
},
WhenGuard {
span: Span,
action: Box<Expr>,
condition: Box<Expr>,
},
TypeOptional {
span: Span,
inner: Box<Expr>,
},
LetExpr {
span: Span,
name: Ident,
value: Box<Expr>,
},
QualifiedName(QualifiedName),
Block { span: Span, items: Vec<Expr> },
}
impl Expr {
pub fn span(&self) -> Span {
match self {
Expr::Ident(id) => id.span,
Expr::StringLiteral(s) => s.span,
Expr::BacktickLiteral { span, .. }
| Expr::NumberLiteral { span, .. }
| Expr::BoolLiteral { span, .. }
| Expr::Null { span }
| Expr::Now { span }
| Expr::This { span }
| Expr::Within { span }
| Expr::DurationLiteral { span, .. }
| Expr::SetLiteral { span, .. }
| Expr::ListLiteral { span, .. }
| Expr::ObjectLiteral { span, .. }
| Expr::GenericType { span, .. }
| Expr::MemberAccess { span, .. }
| Expr::OptionalAccess { span, .. }
| Expr::NullCoalesce { span, .. }
| Expr::Call { span, .. }
| Expr::JoinLookup { span, .. }
| Expr::BinaryOp { span, .. }
| Expr::Comparison { span, .. }
| Expr::LogicalOp { span, .. }
| Expr::Not { span, .. }
| Expr::In { span, .. }
| Expr::NotIn { span, .. }
| Expr::Exists { span, .. }
| Expr::NotExists { span, .. }
| Expr::Where { span, .. }
| Expr::With { span, .. }
| Expr::Pipe { span, .. }
| Expr::Lambda { span, .. }
| Expr::Conditional { span, .. }
| Expr::For { span, .. }
| Expr::ProjectionMap { span, .. }
| Expr::TransitionsTo { span, .. }
| Expr::Becomes { span, .. }
| Expr::Binding { span, .. }
| Expr::WhenGuard { span, .. }
| Expr::TypeOptional { span, .. }
| Expr::LetExpr { span, .. }
| Expr::Block { span, .. } => *span,
Expr::QualifiedName(q) => q.span,
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct CondBranch {
pub span: Span,
pub condition: Expr,
pub body: Expr,
}
#[derive(Debug, Clone, Serialize)]
pub struct CondBlockBranch {
pub span: Span,
pub condition: Expr,
pub items: Vec<BlockItem>,
}
#[derive(Debug, Clone, Serialize)]
pub enum ForBinding {
Single(Ident),
Destructured(Vec<Ident>, Span),
}
#[derive(Debug, Clone, Serialize)]
pub struct Ident {
pub span: Span,
pub name: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct QualifiedName {
pub span: Span,
pub qualifier: Option<String>,
pub name: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct StringLiteral {
pub span: Span,
pub parts: Vec<StringPart>,
}
impl StringLiteral {
pub fn text(&self) -> String {
let mut s = String::new();
for part in &self.parts {
if let StringPart::Text(t) = part {
s.push_str(t);
}
}
s
}
}
#[derive(Debug, Clone, Serialize)]
pub enum StringPart {
Text(String),
Interpolation(Ident),
}
#[derive(Debug, Clone, Serialize)]
pub struct NamedArg {
pub span: Span,
pub name: Ident,
pub value: Expr,
}
#[derive(Debug, Clone, Serialize)]
pub enum CallArg {
Positional(Expr),
Named(NamedArg),
}
#[derive(Debug, Clone, Serialize)]
pub struct JoinField {
pub span: Span,
pub field: Ident,
pub value: Option<Expr>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum BinaryOp {
Add,
Sub,
Mul,
Div,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum ComparisonOp {
Eq,
NotEq,
Lt,
LtEq,
Gt,
GtEq,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum LogicalOp {
And,
Or,
Implies,
}