use crate::source::{SourceFile, Span, Spanned};
use serde::{Deserialize, Serialize};
pub type Name = String;
#[derive(Clone, Debug)]
pub struct Program {
pub source: SourceFile,
pub module: Spanned<Name>,
pub imports: Vec<ImportDecl>,
pub imports_resolved: bool,
pub declarations: Vec<Declaration>,
}
#[derive(Clone, Debug)]
pub struct ImportDecl {
pub path: Spanned<String>,
pub span: Span,
}
#[derive(Clone, Debug)]
pub enum Declaration {
Enum(EnumDecl),
Entity(EntityDecl),
State(StateDecl),
Derive(DeriveDecl),
Decision(DecisionDecl),
Action(ActionDecl),
Transition(TransitionDecl),
Fragment(FragmentDecl),
Rule(RuleDecl),
Case(CaseDecl),
Invariant(InvariantDecl),
Trace(TraceDecl),
}
impl Declaration {
#[must_use]
pub fn name(&self) -> &Spanned<Name> {
match self {
Self::Enum(value) => &value.name,
Self::Entity(value) => &value.name,
Self::State(value) => &value.name,
Self::Derive(value) => &value.name,
Self::Decision(value) => &value.name,
Self::Action(value) => &value.name,
Self::Transition(value) => &value.name,
Self::Fragment(value) => &value.id,
Self::Rule(value) => &value.name,
Self::Case(value) => &value.name,
Self::Invariant(value) => &value.name,
Self::Trace(value) => &value.name,
}
}
#[must_use]
pub fn span(&self) -> Span {
match self {
Self::Enum(value) => value.span,
Self::Entity(value) => value.span,
Self::State(value) => value.span,
Self::Derive(value) => value.span,
Self::Decision(value) => value.span,
Self::Action(value) => value.span,
Self::Transition(value) => value.span,
Self::Fragment(value) => value.span,
Self::Rule(value) => value.span,
Self::Case(value) => value.span,
Self::Invariant(value) => value.span,
Self::Trace(value) => value.span,
}
}
}
#[derive(Clone, Debug)]
pub struct EnumDecl {
pub name: Spanned<Name>,
pub variants: Vec<Spanned<Name>>,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct EntityDecl {
pub name: Spanned<Name>,
pub fields: Vec<FieldDecl>,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct StateDecl {
pub name: Spanned<Name>,
pub fields: Vec<FieldDecl>,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct FieldDecl {
pub name: Spanned<Name>,
pub ty: TypeRef,
pub range: Option<RangeConstraint>,
pub domain: Option<DomainConstraint>,
pub optional: bool,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum TypeRef {
Bool,
Int,
Decimal,
String,
Date,
Duration,
Named(Name),
Unknown,
}
#[derive(Clone, Debug)]
pub struct RangeConstraint {
pub start: NumericLiteral,
pub end: NumericLiteral,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct DomainConstraint {
pub values: Vec<Expr>,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct Parameter {
pub ty: Spanned<Name>,
pub name: Spanned<Name>,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct DeriveDecl {
pub name: Spanned<Name>,
pub parameters: Vec<Parameter>,
pub return_type: Spanned<TypeRef>,
pub expression: Expr,
pub basis: Vec<FragmentRef>,
pub span: Span,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Cardinality {
#[default]
ExactlyOne,
ZeroOrOne,
Many,
}
#[derive(Clone, Debug)]
pub struct DecisionDecl {
pub name: Spanned<Name>,
pub parameters: Vec<Parameter>,
pub return_type: Spanned<TypeRef>,
pub cardinality: Cardinality,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct ActionDecl {
pub name: Spanned<Name>,
pub parameters: Vec<Parameter>,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct TransitionDecl {
pub name: Spanned<Name>,
pub parameters: Vec<Parameter>,
pub action: Spanned<Name>,
pub action_arguments: Vec<Expr>,
pub condition: Expr,
pub updates: Vec<StateUpdate>,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct StateUpdate {
pub receiver: Spanned<Name>,
pub field: Spanned<Name>,
pub value: Expr,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct FragmentDecl {
pub id: Spanned<Name>,
pub locator: Spanned<String>,
pub text: Spanned<String>,
pub refs: Vec<FragmentRef>,
pub derives: Vec<DeriveDecl>,
pub rules: Vec<RuleDecl>,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct FragmentRef {
pub id: Spanned<Name>,
}
impl FragmentRef {
#[must_use]
pub const fn span(&self) -> Span {
self.id.span
}
}
#[derive(Clone, Debug)]
pub struct RuleDecl {
pub name: Spanned<Name>,
pub parameters: Vec<Parameter>,
pub condition: Expr,
pub effect: Effect,
pub basis: Vec<FragmentRef>,
pub span: Span,
}
#[derive(Clone, Debug)]
pub enum Effect {
Decide {
decision: Spanned<Name>,
arguments: Vec<Expr>,
value: Expr,
span: Span,
},
Override {
rule: Spanned<Name>,
span: Span,
},
Invalid {
span: Span,
},
}
#[derive(Clone, Debug)]
pub struct CaseDecl {
pub name: Spanned<Name>,
pub bindings: Vec<BindingDecl>,
pub expectations: Vec<Expectation>,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct BindingDecl {
pub name: Spanned<Name>,
pub entity: Spanned<Name>,
pub fields: Vec<FieldValue>,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct FieldValue {
pub name: Spanned<Name>,
pub value: Expr,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct Expectation {
pub decision: Spanned<Name>,
pub arguments: Vec<Expr>,
pub operator: CompareOp,
pub value: Expr,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct InvariantDecl {
pub name: Spanned<Name>,
pub quantifier: InvariantQuantifier,
pub variables: Vec<Parameter>,
pub assertion: InvariantAssertion,
pub span: Span,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum InvariantQuantifier {
#[default]
All,
Some,
}
#[derive(Clone, Debug)]
pub struct TraceDecl {
pub name: Spanned<Name>,
pub variable: Parameter,
pub initial: Expr,
pub always: Vec<Expr>,
pub terminal: Option<Expr>,
pub no_dead_ends: bool,
pub within: Spanned<usize>,
pub span: Span,
}
#[derive(Clone, Debug)]
pub enum InvariantAssertion {
Cardinality {
cardinality: Cardinality,
decision: Spanned<Name>,
arguments: Vec<Expr>,
span: Span,
},
Implication {
condition: Expr,
expectation: Expectation,
span: Span,
},
}
#[derive(Clone, Debug)]
pub struct Expr {
pub kind: ExprKind,
pub span: Span,
}
impl Expr {
#[must_use]
pub const fn new(kind: ExprKind, span: Span) -> Self {
Self { kind, span }
}
}
#[derive(Clone, Debug)]
pub enum ExprKind {
Literal(Literal),
Name(Name),
Field {
receiver: Box<Expr>,
field: Spanned<Name>,
},
Call {
callee: Spanned<Name>,
arguments: Vec<Expr>,
},
Unary {
operator: UnaryOp,
operand: Box<Expr>,
},
Binary {
left: Box<Expr>,
operator: BinaryOp,
right: Box<Expr>,
},
}
#[derive(Clone, Debug)]
pub enum Literal {
Bool(bool),
Number(NumericLiteral),
String(String),
Unknown,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum NumericLiteral {
Int(i64),
Decimal(String),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum UnaryOp {
Not,
Negate,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BinaryOp {
Or,
And,
Equal,
NotEqual,
Greater,
GreaterEqual,
Less,
LessEqual,
Add,
Subtract,
Multiply,
Divide,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CompareOp {
Equal,
NotEqual,
}