2026-02-08 13:24:35 +00:00
|
|
|
/// Source location for error reporting
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct Span {
|
|
|
|
|
pub start: usize,
|
|
|
|
|
pub end: usize,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Span {
|
|
|
|
|
pub fn new(start: usize, end: usize) -> Self {
|
|
|
|
|
Self { start, end }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Top-level file containing multiple declarations
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct File {
|
|
|
|
|
pub declarations: Vec<Declaration>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Any top-level declaration
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub enum Declaration {
|
|
|
|
|
Use(UseDecl),
|
|
|
|
|
Character(Character),
|
|
|
|
|
Template(Template),
|
|
|
|
|
LifeArc(LifeArc),
|
|
|
|
|
Schedule(Schedule),
|
|
|
|
|
Behavior(Behavior),
|
|
|
|
|
Institution(Institution),
|
|
|
|
|
Relationship(Relationship),
|
|
|
|
|
Location(Location),
|
|
|
|
|
Species(Species),
|
|
|
|
|
Enum(EnumDecl),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Use statement for importing definitions
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct UseDecl {
|
|
|
|
|
pub path: Vec<String>,
|
|
|
|
|
pub kind: UseKind,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub enum UseKind {
|
|
|
|
|
Single, // use foo::bar
|
|
|
|
|
Grouped(Vec<String>), // use foo::{bar, baz}
|
|
|
|
|
Wildcard, // use foo::*
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Character definition
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct Character {
|
|
|
|
|
pub name: String,
|
2026-02-08 15:45:56 +00:00
|
|
|
pub species: Option<String>, // `: Species` - what the character fundamentally is
|
2026-02-08 13:24:35 +00:00
|
|
|
pub fields: Vec<Field>,
|
|
|
|
|
pub template: Option<Vec<String>>, // `from Template1, Template2`
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Template definition (like Character but allows range values)
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct Template {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub fields: Vec<Field>,
|
|
|
|
|
pub strict: bool,
|
|
|
|
|
pub includes: Vec<String>,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Field in a structured definition
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct Field {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub value: Value,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Field value types
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub enum Value {
|
|
|
|
|
Int(i64),
|
|
|
|
|
Float(f64),
|
|
|
|
|
String(String),
|
|
|
|
|
Bool(bool),
|
|
|
|
|
Range(Box<Value>, Box<Value>), // For templates: 20..40
|
|
|
|
|
Time(Time),
|
|
|
|
|
Duration(Duration),
|
|
|
|
|
Identifier(Vec<String>), // Qualified path reference
|
|
|
|
|
List(Vec<Value>),
|
|
|
|
|
Object(Vec<Field>),
|
|
|
|
|
ProseBlock(ProseBlock),
|
|
|
|
|
Override(Override),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Time literal (HH:MM or HH:MM:SS)
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct Time {
|
|
|
|
|
pub hour: u8,
|
|
|
|
|
pub minute: u8,
|
|
|
|
|
pub second: u8,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Duration literal (e.g., 2h30m)
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct Duration {
|
|
|
|
|
pub hours: u32,
|
|
|
|
|
pub minutes: u32,
|
|
|
|
|
pub seconds: u32,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Prose block with tag
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct ProseBlock {
|
|
|
|
|
pub tag: String,
|
|
|
|
|
pub content: String,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Override specification for template instantiation
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct Override {
|
|
|
|
|
pub base: Vec<String>, // Template path
|
|
|
|
|
pub overrides: Vec<OverrideOp>,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub enum OverrideOp {
|
|
|
|
|
Set(Field), // field: value
|
|
|
|
|
Remove(String), // remove field
|
|
|
|
|
Append(Field), // append field
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Life arc state machine
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct LifeArc {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub states: Vec<ArcState>,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct ArcState {
|
|
|
|
|
pub name: String,
|
2026-02-08 15:45:56 +00:00
|
|
|
pub on_enter: Option<Vec<Field>>,
|
2026-02-08 13:24:35 +00:00
|
|
|
pub transitions: Vec<Transition>,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct Transition {
|
|
|
|
|
pub to: String,
|
|
|
|
|
pub condition: Expr,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Schedule definition
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct Schedule {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub blocks: Vec<ScheduleBlock>,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct ScheduleBlock {
|
|
|
|
|
pub start: Time,
|
|
|
|
|
pub end: Time,
|
|
|
|
|
pub activity: String,
|
2026-02-08 15:45:56 +00:00
|
|
|
pub fields: Vec<Field>,
|
2026-02-08 13:24:35 +00:00
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Behavior tree definition
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct Behavior {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub root: BehaviorNode,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub enum BehaviorNode {
|
|
|
|
|
Selector(Vec<BehaviorNode>), // ? operator
|
|
|
|
|
Sequence(Vec<BehaviorNode>), // > operator (context-dependent)
|
|
|
|
|
Condition(Expr),
|
|
|
|
|
Action(String, Vec<Field>), // Action name + parameters
|
|
|
|
|
Decorator(String, Box<BehaviorNode>),
|
|
|
|
|
SubTree(Vec<String>), // Reference to another behavior
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Institution definition
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct Institution {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub fields: Vec<Field>,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Relationship definition
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct Relationship {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub participants: Vec<Participant>,
|
|
|
|
|
pub fields: Vec<Field>,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct Participant {
|
|
|
|
|
pub role: Option<String>, // "as parent"
|
|
|
|
|
pub name: Vec<String>, // Qualified path
|
|
|
|
|
pub self_block: Option<Vec<Field>>,
|
|
|
|
|
pub other_block: Option<Vec<Field>>,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Location definition
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct Location {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub fields: Vec<Field>,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Species definition
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct Species {
|
|
|
|
|
pub name: String,
|
2026-02-08 15:45:56 +00:00
|
|
|
pub includes: Vec<String>,
|
2026-02-08 13:24:35 +00:00
|
|
|
pub fields: Vec<Field>,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Enum definition
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub struct EnumDecl {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub variants: Vec<String>,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Expression AST for conditions and queries
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub enum Expr {
|
|
|
|
|
IntLit(i64),
|
|
|
|
|
FloatLit(f64),
|
|
|
|
|
StringLit(String),
|
|
|
|
|
BoolLit(bool),
|
|
|
|
|
Identifier(Vec<String>),
|
|
|
|
|
FieldAccess(Box<Expr>, String),
|
|
|
|
|
Comparison(Box<Expr>, CompOp, Box<Expr>),
|
|
|
|
|
Logical(Box<Expr>, LogicalOp, Box<Expr>),
|
|
|
|
|
Unary(UnaryOp, Box<Expr>),
|
|
|
|
|
Quantifier(QuantifierKind, String, Box<Expr>, Box<Expr>), /* forall/exists x in collection:
|
|
|
|
|
* predicate */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
|
|
|
pub enum CompOp {
|
|
|
|
|
Eq, // ==
|
|
|
|
|
Ne, // !=
|
|
|
|
|
Lt, // <
|
|
|
|
|
Le, // <=
|
|
|
|
|
Gt, // >
|
|
|
|
|
Ge, // >=
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
|
|
|
pub enum LogicalOp {
|
|
|
|
|
And,
|
|
|
|
|
Or,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
|
|
|
pub enum UnaryOp {
|
|
|
|
|
Not,
|
|
|
|
|
Neg,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
|
|
|
pub enum QuantifierKind {
|
|
|
|
|
ForAll,
|
|
|
|
|
Exists,
|
|
|
|
|
}
|