use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
#[non_exhaustive]
pub enum Commitment {
#[serde(rename = "none")]
#[default]
None,
#[serde(rename = "?")]
Question,
#[serde(rename = "??")]
QuestionQuestion,
#[serde(rename = "$")]
Locked,
#[serde(rename = "$$")]
StrongLocked,
#[serde(rename = "$?")]
LockedQuestion,
#[serde(rename = "$$?")]
StrongLockedQuestion,
#[serde(rename = "$??")]
LockedQuestionQuestion,
#[serde(rename = "$$??")]
StrongLockedQuestionQuestion,
}
#[allow(dead_code)]
impl Commitment {
pub fn is_locked(&self) -> bool {
matches!(
self,
Self::Locked
| Self::StrongLocked
| Self::LockedQuestion
| Self::StrongLockedQuestion
| Self::LockedQuestionQuestion
| Self::StrongLockedQuestionQuestion
)
}
pub fn is_strong_locked(&self) -> bool {
matches!(
self,
Self::StrongLocked | Self::StrongLockedQuestion | Self::StrongLockedQuestionQuestion
)
}
pub fn has_question(&self) -> bool {
matches!(
self,
Self::Question
| Self::LockedQuestion
| Self::StrongLockedQuestion
| Self::QuestionQuestion
| Self::LockedQuestionQuestion
| Self::StrongLockedQuestionQuestion
)
}
pub fn has_question_question(&self) -> bool {
matches!(self, Self::QuestionQuestion)
}
}
impl std::fmt::Display for Commitment {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
Commitment::None => "",
Commitment::Question => "?",
Commitment::QuestionQuestion => "??",
Commitment::Locked => "$",
Commitment::StrongLocked => "$$",
Commitment::LockedQuestion => "$?",
Commitment::StrongLockedQuestion => "$$?",
Commitment::LockedQuestionQuestion => "$??",
Commitment::StrongLockedQuestionQuestion => "$$??",
};
write!(f, "{}", s)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Ident {
pub name: String,
#[serde(default)]
pub commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FString {
pub value: String,
#[serde(default)]
pub commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct File {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub imports: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub rules: Vec<RuleDef>,
pub fragments: Vec<Fragment>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind")]
#[non_exhaustive]
pub enum Fragment {
Module {
module: Module,
},
TypeDef {
typedef: TypeDef,
},
Flow {
flow: FlowDef,
},
Func {
func: FuncDef,
},
Ui {
ui: UiDef,
},
Steps {
#[serde(default)]
keyword_commitment: Commitment,
steps: Vec<Step>,
},
Expr {
expr: Expr,
}, UiNode {
node: UiNode,
}, Placeholder {
#[serde(default)]
keyword_commitment: Commitment,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Module {
pub name: Ident,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub desc: Option<Desc>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub rules: Vec<RuleDef>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub math: Option<MathBlock>,
#[serde(default)]
pub items: Vec<Fragment>, #[serde(default)]
pub keyword_commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TypeDef {
pub name: Ident,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub desc: Option<Desc>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub rules: Vec<RuleDef>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub math: Option<MathBlock>,
pub body: TypeBody,
#[serde(default)]
pub keyword_commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind")]
#[non_exhaustive]
pub enum TypeBody {
Enum { variants: Vec<Ident> },
Record { fields: Vec<Field> },
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Field {
pub name: Ident,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub rules: Vec<RuleDef>,
pub type_hint: Vec<Atom>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RuleDef {
pub desc: Desc,
#[serde(default)]
pub keyword_commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct FlowDef {
pub name: Ident,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub rules: Vec<RuleDef>,
pub entries: Vec<FlowEntry>,
#[serde(default)]
pub keyword_commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct FlowEntry {
pub state: Ident,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub rules: Vec<RuleDef>,
pub arms: Vec<FlowArm>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct FlowArm {
pub to: Ident,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub requires: Option<Condition>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub desc: Option<Desc>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub rules: Vec<RuleDef>,
#[serde(default)]
pub to_keyword_commitment: Commitment,
#[serde(default)]
pub requires_keyword_commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct FuncDef {
pub name: Ident,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub desc: Option<Desc>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub rules: Vec<RuleDef>,
pub params: Vec<Param>,
#[serde(default)]
pub capabilities: Vec<Capability>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub requires: Option<Condition>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ensures: Option<Condition>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub math: Option<MathBlock>,
pub steps: Vec<Step>,
#[serde(default)]
pub keyword_commitment: Commitment,
#[serde(default)]
pub requires_keyword_commitment: Commitment,
#[serde(default)]
pub ensures_keyword_commitment: Commitment,
#[serde(default)]
pub with_keyword_commitment: Commitment,
#[serde(default)]
pub steps_keyword_commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Param {
pub name: Ident,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub type_hint: Vec<Atom>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Capability {
pub name: Ident,
#[serde(default)]
pub commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind")]
#[non_exhaustive]
pub enum Condition {
Structured { expr: Expr },
Natural { text: FString },
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind")]
#[non_exhaustive]
pub enum Expr {
Ident {
value: Ident,
},
String {
value: FString,
},
Number {
value: String,
},
Bool {
value: bool,
#[serde(default)]
keyword_commitment: Commitment,
},
List {
items: Vec<Expr>,
},
Not {
expr: Box<Expr>,
#[serde(default)]
keyword_commitment: Commitment,
},
And {
left: Box<Expr>,
right: Box<Expr>,
#[serde(default)]
keyword_commitment: Commitment,
},
Or {
left: Box<Expr>,
right: Box<Expr>,
#[serde(default)]
keyword_commitment: Commitment,
},
In {
left: Box<Expr>,
right: Box<Expr>,
#[serde(default)]
keyword_commitment: Commitment,
},
Compare {
left: Box<Expr>,
op: CompareOp,
right: Box<Expr>,
#[serde(default)]
keyword_commitment: Commitment,
},
Neg {
expr: Box<Expr>,
#[serde(default)]
keyword_commitment: Commitment,
},
Add {
left: Box<Expr>,
right: Box<Expr>,
},
Sub {
left: Box<Expr>,
right: Box<Expr>,
},
Mul {
left: Box<Expr>,
right: Box<Expr>,
},
Div {
left: Box<Expr>,
right: Box<Expr>,
},
Pow {
left: Box<Expr>,
right: Box<Expr>,
},
MatMul {
left: Box<Expr>,
right: Box<Expr>,
},
BitAnd {
left: Box<Expr>,
right: Box<Expr>,
},
BitOr {
left: Box<Expr>,
right: Box<Expr>,
},
BitXor {
left: Box<Expr>,
right: Box<Expr>,
},
BitNot {
expr: Box<Expr>,
#[serde(default)]
keyword_commitment: Commitment,
},
Shl {
left: Box<Expr>,
right: Box<Expr>,
},
Shr {
left: Box<Expr>,
right: Box<Expr>,
},
Index {
object: Box<Expr>,
field: Ident,
},
Subscript {
object: Box<Expr>,
indices: Vec<Expr>,
},
Call {
callee: Box<Expr>,
args: Vec<Expr>,
},
Placeholder {
#[serde(default)]
keyword_commitment: Commitment,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct MathBlock {
pub statements: Vec<MathStatement>,
#[serde(default)]
pub keyword_commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind")]
#[non_exhaustive]
pub enum MathStatement {
Define { target: Expr, value: Expr },
Expr { expr: Expr },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum CompareOp {
Eq,
Ne,
Lt,
Gt,
Le,
Ge,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind")]
#[non_exhaustive]
pub enum Step {
Action { step: ActionStep },
Assign { step: AssignStep },
If { step: IfStep },
For { step: ForStep },
While { step: WhileStep },
Parasteps { step: ParastepsStep },
Error { step: ErrorStep },
Desc { content: Desc }, Placeholder { keyword_commitment: Commitment }, }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ActionStep {
#[serde(default)]
pub label: Vec<Atom>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub desc: Option<Desc>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub to: Option<ToTarget>,
#[serde(default)]
pub on_blocks: Vec<OnBlock>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AssignStep {
pub target: Expr,
pub value: SimpleValue,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub desc: Option<Desc>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub to: Option<ToTarget>,
#[serde(default)]
pub on_blocks: Vec<OnBlock>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind")]
#[non_exhaustive]
pub enum SimpleValue {
Ident {
value: Ident,
},
String {
value: FString,
},
Number {
value: String,
},
Bool {
value: bool,
#[serde(default)]
keyword_commitment: Commitment,
},
List {
items: Vec<Vec<Atom>>,
},
Placeholder {
commitment: Commitment,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct IfStep {
pub cond: Condition,
pub then_branch: Vec<Step>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub else_branch: Option<Vec<Step>>,
#[serde(default)]
pub if_keyword_commitment: Commitment,
#[serde(default)]
pub else_keyword_commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ForStep {
pub var: Ident,
pub iterable: Vec<Atom>,
pub body: Vec<Step>,
#[serde(default)]
pub keyword_commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct WhileStep {
pub cond: Condition,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub desc: Option<Desc>,
pub body: Vec<Step>,
#[serde(default)]
pub keyword_commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ParastepsStep {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<FString>,
pub steps: Vec<Step>,
#[serde(default)]
pub keyword_commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ErrorStep {
pub message: FString,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub to: Option<ToTarget>,
#[serde(default)]
pub keyword_commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct OnBlock {
pub condition: Vec<Atom>,
pub steps: Vec<Step>,
#[serde(default)]
pub keyword_commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ToTarget {
pub target: Ident,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Desc {
#[serde(default)]
pub need_commitment: Commitment,
pub content: FString,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind")]
#[non_exhaustive]
pub enum Atom {
Ident { value: Ident },
String { value: FString },
Number { value: String },
Symbol { value: String },
List { items: Vec<Vec<Atom>> },
Ellipsis { commitment: Commitment },
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UiDef {
pub name: Ident,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub binds: Option<Ident>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub rules: Vec<RuleDef>,
pub root: UiNode,
#[serde(default)]
pub keyword_commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind")]
#[non_exhaustive]
pub enum UiNode {
Stack { stack: StackNode },
Parallel { parallel: StackNode },
Leaf { leaf: UiLeaf },
Error { error: UiErrorNode },
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UiErrorNode {
pub message: FString,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub desc: Option<Desc>,
#[serde(default)]
pub keyword_commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StackNode {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<FString>,
pub children: Vec<UiNode>,
#[serde(default)]
pub keyword_commitment: Commitment,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UiLeaf {
pub content: FString,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub desc: Option<Desc>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub requires: Option<Condition>,
#[serde(default)]
pub requires_keyword_commitment: Commitment,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub with: Vec<Capability>,
#[serde(default)]
pub with_keyword_commitment: Commitment,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub on: Option<OnBinding>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct OnBinding {
pub event_name: EventName,
pub action: ActionExpr,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind")]
#[non_exhaustive]
pub enum EventName {
Ident { value: Ident },
Natural { text: FString },
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ActionExpr {
pub actions: Vec<Action>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind")]
#[non_exhaustive]
pub enum Action {
Call { expr: Expr },
Navigate { target: Ident },
Assign { target: Expr, value: Expr },
Natural { text: FString },
}