Added optional species_base field to Template struct enabling
template-species inheritance syntax: `template Name: Species { ... }`.
Updated LALRPOP grammar and all Template construction sites.
547 lines
14 KiB
Rust
547 lines
14 KiB
Rust
/// 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<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),
|
|
Concept(ConceptDecl),
|
|
SubConcept(SubConceptDecl),
|
|
ConceptComparison(ConceptComparisonDecl),
|
|
}
|
|
|
|
/// 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::*
|
|
}
|
|
|
|
/// Link to a behavior tree with optional conditions and priority
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct BehaviorLink {
|
|
pub tree: Vec<String>, // Qualified path to behavior tree
|
|
pub condition: Option<Expr>, // 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<Self, Self::Err> {
|
|
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<String>, // `: Species` - what the character fundamentally is
|
|
pub fields: Vec<Field>,
|
|
pub template: Option<Vec<String>>, // `from Template1, Template2`
|
|
pub uses_behaviors: Option<Vec<BehaviorLink>>, // `uses behaviors: [...]`
|
|
pub uses_schedule: Option<Vec<String>>, /* `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<String>, // `: Species` - type constraint from species
|
|
pub fields: Vec<Field>,
|
|
pub strict: bool,
|
|
pub includes: Vec<String>,
|
|
pub uses_behaviors: Option<Vec<BehaviorLink>>, // `uses behaviors: [...]`
|
|
pub uses_schedule: Option<Vec<String>>, /* `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<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),
|
|
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<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,
|
|
pub on_enter: Option<Vec<Field>>,
|
|
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 with composition support
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct Schedule {
|
|
pub name: String,
|
|
pub extends: Option<String>, // Base schedule to extend
|
|
pub blocks: Vec<ScheduleBlock>,
|
|
pub recurrences: Vec<RecurrencePattern>, // Recurring events
|
|
pub fields: Vec<Field>, // Documentation prose blocks, metadata
|
|
pub span: Span,
|
|
}
|
|
|
|
/// A time block in a schedule
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct ScheduleBlock {
|
|
pub name: Option<String>, // 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<Vec<String>>, // Behavior reference (new way)
|
|
pub temporal_constraint: Option<TemporalConstraint>, // When this block applies
|
|
pub fields: Vec<Field>,
|
|
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<ScheduleBlock>, // 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<String>,
|
|
children: Vec<BehaviorNode>,
|
|
},
|
|
Sequence {
|
|
label: Option<String>,
|
|
children: Vec<BehaviorNode>,
|
|
},
|
|
Condition(Expr),
|
|
Action(String, Vec<Field>), // Action name + parameters
|
|
Decorator {
|
|
decorator_type: DecoratorType,
|
|
child: Box<BehaviorNode>,
|
|
},
|
|
SubTree(Vec<String>), // 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<Field>,
|
|
pub uses_behaviors: Option<Vec<BehaviorLink>>, // `uses behaviors: [...]`
|
|
pub uses_schedule: Option<Vec<String>>, /* `uses schedule: ScheduleName` or `uses
|
|
* schedules: [...]` */
|
|
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 name: Vec<String>, // Qualified path
|
|
pub role: Option<String>, // "as parent" (optional)
|
|
pub fields: Vec<Field>, // Participant-specific fields (required block)
|
|
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,
|
|
pub includes: Vec<String>,
|
|
pub fields: Vec<Field>,
|
|
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<String> },
|
|
Record { fields: Vec<Field> },
|
|
}
|
|
|
|
/// Concept comparison - compile-time pattern matching for concept variants
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct ConceptComparisonDecl {
|
|
pub name: String,
|
|
pub variants: Vec<VariantPattern>,
|
|
pub span: Span,
|
|
}
|
|
|
|
/// A variant pattern with field conditions
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct VariantPattern {
|
|
pub name: String,
|
|
pub conditions: Vec<FieldCondition>,
|
|
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<String>), // 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<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,
|
|
}
|
|
|
|
// ===== 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<BehaviorLink>),
|
|
UsesSchedule(Vec<String>),
|
|
}
|
|
|
|
/// Helper for parsing institution bodies with flexible ordering
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum InstitutionBodyItem {
|
|
Field(Field),
|
|
UsesBehaviors(Vec<BehaviorLink>),
|
|
UsesSchedule(Vec<String>),
|
|
}
|
|
|
|
/// Helper for parsing template body items with flexible ordering
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum TemplateBodyItem {
|
|
Field(Field),
|
|
Include(String),
|
|
UsesBehaviors(Vec<BehaviorLink>),
|
|
UsesSchedule(Vec<String>),
|
|
}
|
|
|
|
/// Helper for parsing behavior link fields
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum BehaviorLinkField {
|
|
Tree(Vec<String>),
|
|
Condition(Expr),
|
|
Priority(Priority),
|
|
}
|