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),
Derive(DeriveDecl),
Decision(DecisionDecl),
Fragment(FragmentDecl),
Rule(RuleDecl),
Fixture(FixtureDecl),
Case(CaseDecl),
Invariant(InvariantDecl),
}
impl Declaration {
#[must_use]
pub fn name(&self) -> &Spanned<Name> {
match self {
Self::Enum(value) => &value.name,
Self::Entity(value) => &value.name,
Self::Derive(value) => &value.name,
Self::Decision(value) => &value.name,
Self::Fragment(value) => &value.id,
Self::Rule(value) => &value.name,
Self::Fixture(value) => &value.name,
Self::Case(value) => &value.name,
Self::Invariant(value) => &value.name,
}
}
#[must_use]
pub fn span(&self) -> Span {
match self {
Self::Enum(value) => value.span,
Self::Entity(value) => value.span,
Self::Derive(value) => value.span,
Self::Decision(value) => value.span,
Self::Fragment(value) => value.span,
Self::Rule(value) => value.span,
Self::Fixture(value) => value.span,
Self::Case(value) => value.span,
Self::Invariant(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 FieldDecl {
pub name: Spanned<Name>,
pub ty: TypeRef,
pub ty_span: Span,
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 start_inclusive: bool,
pub end_inclusive: bool,
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 implicit_type: bool,
pub implicit_binding: bool,
pub name: Spanned<Name>,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct DeriveDecl {
pub name: Spanned<Name>,
pub parameters: Vec<Parameter>,
pub implicit_parameters: bool,
pub return_type: Spanned<TypeRef>,
pub implicit_return_type: bool,
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 implicit_parameters: bool,
pub return_type: Spanned<TypeRef>,
pub cardinality: Cardinality,
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 implicit_parameters: bool,
pub condition: Expr,
pub effect: Effect,
pub overrides: Vec<RuleOverride>,
pub basis: Vec<FragmentRef>,
pub span: Span,
}
#[derive(Clone, Debug)]
pub struct RuleOverride {
pub rule: Spanned<Name>,
pub span: Span,
}
impl RuleDecl {
pub fn override_targets(&self) -> impl Iterator<Item = (&Spanned<Name>, Span)> {
let primary = match &self.effect {
Effect::Override { rule, span } => Some((rule, *span)),
Effect::Decide { .. } | Effect::Invalid { .. } => None,
};
primary.into_iter().chain(
self.overrides
.iter()
.map(|override_| (&override_.rule, override_.span)),
)
}
}
#[derive(Clone, Debug)]
pub enum Effect {
Decide {
decision: Spanned<Name>,
arguments: Vec<Expr>,
implicit_arguments: bool,
value: Expr,
span: Span,
},
Override {
rule: Spanned<Name>,
span: Span,
},
Invalid {
span: Span,
},
}
#[derive(Clone, Debug)]
pub struct FixtureDecl {
pub name: Spanned<Name>,
pub entity: Spanned<Name>,
pub fields: Vec<FieldValue>,
pub 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 fixture: Option<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 implicit_arguments: bool,
pub operator: CompareOp,
pub expected: ExpectedValue,
pub span: Span,
}
#[derive(Clone, Debug)]
pub enum ExpectedValue {
Scalar(Expr),
Set { values: Vec<Expr>, span: Span },
}
impl ExpectedValue {
#[must_use]
pub const fn span(&self) -> Span {
match self {
Self::Scalar(value) => value.span,
Self::Set { span, .. } => *span,
}
}
pub fn expressions(&self) -> impl Iterator<Item = &Expr> {
match self {
Self::Scalar(value) => std::slice::from_ref(value).iter(),
Self::Set { values, .. } => values.iter(),
}
}
pub fn expressions_mut(&mut self) -> impl Iterator<Item = &mut Expr> {
match self {
Self::Scalar(value) => std::slice::from_mut(value).iter_mut(),
Self::Set { values, .. } => values.iter_mut(),
}
}
}
#[derive(Clone, Debug)]
pub struct InvariantDecl {
pub name: Spanned<Name>,
pub quantifier: InvariantQuantifier,
pub variables: Vec<Parameter>,
pub implicit_variables: bool,
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 enum InvariantAssertion {
Cardinality {
cardinality: Cardinality,
decision: Spanned<Name>,
arguments: Vec<Expr>,
implicit_arguments: bool,
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>,
implicit_receiver: bool,
},
Call {
callee: Spanned<Name>,
arguments: Vec<Expr>,
implicit_arguments: bool,
postfix: bool,
},
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,
}