Files
storybook/src/types.rs
Sienna Meridian Satterwhite a8882eb3ec feat(parser): add action parameters, repeater decorator, and named participants
Add syntax enhancements for more expressive behavior trees and relationships.

Action parameters:
- Support typed/positional parameters: WaitDuration(2.0)
- Support named parameters: SetValue(field: value)
- Enable inline values without field names

Repeater decorator:
- Add * { node } syntax for repeating behavior nodes
- Maps to Decorator("repeat", node)

Named participant blocks:
- Replace self/other blocks with named participant syntax
- Support multi-party relationships
- Example: Alice { role: seeker } instead of self { role: seeker }

Schedule block syntax:
- Require braces for schedule blocks to support narrative fields
- Update tests to use new syntax: 04:00 -> 06:00: Activity { }
2026-02-08 15:45:56 +00:00

230 lines
6.4 KiB
Rust

//! Public types for resolved Storybook entities
//!
//! These types represent fully resolved, validated entities after the
//! resolution pipeline completes. Unlike the AST types which represent
//! raw parsed syntax, these types:
//! - Have all cross-references resolved
//! - Have all overrides applied
//! - Have passed semantic validation
//! - Are ready for consumption by the game engine
use std::collections::HashMap;
use crate::syntax::ast::{
BehaviorNode,
Participant,
ProseBlock,
Span,
Time,
Transition,
Value,
};
/// A fully resolved Storybook project
#[derive(Debug, Clone)]
pub struct ResolvedFile {
pub declarations: Vec<ResolvedDeclaration>,
}
/// A resolved top-level declaration
#[derive(Debug, Clone)]
pub enum ResolvedDeclaration {
Character(ResolvedCharacter),
Template(ResolvedTemplate),
LifeArc(ResolvedLifeArc),
Schedule(ResolvedSchedule),
Behavior(ResolvedBehavior),
Institution(ResolvedInstitution),
Relationship(ResolvedRelationship),
Location(ResolvedLocation),
Species(ResolvedSpecies),
Enum(ResolvedEnum),
}
/// A character with all templates applied and references resolved
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedCharacter {
pub name: String,
pub species: Option<String>,
pub fields: HashMap<String, Value>,
pub prose_blocks: HashMap<String, ProseBlock>,
pub span: Span,
}
/// A template definition (before instantiation)
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedTemplate {
pub name: String,
pub fields: HashMap<String, Value>,
pub span: Span,
}
/// A life arc with validated state transitions
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedLifeArc {
pub name: String,
pub states: Vec<ResolvedArcState>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedArcState {
pub name: String,
pub transitions: Vec<Transition>,
pub span: Span,
}
/// A schedule with validated non-overlapping blocks
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedSchedule {
pub name: String,
pub blocks: Vec<ResolvedScheduleBlock>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedScheduleBlock {
pub activity: String,
pub start: Time,
pub end: Time,
pub span: Span,
}
/// A behavior tree with validated actions
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedBehavior {
pub name: String,
pub root: BehaviorNode,
pub span: Span,
}
/// An institution with resolved member references
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedInstitution {
pub name: String,
pub fields: HashMap<String, Value>,
pub span: Span,
}
/// A bidirectional relationship with merged self/other blocks
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedRelationship {
pub name: String,
pub participants: Vec<Participant>,
pub fields: HashMap<String, Value>,
pub span: Span,
}
/// A location definition
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedLocation {
pub name: String,
pub fields: HashMap<String, Value>,
pub span: Span,
}
/// A species definition
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedSpecies {
pub name: String,
pub fields: HashMap<String, Value>,
pub span: Span,
}
/// An enum definition with variants
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedEnum {
pub name: String,
pub variants: Vec<String>,
pub span: Span,
}
impl ResolvedFile {
/// Get all characters in the file
pub fn characters(&self) -> impl Iterator<Item = &ResolvedCharacter> {
self.declarations.iter().filter_map(|decl| match decl {
| ResolvedDeclaration::Character(c) => Some(c),
| _ => None,
})
}
/// Get all relationships in the file
pub fn relationships(&self) -> impl Iterator<Item = &ResolvedRelationship> {
self.declarations.iter().filter_map(|decl| match decl {
| ResolvedDeclaration::Relationship(r) => Some(r),
| _ => None,
})
}
/// Get all institutions in the file
pub fn institutions(&self) -> impl Iterator<Item = &ResolvedInstitution> {
self.declarations.iter().filter_map(|decl| match decl {
| ResolvedDeclaration::Institution(i) => Some(i),
| _ => None,
})
}
/// Get all schedules in the file
pub fn schedules(&self) -> impl Iterator<Item = &ResolvedSchedule> {
self.declarations.iter().filter_map(|decl| match decl {
| ResolvedDeclaration::Schedule(s) => Some(s),
| _ => None,
})
}
/// Get all behavior trees in the file
pub fn behaviors(&self) -> impl Iterator<Item = &ResolvedBehavior> {
self.declarations.iter().filter_map(|decl| match decl {
| ResolvedDeclaration::Behavior(b) => Some(b),
| _ => None,
})
}
/// Get all life arcs in the file
pub fn life_arcs(&self) -> impl Iterator<Item = &ResolvedLifeArc> {
self.declarations.iter().filter_map(|decl| match decl {
| ResolvedDeclaration::LifeArc(la) => Some(la),
| _ => None,
})
}
/// Get all locations in the file
pub fn locations(&self) -> impl Iterator<Item = &ResolvedLocation> {
self.declarations.iter().filter_map(|decl| match decl {
| ResolvedDeclaration::Location(l) => Some(l),
| _ => None,
})
}
/// Get all species in the file
pub fn species(&self) -> impl Iterator<Item = &ResolvedSpecies> {
self.declarations.iter().filter_map(|decl| match decl {
| ResolvedDeclaration::Species(s) => Some(s),
| _ => None,
})
}
/// Get all enums in the file
pub fn enums(&self) -> impl Iterator<Item = &ResolvedEnum> {
self.declarations.iter().filter_map(|decl| match decl {
| ResolvedDeclaration::Enum(e) => Some(e),
| _ => None,
})
}
/// Find a character by name
pub fn find_character(&self, name: &str) -> Option<&ResolvedCharacter> {
self.characters().find(|c| c.name == name)
}
/// Find a relationship by name
pub fn find_relationship(&self, name: &str) -> Option<&ResolvedRelationship> {
self.relationships().find(|r| r.name == name)
}
/// Find an institution by name
pub fn find_institution(&self, name: &str) -> Option<&ResolvedInstitution> {
self.institutions().find(|i| i.name == name)
}
}