feat: implement storybook DSL with template composition and validation
Add complete domain-specific language for authoring narrative content for agent simulations. Features: - Complete parser using LALRPOP + logos lexer - Template composition (includes + multiple inheritance) - Strict mode validation for templates - Reserved keyword protection - Semantic validators (trait ranges, schedule overlaps, life arcs, behaviors) - Name resolution and cross-reference tracking - CLI tool (validate, inspect, query commands) - Query API with filtering - 260 comprehensive tests (unit, integration, property-based) Implementation phases: - Phase 1 (Parser): Complete - Phase 2 (Resolution + Validation): Complete - Phase 3 (Public API + CLI): Complete BREAKING CHANGE: Initial implementation
This commit is contained in:
228
src/types.rs
Normal file
228
src/types.rs
Normal file
@@ -0,0 +1,228 @@
|
||||
//! 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 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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user