sigil_parser/plurality/ast.rs
1//! # AST Extensions for Plurality
2//!
3//! New AST nodes for alter definitions, switch expressions, headspace
4//! navigation, and other plurality-specific constructs.
5
6use crate::ast::{
7 Attribute, Block, Expr, Generics, Ident, Param, TypeExpr, Visibility, WhereClause,
8};
9use crate::span::Span;
10
11// ============================================================================
12// ALTER SOURCE MARKERS
13// ============================================================================
14
15/// Alter-source markers extend evidentiality to track which alter
16/// perceives or controls data.
17///
18/// These combine with standard evidentiality (!~?‽) to create
19/// compound types like `Perception@Abaddon!` (certain, from Abaddon's view).
20#[derive(Debug, Clone, PartialEq)]
21pub enum AlterSource {
22 /// Data from the currently fronting alter (authoritative)
23 Fronting,
24 /// Data from a co-conscious alter (reported, may differ)
25 CoConscious(Option<Ident>),
26 /// Data from a dormant alter (uncertain access)
27 Dormant(Option<Ident>),
28 /// Data from multiple alters (potentially contradictory)
29 Blended(Vec<Ident>),
30 /// Data from a specific named alter
31 Named(Ident),
32 /// Data from any alter matching a trait bound
33 Bound(AlterBound),
34}
35
36/// Trait bound for alter-generic code
37#[derive(Debug, Clone, PartialEq)]
38pub struct AlterBound {
39 /// The type parameter name (e.g., `A` in `fn foo<A: Alter>`)
40 pub name: Ident,
41 /// Required traits (e.g., `Alter`, `Council`, `Combat`)
42 pub bounds: Vec<Ident>,
43}
44
45// ============================================================================
46// ALTER DEFINITION
47// ============================================================================
48
49/// An alter definition - a first-class identity within the System.
50///
51/// ```sigil
52/// alter Abaddon: Council {
53/// archetype: Goetia::Abaddon,
54/// preferred_reality: RealityLayer::Fractured,
55/// abilities: [...],
56/// triggers: [...],
57/// anima: { ... },
58/// states: { ... }
59/// }
60/// ```
61#[derive(Debug, Clone, PartialEq)]
62pub struct AlterDef {
63 /// Visibility (pub, crate, etc.)
64 pub visibility: Visibility,
65 /// Attributes (#[derive(...)])
66 pub attrs: Vec<Attribute>,
67 /// Alter name
68 pub name: Ident,
69 /// Alter category (Council, Servant, Fragment, etc.)
70 pub category: AlterCategory,
71 /// Generic parameters
72 pub generics: Option<Generics>,
73 /// Where clause
74 pub where_clause: Option<WhereClause>,
75 /// Alter body
76 pub body: AlterBody,
77 /// Source span
78 pub span: Span,
79}
80
81/// Category of alter (determines capabilities)
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83pub enum AlterCategory {
84 /// Can front and take control
85 Council,
86 /// Maintains internal functions, cannot front
87 Servant,
88 /// Incomplete alter, may evolve
89 Fragment,
90 /// Hidden until discovered
91 Hidden,
92 /// Hostile or exiled alter
93 Persecutor,
94 /// Custom category
95 Custom,
96}
97
98/// Body of an alter definition
99#[derive(Debug, Clone, PartialEq)]
100pub struct AlterBody {
101 /// Archetype (Goetia demon, mythological figure, etc.)
102 pub archetype: Option<Expr>,
103 /// Preferred reality layer
104 pub preferred_reality: Option<Expr>,
105 /// Available abilities
106 pub abilities: Vec<Expr>,
107 /// Trigger conditions
108 pub triggers: Vec<Expr>,
109 /// Anima configuration (base emotional state)
110 pub anima: Option<AnimaConfig>,
111 /// State machine
112 pub states: Option<AlterStateMachine>,
113 /// Special capabilities
114 pub special: Vec<SpecialCapability>,
115 /// Methods and associated functions
116 pub methods: Vec<AlterMethod>,
117 /// Associated types
118 pub types: Vec<AlterTypeAlias>,
119}
120
121/// Anima configuration for an alter
122#[derive(Debug, Clone, PartialEq)]
123pub struct AnimaConfig {
124 /// Base arousal level (0.0 - 1.0)
125 pub base_arousal: Option<Expr>,
126 /// Base dominance level (0.0 - 1.0)
127 pub base_dominance: Option<Expr>,
128 /// How much this alter broadcasts emotions
129 pub expressiveness: Option<Expr>,
130 /// How much this alter picks up others' emotions
131 pub susceptibility: Option<Expr>,
132 /// Additional anima fields
133 pub extra: Vec<(Ident, Expr)>,
134}
135
136/// State machine for alter lifecycle
137#[derive(Debug, Clone, PartialEq)]
138pub struct AlterStateMachine {
139 /// State transitions
140 pub transitions: Vec<AlterTransition>,
141}
142
143/// A state transition in the alter lifecycle
144#[derive(Debug, Clone, PartialEq)]
145pub struct AlterTransition {
146 /// Source state
147 pub from: AlterState,
148 /// Target state
149 pub to: AlterState,
150 /// Trigger condition
151 pub on: Expr,
152 /// Guard condition (optional)
153 pub guard: Option<Expr>,
154 /// Action to perform (optional)
155 pub action: Option<Block>,
156}
157
158/// Possible states for an alter
159#[derive(Debug, Clone, PartialEq)]
160pub enum AlterState {
161 Dormant,
162 Stirring,
163 CoConscious,
164 Emerging,
165 Fronting,
166 Receding,
167 Triggered,
168 Dissociating,
169 /// Custom state
170 Custom(Ident),
171}
172
173/// Special capability unique to an alter
174#[derive(Debug, Clone, PartialEq)]
175pub struct SpecialCapability {
176 pub name: Ident,
177 pub params: Vec<(Ident, Expr)>,
178}
179
180/// Method defined on an alter
181#[derive(Debug, Clone, PartialEq)]
182pub struct AlterMethod {
183 pub visibility: Visibility,
184 pub is_async: bool,
185 pub name: Ident,
186 pub params: Vec<Param>,
187 pub return_type: Option<TypeExpr>,
188 pub body: Option<Block>,
189}
190
191/// Type alias for an alter
192#[derive(Debug, Clone, PartialEq)]
193pub struct AlterTypeAlias {
194 pub visibility: Visibility,
195 pub name: Ident,
196 pub ty: TypeExpr,
197}
198
199// ============================================================================
200// ALTER BLOCK
201// ============================================================================
202
203/// An alter block - scoped fronting for a code section.
204///
205/// ```sigil
206/// alter Abaddon {
207/// // Inside here, 'self' refers to Abaddon
208/// // Perception uses Abaddon's view
209/// let threat = perceive_entity(enemy);
210/// }
211/// ```
212#[derive(Debug, Clone, PartialEq)]
213pub struct AlterBlock {
214 /// Which alter is fronting for this block
215 pub alter: AlterExpr,
216 /// The code to execute as that alter
217 pub body: Block,
218 /// Source span
219 pub span: Span,
220}
221
222/// Expression that resolves to an alter
223#[derive(Debug, Clone, PartialEq)]
224pub enum AlterExpr {
225 /// Named alter: `alter Abaddon { ... }`
226 Named(Ident),
227 /// Current fronter: `alter council·fronter() { ... }`
228 CurrentFronter(Box<Expr>),
229 /// Expression that evaluates to an alter
230 Expr(Box<Expr>),
231}
232
233// ============================================================================
234// SWITCH EXPRESSION
235// ============================================================================
236
237/// A switch expression - deliberated or forced switching.
238///
239/// ```sigil
240/// let result = switch to Beleth {
241/// reason: SwitchReason::TacticalNeed,
242/// urgency: 0.8,
243/// requires: Consensus::Majority,
244/// then: { ... },
245/// else: { ... },
246/// emergency: { force_switch() }
247/// };
248/// ```
249#[derive(Debug, Clone, PartialEq)]
250pub struct SwitchExpr {
251 /// Is this a forced switch (switch!)
252 pub forced: bool,
253 /// Target alter
254 pub target: AlterExpr,
255 /// Switch configuration
256 pub config: SwitchConfig,
257 /// Source span
258 pub span: Span,
259}
260
261/// Configuration for a switch
262#[derive(Debug, Clone, PartialEq)]
263pub struct SwitchConfig {
264 /// Reason for the switch
265 pub reason: Option<Expr>,
266 /// Urgency level (0.0 - 1.0)
267 pub urgency: Option<Expr>,
268 /// Required consensus level
269 pub requires: Option<Expr>,
270 /// Block to execute on success
271 pub then_block: Option<Block>,
272 /// Block to execute on failure
273 pub else_block: Option<Block>,
274 /// Emergency override block
275 pub emergency_block: Option<Block>,
276 /// Whether to bypass deliberation
277 pub bypass_deliberation: bool,
278}
279
280// ============================================================================
281// CO-CONSCIOUS CHANNEL
282// ============================================================================
283
284/// A co-conscious communication channel.
285///
286/// ```sigil
287/// cocon<Stolas, Paimon> knowledge_share {
288/// fn share_discovery(info: Knowledge!) -> Acknowledgment~ {
289/// Paimon.receive(info~)
290/// }
291/// }
292/// ```
293#[derive(Debug, Clone, PartialEq)]
294pub struct CoConChannel {
295 /// Participating alters
296 pub participants: Vec<Ident>,
297 /// Channel name
298 pub name: Ident,
299 /// Channel body
300 pub body: Block,
301 /// Source span
302 pub span: Span,
303}
304
305// ============================================================================
306// REALITY LAYER DEFINITION
307// ============================================================================
308
309/// A reality layer definition for superimposed entities.
310///
311/// ```sigil
312/// reality entity Church {
313/// layer Grounded {
314/// name: "First Ward Chapel",
315/// threat: 0.2,
316/// }
317/// layer Fractured {
318/// name: "The White Throne's Outpost",
319/// threat: 0.8,
320/// }
321/// transform Grounded -> Fractured: on perception > 0.5,
322/// }
323/// ```
324#[derive(Debug, Clone, PartialEq)]
325pub struct RealityDef {
326 /// Visibility
327 pub visibility: Visibility,
328 /// Entity name
329 pub name: Ident,
330 /// Layer definitions
331 pub layers: Vec<RealityLayer>,
332 /// Transform rules
333 pub transforms: Vec<RealityTransform>,
334 /// Source span
335 pub span: Span,
336}
337
338/// A single reality layer
339#[derive(Debug, Clone, PartialEq)]
340pub struct RealityLayer {
341 /// Layer name (Grounded, Fractured, Psychological, Cosmic)
342 pub name: Ident,
343 /// Layer fields
344 pub fields: Vec<(Ident, Expr)>,
345}
346
347/// A transform rule between reality layers
348#[derive(Debug, Clone, PartialEq)]
349pub struct RealityTransform {
350 /// Source layer
351 pub from: Ident,
352 /// Target layer
353 pub to: Ident,
354 /// Condition for transform
355 pub condition: Expr,
356}
357
358// ============================================================================
359// HEADSPACE DEFINITION
360// ============================================================================
361
362/// A headspace (Inner World) definition.
363///
364/// ```sigil
365/// headspace InnerWorld {
366/// location Citadel: Sanctuary {
367/// biome: Biome::Citadel,
368/// connections: [...]
369/// }
370///
371/// fn navigate(from: LocationId, to: LocationId) -> NavigationResult@? { ... }
372/// }
373/// ```
374#[derive(Debug, Clone, PartialEq)]
375pub struct HeadspaceDef {
376 /// Visibility
377 pub visibility: Visibility,
378 /// Headspace name
379 pub name: Ident,
380 /// Location definitions
381 pub locations: Vec<LocationDef>,
382 /// Methods
383 pub methods: Vec<AlterMethod>,
384 /// Source span
385 pub span: Span,
386}
387
388/// A location in the headspace
389#[derive(Debug, Clone, PartialEq)]
390pub struct LocationDef {
391 /// Location name
392 pub name: Ident,
393 /// Location type (Sanctuary, PersonalDomain, etc.)
394 pub location_type: Ident,
395 /// Location fields
396 pub fields: Vec<(Ident, Expr)>,
397 /// Connections (stream definitions)
398 pub connections: Vec<StreamDef>,
399 /// Hazards
400 pub hazards: Vec<Expr>,
401}
402
403/// A consciousness stream connection
404#[derive(Debug, Clone, PartialEq)]
405pub struct StreamDef {
406 /// Target location
407 pub target: Ident,
408 /// Stream content type
409 pub content: Option<Expr>,
410 /// Is bidirectional
411 pub bidirectional: bool,
412 /// Is locked
413 pub locked: bool,
414}
415
416// ============================================================================
417// SPLIT EXPRESSION
418// ============================================================================
419
420/// A split expression - trauma-based alter creation.
421///
422/// ```sigil
423/// let new_alter = split! from trauma.primary_holder {
424/// purpose: SplitPurpose::TraumaHolder,
425/// memories: inherited_memories(),
426/// traits: possibly_inverted_traits(),
427/// };
428/// ```
429#[derive(Debug, Clone, PartialEq)]
430pub struct SplitExpr {
431 /// Parent alter to split from
432 pub parent: AlterExpr,
433 /// Split configuration
434 pub config: SplitConfig,
435 /// Source span
436 pub span: Span,
437}
438
439/// Configuration for a split
440#[derive(Debug, Clone, PartialEq)]
441pub struct SplitConfig {
442 /// Purpose of the new alter
443 pub purpose: Option<Expr>,
444 /// Memories to inherit
445 pub memories: Option<Expr>,
446 /// Traits to inherit (may be inverted)
447 pub traits: Option<Expr>,
448 /// Additional fields
449 pub extra: Vec<(Ident, Expr)>,
450}
451
452// ============================================================================
453// TYPE EXTENSIONS
454// ============================================================================
455
456/// Extended type expression with alter-source
457#[derive(Debug, Clone, PartialEq)]
458pub struct AlterSourcedType {
459 /// Base type
460 pub inner: TypeExpr,
461 /// Alter source
462 pub alter_source: AlterSource,
463 /// Source span
464 pub span: Span,
465}
466
467// ============================================================================
468// TRIGGER DEFINITION
469// ============================================================================
470
471/// A trigger handler definition.
472///
473/// ```sigil
474/// on trigger ThreatDetected { level: threat } where threat > 0.9 {
475/// switch! to Abaddon {
476/// reason: SwitchReason::Emergency,
477/// bypass_deliberation: true,
478/// }
479/// }
480/// ```
481#[derive(Debug, Clone, PartialEq)]
482pub struct TriggerHandler {
483 /// Trigger pattern to match
484 pub pattern: TriggerPattern,
485 /// Guard condition
486 pub guard: Option<Expr>,
487 /// Handler body
488 pub body: Block,
489 /// Source span
490 pub span: Span,
491}
492
493/// Pattern for matching triggers
494#[derive(Debug, Clone, PartialEq)]
495pub struct TriggerPattern {
496 /// Trigger type name
497 pub trigger_type: Ident,
498 /// Destructured fields
499 pub fields: Vec<(Ident, Ident)>,
500}
501
502// ============================================================================
503// PLURALITY ITEM (TOP-LEVEL)
504// ============================================================================
505
506/// Top-level plurality items
507#[derive(Debug, Clone, PartialEq)]
508pub enum PluralityItem {
509 /// Alter definition
510 Alter(AlterDef),
511 /// Headspace definition
512 Headspace(HeadspaceDef),
513 /// Reality entity definition
514 Reality(RealityDef),
515 /// Co-conscious channel
516 CoConChannel(CoConChannel),
517 /// Trigger handler
518 TriggerHandler(TriggerHandler),
519}
520
521// ============================================================================
522// PLURALITY EXPRESSION
523// ============================================================================
524
525/// Plurality-specific expressions
526#[derive(Debug, Clone, PartialEq)]
527pub enum PluralityExpr {
528 /// Alter block
529 AlterBlock(AlterBlock),
530 /// Switch expression
531 Switch(SwitchExpr),
532 /// Split expression
533 Split(SplitExpr),
534 /// Alter-sourced value access
535 AlterSourced {
536 expr: Box<Expr>,
537 source: AlterSource,
538 span: Span,
539 },
540}
541
542// ============================================================================
543// CONVERSION TRAITS
544// ============================================================================
545
546impl From<AlterDef> for PluralityItem {
547 fn from(def: AlterDef) -> Self {
548 PluralityItem::Alter(def)
549 }
550}
551
552impl From<HeadspaceDef> for PluralityItem {
553 fn from(def: HeadspaceDef) -> Self {
554 PluralityItem::Headspace(def)
555 }
556}
557
558impl From<RealityDef> for PluralityItem {
559 fn from(def: RealityDef) -> Self {
560 PluralityItem::Reality(def)
561 }
562}
563
564impl AlterState {
565 /// Parse from identifier
566 pub fn from_ident(ident: &Ident) -> Self {
567 match ident.name.as_str() {
568 "Dormant" => AlterState::Dormant,
569 "Stirring" => AlterState::Stirring,
570 "CoConscious" => AlterState::CoConscious,
571 "Emerging" => AlterState::Emerging,
572 "Fronting" => AlterState::Fronting,
573 "Receding" => AlterState::Receding,
574 "Triggered" => AlterState::Triggered,
575 "Dissociating" => AlterState::Dissociating,
576 _ => AlterState::Custom(ident.clone()),
577 }
578 }
579}
580
581impl AlterCategory {
582 /// Parse from identifier
583 pub fn from_ident(ident: &Ident) -> Self {
584 match ident.name.as_str() {
585 "Council" => AlterCategory::Council,
586 "Servant" => AlterCategory::Servant,
587 "Fragment" => AlterCategory::Fragment,
588 "Hidden" => AlterCategory::Hidden,
589 "Persecutor" => AlterCategory::Persecutor,
590 _ => AlterCategory::Custom,
591 }
592 }
593}
594
595#[cfg(test)]
596mod tests {
597 use super::*;
598
599 #[test]
600 fn test_alter_state_parsing() {
601 let ident = Ident {
602 name: "Fronting".to_string(),
603 evidentiality: None,
604 affect: None,
605 span: Span::default(),
606 };
607 assert_eq!(AlterState::from_ident(&ident), AlterState::Fronting);
608 }
609
610 #[test]
611 fn test_alter_category_parsing() {
612 let ident = Ident {
613 name: "Council".to_string(),
614 evidentiality: None,
615 affect: None,
616 span: Span::default(),
617 };
618 assert_eq!(AlterCategory::from_ident(&ident), AlterCategory::Council);
619 }
620}