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:
282
src/syntax/ast.rs
Normal file
282
src/syntax/ast.rs
Normal file
@@ -0,0 +1,282 @@
|
||||
/// 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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
}
|
||||
Reference in New Issue
Block a user