2026-02-13 21:52:03 +00:00
# Expression Language
The Storybook expression language enables conditions, queries, and logic throughout the system. Expressions appear in life arc transitions, behavior tree guards, decorator conditions, and relationship queries. This chapter provides a complete reference for expression syntax and semantics.
## What are Expressions?
Expressions are logical statements that evaluate to `true` or `false` . They combine:
- **Literals**: Numbers, strings, booleans
- **Identifiers**: References to fields and entities
- **Comparisons**: `==` , `!=` , `<` , `<=` , `>` , `>=`
- **Logical operators**: `and` , `or` , `not`
- **Field access**: `self.field` , `other.field`
- **Quantifiers**: `forall` , `exists` (for collections)
## Syntax
```bnf
<expression> ::= <literal>
| <identifier>
| <field-access>
| <comparison>
| <logical>
| <unary>
| <quantifier>
| "(" <expression> ")"
2026-02-14 15:35:41 +00:00
<literal> ::= <number> | <decimal> | <text> | <boolean>
2026-02-13 21:52:03 +00:00
<identifier> ::= <simple-name>
| <qualified-path>
<field-access> ::= <expression> "." <identifier>
| "self" "." <identifier>
| "other" "." <identifier>
<comparison> ::= <expression> <comp-op> <expression>
<comp-op> ::= "==" | "!=" | "<" | "<=" | ">" | ">="
<logical> ::= <expression> "and" <expression>
| <expression> "or" <expression>
<unary> ::= "not" <expression>
| "-" <expression>
<quantifier> ::= ("forall" | "exists") <identifier> "in" <expression> ":" <expression>
```
## Literals
### Integer Literals
```storybook
42
-7
0
1000
```
### Float Literals
```storybook
3.14
-0.5
0.0
100.25
```
### String Literals
```storybook
"Martha"
"Sourdough takes patience."
"active"
```
Strings are enclosed in double quotes. Escape sequences: `\n` , `\t` , `\\` , `\"` .
### Boolean Literals
```storybook
true
false
```
## Identifiers
Identifiers reference fields or entities.
### Simple Identifiers
```storybook
health
enemy_count
is_ready
```
### Qualified Paths
```storybook
Martha.skill_level
Character.emotional_state
```
## Comparison Operators
### Equality: `==`
Tests if two values are equal.
```storybook
name == "Martha"
count == 5
status == active
```
**Type compatibility:**
- Both operands must be the same type
2026-02-14 15:35:41 +00:00
- Works with: number, decimal, text, boolean, enum values
2026-02-13 21:52:03 +00:00
### Inequality: `!=`
Tests if two values are not equal.
```storybook
name != "Gregory"
health != 0
ready != true
```
### Less Than: `<`
Tests if left operand is less than right.
```storybook
health < 20
age < 18
distance < 10.0
```
2026-02-14 15:35:41 +00:00
**Valid types:** number, decimal
2026-02-13 21:52:03 +00:00
### Less Than or Equal: `<=`
```storybook
health <= 50
count <= max_count
```
### Greater Than: `>`
```storybook
strength > 10
bond > 0.5
```
### Greater Than or Equal: `>=`
```storybook
age >= 21
score >= 100
```
## Logical Operators
### AND: `and`
Both operands must be true.
```storybook
health < 50 and has_potion
is_ready and not is_busy
age >= 18 and age < 65
```
**Evaluation:** Short-circuit (if left is false, right is not evaluated)
### OR: `or`
At least one operand must be true.
```storybook
is_day or is_lit
health < 20 or surrounded
enemy_count == 0 or all_enemies_dead
```
**Evaluation:** Short-circuit (if left is true, right is not evaluated)
### Operator Precedence
From highest to lowest:
1. **Parentheses ** : `(...)`
2. **Unary ** : `not` , `-`
3. **Comparisons ** : `==` , `!=` , `<` , `<=` , `>` , `>=`
4. **AND ** : `and`
5. **OR ** : `or`
**Examples:**
```storybook
not is_ready and is_awake
// Equivalent to: (not is_ready) and is_awake
health < 50 or is_poisoned and has_antidote
// Equivalent to: (health < 50) or (is_poisoned and has_antidote)
// Use parentheses for clarity:
(health < 50 or is_poisoned) and has_antidote
```
## Unary Operators
### NOT: `not`
Inverts a boolean value.
```storybook
not is_ready
not (health < 20)
not enemy_nearby and safe
```
### Negation: `-`
Negates a numeric value.
```storybook
-health
-10
-(max_value - current_value)
```
## Field Access
### Direct Field Access
```storybook
health
bond
emotional_state
```
References a field on the current entity.
### Dot Access
```storybook
Martha.skill_level
Character.emotional_state
enemy.health
```
Access fields on other entities.
### Self Access
In relationships and certain contexts, `self` refers to the current participant:
```storybook
self.bond
self.responsibility
self.trust
```
**Use case:** Relationship transitions, symmetric queries
### Other Access
In relationships, `other` refers to other participants:
```storybook
other.bond
other.aware_of_mentor
other.respect
```
**Use case:** Relationship queries with perspective
### Example in Life Arcs
```storybook
life_arc RelationshipState {
state new {
on self.bond > 0.7 and other.bond > 0.7 -> stable
}
state stable {
on self.bond < 0.3 -> troubled
on other.bond < 0.3 -> troubled
}
state troubled {
on self.bond < 0.1 or other.bond < 0.1 -> broken
}
state broken {}
}
```
## Quantifiers
Quantifiers test conditions over collections.
### ForAll: `forall`
Tests if a condition holds for all elements in a collection.
```storybook
forall e in enemies: e.defeated
forall item in inventory: item.weight < 10
```
**Syntax:**
```bnf
forall <variable> in <collection>: <predicate>
```
**Semantics:**
- Returns `true` if predicate is true for every element
- Returns `true` for empty collections (vacuously true)
**Examples:**
```storybook
// All enemies defeated?
forall enemy in enemies: enemy.health <= 0
// All party members ready?
forall member in party: member.is_ready
// All doors locked?
forall door in doors: door.is_locked
```
### Exists: `exists`
Tests if a condition holds for at least one element.
```storybook
exists e in enemies: e.is_hostile
exists item in inventory: item.is_healing_potion
```
**Syntax:**
```bnf
exists <variable> in <collection>: <predicate>
```
**Semantics:**
- Returns `true` if predicate is true for any element
- Returns `false` for empty collections
**Examples:**
```storybook
// Any enemy nearby?
exists enemy in enemies: enemy.distance < 10
// Any door unlocked?
exists door in doors: not door.is_locked
// Any ally wounded?
exists ally in allies: ally.health < ally.max_health * 0.5
```
### Nested Quantifiers
Quantifiers can nest:
```storybook
forall team in teams: exists player in team: player.is_leader
// Every team has at least one leader
exists room in dungeon: forall enemy in room.enemies: enemy.defeated
// At least one room has all enemies defeated
```
## Usage in Context
### Life Arc Transitions
```storybook
life_arc CombatState {
state idle {
on enemy_count > 0 -> combat
}
state combat {
on health < 20 -> fleeing
on enemy_count == 0 -> victorious
}
state fleeing {
on distance_from_enemies > 100 -> safe
}
state victorious {
on celebration_complete -> idle
}
state safe {
on health >= 50 -> idle
}
}
```
### Behavior Tree Conditions
```storybook
behavior GuardedAction {
if(health > 50 and has_weapon) {
AggressiveAttack
}
}
behavior ConditionalChoice {
choose tactics {
then melee {
if(distance < 5 and weapon_type == "sword")
MeleeAttack
}
then ranged {
if(distance >= 5 and has_arrows)
RangedAttack
}
}
}
```
### Behavior Tree Conditions
```storybook
behavior SmartAI {
choose strategy {
then aggressive {
if(health > 70 and enemy_count < 3)
Attack
}
then defensive {
if(health < 30 or enemy_count >= 5)
Defend
}
then balanced {
if(health >= 30 and health <= 70)
TacticalManeuver
}
}
}
```
## Type System
### Type Compatibility
Comparisons require compatible types:
| Operator | Left Type | Right Type | Valid? |
|----------|-----------|------------|--------|
2026-02-14 15:35:41 +00:00
| `==` , `!=` | number | number | ✓ |
| `==` , `!=` | decimal | decimal | ✓ |
| `==` , `!=` | text | text | ✓ |
| `==` , `!=` | boolean | boolean | ✓ |
2026-02-13 21:52:03 +00:00
| `==` , `!=` | enum | same enum | ✓ |
2026-02-14 15:35:41 +00:00
| `==` , `!=` | number | decimal | ✗ |
| `<` , `<=` , `>` , `>=` | number | number | ✓ |
| `<` , `<=` , `>` , `>=` | decimal | decimal | ✓ |
| `<` , `<=` , `>` , `>=` | text | text | ✗ |
2026-02-13 21:52:03 +00:00
### Implicit Coercion
**None.** Storybook has no implicit type coercion. All comparisons must be between compatible types.
**Error:**
```storybook
2026-02-14 15:35:41 +00:00
count == "5" // Error: number vs text
health < true // Error: number vs boolean
2026-02-13 21:52:03 +00:00
```
**Correct:**
```storybook
count == 5
health < 50
```
## Special Keyword: `is`
The `is` keyword provides syntactic sugar for equality with enum values:
```storybook
// Instead of:
status == active
// You can write:
status is active
```
**More examples:**
```storybook
name is "Martha"
skill_level is master
emotional_state is focused
```
This is purely syntactic—`is` and `==` are equivalent.
## Complete Examples
### Simple Conditions
```storybook
health < 20
enemy_nearby
not is_ready
count > 5
```
### Complex Conditions
```storybook
(health < 20 and not has_potion) or surrounded
forall e in enemies: e.defeated
exists item in inventory: item.is_healing_potion and item.quantity > 0
```
### Life Arc with Complex Conditions
```storybook
life_arc CharacterMood {
state content {
on health < 30 or hunger > 80 -> distressed
on social_interaction > 0.8 -> happy
}
state distressed {
on health >= 50 and hunger < 30 -> content
on (health < 10 or hunger > 95) and help_available -> desperate
}
state happy {
on social_interaction < 0.3 -> content
on received_bad_news -> distressed
}
state desperate {
on help_received -> distressed
}
}
```
### Behavior with Quantifiers
```storybook
behavior SquadLeader {
choose leadership {
then regroup {
if(squad_has_wounded)
OrderRetreat
}
then advance {
if(squad_all_ready)
OrderAdvance
}
then hold_position {
if(not squad_all_ready)
OrderHold
}
}
}
```
### Relationship Query
```storybook
life_arc FriendshipQuality {
state new_friends {
on self.bond > 0.7 and other.bond > 0.7 -> strong_bond
on self.trust < 0.3 or other.trust < 0.3 -> shaky
}
state strong_bond {
on self.bond < 0.5 -> weakening
}
state weakening {
on self.bond < 0.2 or other.bond < 0.2 -> ended
on self.bond > 0.7 and other.bond > 0.7 -> strong_bond
}
state shaky {
on self.trust > 0.6 and other.trust > 0.6 -> new_friends
on self.trust < 0.1 or other.trust < 0.1 -> ended
}
state ended {}
}
```
## Validation Rules
1. **Type consistency ** : Both sides of comparison must be compatible types
2. **Boolean context ** : Logical operators (`and` , `or` , `not` ) require boolean operands
3. **Field existence ** : Referenced fields must exist on the entity
4. **Collection validity ** : Quantifiers require collection-typed expressions
5. **Variable scope ** : Quantifier variables only valid within their predicate
6. **No division by zero ** : Arithmetic operations must not divide by zero
7. **Enum validity ** : Enum comparisons must reference defined enum values
## Best Practices
### 1. Use Parentheses for Clarity
**Avoid:**
```storybook
health < 50 or is_poisoned and has_antidote
```
**Prefer:**
```storybook
(health < 50 or is_poisoned) and has_antidote
```
### 2. Break Complex Conditions
**Avoid:**
```storybook
on (health < 20 and not has_potion) or (surrounded and not has_escape) or (enemy_count > 10 and weapon_broken) -> desperate
```
**Prefer:**
```storybook
state combat {
on health < 20 and not has_potion -> desperate
on surrounded and not has_escape -> desperate
on enemy_count > 10 and weapon_broken -> desperate
}
```
### 3. Name Complex Conditions
For repeated complex conditions, consider using intermediate fields:
**Instead of:**
```storybook
on health < (max_health * 0.2) and enemy_count > 5 -> flee
```
**Consider:**
```storybook
// In character definition:
critically_wounded: health < (max_health * 0.2)
outnumbered: enemy_count > 5
// In life arc:
on critically_wounded and outnumbered -> flee
```
### 4. Use `is` for Enums
**Prefer:**
```storybook
status is active
emotional_state is focused
```
**Over:**
```storybook
status == active
emotional_state == focused
```
### 5. Quantifiers for Collections
**Avoid:**
```storybook
// Manual checks for each element
if enemy1.defeated and enemy2.defeated and enemy3.defeated
```
**Prefer:**
```storybook
if forall enemy in enemies: enemy.defeated
```
## Cross-References
- [Life Arcs ](./13-life-arcs.md ) - Transition conditions
- [Behavior Trees ](./11-behavior-trees.md ) - Guard and condition nodes
- [Decorators ](./12-decorators.md ) - Guard decorator
- [Relationships ](./15-relationships.md ) - Self/other field access
- [Value Types ](./18-value-types.md ) - Literal value types
## Related Concepts
- **Type safety**: Strong typing prevents type errors at compile time
- **Short-circuit evaluation**: AND/OR operators optimize evaluation
- **Quantifiers**: Enable expressive collection queries
- **Field access**: Context-sensitive (`self` , `other` ) for relationships
- **Boolean algebra**: Standard logical operators with expected semantics