release: Storybook v0.2.0 - Major syntax and features update

BREAKING CHANGES:
- Relationship syntax now requires blocks for all participants
- Removed self/other perspective blocks from relationships
- Replaced 'guard' keyword with 'if' for behavior tree decorators

Language Features:
- Add tree-sitter grammar with improved if/condition disambiguation
- Add comprehensive tutorial and reference documentation
- Add SBIR v0.2.0 binary format specification
- Add resource linking system for behaviors and schedules
- Add year-long schedule patterns (day, season, recurrence)
- Add behavior tree enhancements (named nodes, decorators)

Documentation:
- Complete tutorial series (9 chapters) with baker family examples
- Complete reference documentation for all language features
- SBIR v0.2.0 specification with binary format details
- Added locations and institutions documentation

Examples:
- Convert all examples to baker family scenario
- Add comprehensive working examples

Tooling:
- Zed extension with LSP integration
- Tree-sitter grammar for syntax highlighting
- Build scripts and development tools

Version Updates:
- Main package: 0.1.0 → 0.2.0
- Tree-sitter grammar: 0.1.0 → 0.2.0
- Zed extension: 0.1.0 → 0.2.0
- Storybook editor: 0.1.0 → 0.2.0
This commit is contained in:
2026-02-13 21:52:03 +00:00
parent 80332971b8
commit 16deb5d237
290 changed files with 90316 additions and 5827 deletions

View File

@@ -1,13 +1,52 @@
/// Source location for error reporting
/// 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 }
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)
}
}
@@ -48,6 +87,36 @@ pub enum UseKind {
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 Priority {
pub fn from_str(s: &str) -> Option<Self> {
match s {
| "low" => Some(Priority::Low),
| "normal" => Some(Priority::Normal),
| "high" => Some(Priority::High),
| "critical" => Some(Priority::Critical),
| _ => None,
}
}
}
/// Character definition
#[derive(Debug, Clone, PartialEq)]
pub struct Character {
@@ -55,6 +124,9 @@ pub struct Character {
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,
}
@@ -65,6 +137,9 @@ pub struct Template {
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,
}
@@ -155,23 +230,66 @@ pub struct Transition {
pub span: Span,
}
/// Schedule definition
/// 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,
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 {
@@ -182,19 +300,73 @@ pub struct Behavior {
#[derive(Debug, Clone, PartialEq)]
pub enum BehaviorNode {
Selector(Vec<BehaviorNode>), // ? operator
Sequence(Vec<BehaviorNode>), // > operator (context-dependent)
Selector {
label: Option<String>,
children: Vec<BehaviorNode>,
},
Sequence {
label: Option<String>,
children: Vec<BehaviorNode>,
},
Condition(Expr),
Action(String, Vec<Field>), // Action name + parameters
Decorator(String, Box<BehaviorNode>),
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,
}
@@ -209,10 +381,9 @@ pub struct Relationship {
#[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 role: Option<String>, // "as parent" (optional)
pub fields: Vec<Field>, // Participant-specific fields (required block)
pub span: Span,
}
@@ -284,3 +455,40 @@ 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),
}