/// Source location for error reporting with line/column information #[derive(Debug, Clone, PartialEq)] pub struct Span { pub start: usize, pub end: usize, pub start_line: usize, // 0-indexed line number pub start_col: usize, // 0-indexed column number pub end_line: usize, pub end_col: usize, } impl Span { pub fn new(start: usize, end: usize) -> Self { Self { start, end, start_line: 0, start_col: 0, end_line: 0, end_col: 0, } } pub fn with_position( start: usize, end: usize, start_line: usize, start_col: usize, end_line: usize, end_col: usize, ) -> Self { Self { start, end, start_line, start_col, end_line, end_col, } } /// Convert to LSP Position for the start pub fn start_position(&self) -> (u32, u32) { (self.start_line as u32, self.start_col as u32) } /// Convert to LSP Position for the end pub fn end_position(&self) -> (u32, u32) { (self.end_line as u32, self.end_col as u32) } } /// Top-level file containing multiple declarations #[derive(Debug, Clone, PartialEq)] pub struct File { pub declarations: Vec, } /// 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), Concept(ConceptDecl), SubConcept(SubConceptDecl), ConceptComparison(ConceptComparisonDecl), } /// Use statement for importing definitions #[derive(Debug, Clone, PartialEq)] pub struct UseDecl { pub path: Vec, pub kind: UseKind, pub span: Span, } #[derive(Debug, Clone, PartialEq)] pub enum UseKind { Single, // use foo::bar Grouped(Vec), // use foo::{bar, baz} Wildcard, // use foo::* } /// Link to a behavior tree with optional conditions and priority #[derive(Debug, Clone, PartialEq)] pub struct BehaviorLink { pub tree: Vec, // Qualified path to behavior tree pub condition: Option, // Optional when clause pub priority: Priority, // Execution priority pub span: Span, } /// Priority levels for behavior selection #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum Priority { Low, Normal, High, Critical, } impl std::str::FromStr for Priority { type Err = (); fn from_str(s: &str) -> Result { match s { | "low" => Ok(Priority::Low), | "normal" => Ok(Priority::Normal), | "high" => Ok(Priority::High), | "critical" => Ok(Priority::Critical), | _ => Err(()), } } } /// Character definition #[derive(Debug, Clone, PartialEq)] pub struct Character { pub name: String, pub species: Option, // `: Species` - what the character fundamentally is pub fields: Vec, pub template: Option>, // `from Template1, Template2` pub uses_behaviors: Option>, // `uses behaviors: [...]` pub uses_schedule: Option>, /* `uses schedule: ScheduleName` or `uses schedules: * [...]` */ pub span: Span, } /// Template definition (like Character but allows range values) #[derive(Debug, Clone, PartialEq)] pub struct Template { pub name: String, pub species_base: Option, // `: Species` - type constraint from species pub fields: Vec, pub strict: bool, pub includes: Vec, pub uses_behaviors: Option>, // `uses behaviors: [...]` pub uses_schedule: Option>, /* `uses schedule: ScheduleName` or `uses * schedules: [...]` */ 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 { Number(i64), Decimal(f64), Text(String), Boolean(bool), Range(Box, Box), // For templates: 20..40 Time(Time), Duration(Duration), Identifier(Vec), // Qualified path reference List(Vec), Object(Vec), ProseBlock(ProseBlock), Override(Override), Any, // Special marker for type system - matches any value } /// 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, // Template path pub overrides: Vec, 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, pub span: Span, } #[derive(Debug, Clone, PartialEq)] pub struct ArcState { pub name: String, pub on_enter: Option>, pub transitions: Vec, pub span: Span, } #[derive(Debug, Clone, PartialEq)] pub struct Transition { pub to: String, pub condition: Expr, pub span: Span, } /// Schedule definition with composition support #[derive(Debug, Clone, PartialEq)] pub struct Schedule { pub name: String, pub extends: Option, // Base schedule to extend pub blocks: Vec, pub recurrences: Vec, // Recurring events pub fields: Vec, // Documentation prose blocks, metadata pub span: Span, } /// A time block in a schedule #[derive(Debug, Clone, PartialEq)] pub struct ScheduleBlock { pub name: Option, // Block name for override system pub is_override: bool, // Whether this block overrides a base block pub start: Time, pub end: Time, pub activity: String, // DEPRECATED: kept for backward compatibility pub action: Option>, // Behavior reference (new way) pub temporal_constraint: Option, // When this block applies pub fields: Vec, pub span: Span, } /// Temporal constraint for when a schedule block applies #[derive(Debug, Clone, PartialEq)] pub enum TemporalConstraint { Season(String), // Applies during specific season (enum value) DayOfWeek(String), // Applies on specific day of week (enum value) Month(String), // Applies during specific month (enum value) DateRange(String, String), // Applies between two dates (TODO: date type) } /// Recurring event pattern #[derive(Debug, Clone, PartialEq)] pub struct RecurrencePattern { pub name: String, // Event name (e.g., "MarketDay") pub constraint: TemporalConstraint, // When it recurs (e.g., "on Earthday") pub blocks: Vec, // What happens during the event pub span: Span, } // ===== Parser Helper Types for Schedules ===== /// Helper for parsing schedule bodies with flexible ordering #[derive(Debug, Clone, PartialEq)] pub enum ScheduleBodyItem { Field(Field), Block(ScheduleBlock), Recurrence(RecurrencePattern), } /// Helper for parsing schedule block content #[derive(Debug, Clone, PartialEq)] pub enum BlockContentItem { TimeRange(Time, Time), Field(Field), } /// 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 { label: Option, children: Vec, }, Sequence { label: Option, children: Vec, }, Condition(Expr), Action(String, Vec), // Action name + parameters Decorator { decorator_type: DecoratorType, child: Box, }, SubTree(Vec), // Reference to another behavior } #[derive(Debug, Clone, PartialEq)] pub enum DecoratorType { Repeat, // infinite loop RepeatN(u32), // N times RepeatRange(u32, u32), // min..max times Invert, Retry(u32), // max attempts Timeout(String), // duration string (e.g., "5s", "30m", "2h") Cooldown(String), // duration string (e.g., "5s", "30m", "2h") If(Expr), SucceedAlways, FailAlways, } // BehaviorDuration is used for decorator timeouts/cooldowns (single unit) // whereas Duration (above) is for general time literals (compound: 2h30m) #[derive(Debug, Clone, PartialEq)] pub struct BehaviorDuration { pub value: u32, pub unit: DurationUnit, } #[derive(Debug, Clone, PartialEq)] pub enum DurationUnit { Days, Hours, Minutes, Seconds, } impl BehaviorDuration { pub fn to_milliseconds(&self) -> u64 { let base_ms = self.value as u64; match self.unit { | DurationUnit::Days => base_ms * 24 * 60 * 60 * 1000, | DurationUnit::Hours => base_ms * 60 * 60 * 1000, | DurationUnit::Minutes => base_ms * 60 * 1000, | DurationUnit::Seconds => base_ms * 1000, } } } /// Institution definition #[derive(Debug, Clone, PartialEq)] pub struct Institution { pub name: String, pub fields: Vec, pub uses_behaviors: Option>, // `uses behaviors: [...]` pub uses_schedule: Option>, /* `uses schedule: ScheduleName` or `uses * schedules: [...]` */ pub span: Span, } /// Relationship definition #[derive(Debug, Clone, PartialEq)] pub struct Relationship { pub name: String, pub participants: Vec, pub fields: Vec, pub span: Span, } #[derive(Debug, Clone, PartialEq)] pub struct Participant { pub name: Vec, // Qualified path pub role: Option, // "as parent" (optional) pub fields: Vec, // Participant-specific fields (required block) pub span: Span, } /// Location definition #[derive(Debug, Clone, PartialEq)] pub struct Location { pub name: String, pub fields: Vec, pub span: Span, } /// Species definition #[derive(Debug, Clone, PartialEq)] pub struct Species { pub name: String, pub includes: Vec, pub fields: Vec, pub span: Span, } /// Concept declaration - base type definition #[derive(Debug, Clone, PartialEq)] pub struct ConceptDecl { pub name: String, pub span: Span, } /// Sub-concept declaration - enum or record subtype #[derive(Debug, Clone, PartialEq)] pub struct SubConceptDecl { pub name: String, pub parent_concept: String, pub kind: SubConceptKind, pub span: Span, } /// Sub-concept can be either enum-like or record-like #[derive(Debug, Clone, PartialEq)] pub enum SubConceptKind { Enum { variants: Vec }, Record { fields: Vec }, } /// Concept comparison - compile-time pattern matching for concept variants #[derive(Debug, Clone, PartialEq)] pub struct ConceptComparisonDecl { pub name: String, pub variants: Vec, pub span: Span, } /// A variant pattern with field conditions #[derive(Debug, Clone, PartialEq)] pub struct VariantPattern { pub name: String, pub conditions: Vec, pub span: Span, } /// A condition on a field within a variant pattern #[derive(Debug, Clone, PartialEq)] pub struct FieldCondition { pub field_name: String, pub condition: Condition, pub span: Span, } /// The type of condition for field matching #[derive(Debug, Clone, PartialEq)] pub enum Condition { Any, // matches any value Is(Vec), // matches specific values (e.g., "is Glass or is Plastic") } /// Expression AST for conditions and queries #[derive(Debug, Clone, PartialEq)] pub enum Expr { NumberLit(i64), DecimalLit(f64), TextLit(String), BooleanLit(bool), Identifier(Vec), FieldAccess(Box, String), Comparison(Box, CompOp, Box), Logical(Box, LogicalOp, Box), Unary(UnaryOp, Box), Quantifier(QuantifierKind, String, Box, Box), /* 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, } // ===== Parser Helper Types ===== // These enums are used internally by the LALRPOP parser to handle flexible // ordering /// Helper for parsing character/institution bodies with flexible ordering #[derive(Debug, Clone, PartialEq)] pub enum CharacterBodyItem { Field(Field), UsesBehaviors(Vec), UsesSchedule(Vec), } /// Helper for parsing institution bodies with flexible ordering #[derive(Debug, Clone, PartialEq)] pub enum InstitutionBodyItem { Field(Field), UsesBehaviors(Vec), UsesSchedule(Vec), } /// Helper for parsing template body items with flexible ordering #[derive(Debug, Clone, PartialEq)] pub enum TemplateBodyItem { Field(Field), Include(String), UsesBehaviors(Vec), UsesSchedule(Vec), } /// Helper for parsing behavior link fields #[derive(Debug, Clone, PartialEq)] pub enum BehaviorLinkField { Tree(Vec), Condition(Expr), Priority(Priority), }