Skip to main content

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}