sea_core/parser/
ast.rs

1use crate::graph::Graph;
2use crate::parser::error::{ParseError, ParseResult};
3use crate::parser::{ParseOptions, Rule, SeaParser};
4use crate::patterns::Pattern;
5use crate::policy::{
6    AggregateFunction, BinaryOp, Expression, Policy, PolicyKind as CorePolicyKind,
7    PolicyModality as CorePolicyModality, Quantifier as PolicyQuantifier, UnaryOp, WindowSpec,
8};
9use crate::primitives::{ConceptChange, Entity, Flow, RelationType, Resource, Role, Severity};
10use crate::units::unit_from_string;
11use crate::SemanticVersion;
12use chrono::Duration;
13use pest::iterators::{Pair, Pairs};
14use pest::{Parser, Span};
15use rust_decimal::prelude::ToPrimitive;
16use rust_decimal::Decimal;
17use serde::{Deserialize, Serialize};
18use serde_json::json;
19use serde_json::Value as JsonValue;
20use std::collections::HashMap;
21
22/// File-level metadata from header annotations
23#[derive(Debug, Clone, PartialEq, Default)]
24pub struct FileMetadata {
25    pub namespace: Option<String>,
26    pub version: Option<String>,
27    pub owner: Option<String>,
28    pub profile: Option<String>,
29    pub imports: Vec<ImportDecl>,
30}
31
32/// Import declaration for a module file
33#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
34pub struct ImportDecl {
35    pub specifier: ImportSpecifier,
36    pub from_module: String,
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40pub enum ImportSpecifier {
41    Named(Vec<ImportItem>),
42    Wildcard(String),
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
46pub struct ImportItem {
47    pub name: String,
48    pub alias: Option<String>,
49}
50
51/// Policy metadata
52#[derive(Debug, Clone, PartialEq)]
53pub struct PolicyMetadata {
54    pub kind: Option<PolicyKind>,
55    pub modality: Option<PolicyModality>,
56    pub priority: Option<i32>,
57    pub rationale: Option<String>,
58    pub tags: Vec<String>,
59}
60
61#[derive(Debug, Clone, PartialEq)]
62pub enum PolicyKind {
63    Constraint,
64    Derivation,
65    Obligation,
66}
67
68impl std::fmt::Display for PolicyKind {
69    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        match self {
71            PolicyKind::Constraint => write!(f, "Constraint"),
72            PolicyKind::Derivation => write!(f, "Derivation"),
73            PolicyKind::Obligation => write!(f, "Obligation"),
74        }
75    }
76}
77
78#[derive(Debug, Clone, PartialEq)]
79pub enum PolicyModality {
80    Obligation,
81    Prohibition,
82    Permission,
83}
84
85impl std::fmt::Display for PolicyModality {
86    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87        match self {
88            PolicyModality::Obligation => write!(f, "Obligation"),
89            PolicyModality::Prohibition => write!(f, "Prohibition"),
90            PolicyModality::Permission => write!(f, "Permission"),
91        }
92    }
93}
94
95/// Metric declaration AST node
96#[derive(Debug, Clone, PartialEq)]
97pub struct MetricMetadata {
98    pub refresh_interval: Option<Duration>,
99    pub unit: Option<String>,
100    pub threshold: Option<Decimal>,
101    pub severity: Option<Severity>,
102    pub target: Option<Decimal>,
103    pub window: Option<Duration>,
104}
105
106#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
107pub enum TargetFormat {
108    Calm,
109    Kg,
110    Sbvr,
111    Protobuf,
112}
113
114impl std::fmt::Display for TargetFormat {
115    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116        match self {
117            TargetFormat::Calm => write!(f, "CALM"),
118            TargetFormat::Kg => write!(f, "KG"),
119            TargetFormat::Sbvr => write!(f, "SBVR"),
120            TargetFormat::Protobuf => write!(f, "Protobuf"),
121        }
122    }
123}
124
125#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
126pub struct MappingRule {
127    pub primitive_type: String,
128    pub primitive_name: String,
129    pub target_type: String,
130    pub fields: HashMap<String, JsonValue>,
131}
132
133#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
134pub struct ProjectionOverride {
135    pub primitive_type: String,
136    pub primitive_name: String,
137    pub fields: HashMap<String, JsonValue>,
138}
139
140/// Abstract Syntax Tree for SEA DSL
141#[derive(Debug, Clone, PartialEq)]
142pub struct Ast {
143    pub metadata: FileMetadata,
144    pub declarations: Vec<AstNode>,
145}
146
147/// AST Node types
148#[derive(Debug, Clone, PartialEq)]
149pub enum AstNode {
150    Export(Box<AstNode>),
151    Entity {
152        name: String,
153        version: Option<String>,
154        annotations: HashMap<String, JsonValue>,
155        domain: Option<String>,
156    },
157    Resource {
158        name: String,
159        unit_name: Option<String>,
160        domain: Option<String>,
161    },
162    Flow {
163        resource_name: String,
164        from_entity: String,
165        to_entity: String,
166        quantity: Option<i32>,
167    },
168    Pattern {
169        name: String,
170        regex: String,
171    },
172    Role {
173        name: String,
174        domain: Option<String>,
175    },
176    Relation {
177        name: String,
178        subject_role: String,
179        predicate: String,
180        object_role: String,
181        via_flow: Option<String>,
182    },
183    Dimension {
184        name: String,
185    },
186    UnitDeclaration {
187        symbol: String,
188        dimension: String,
189        factor: Decimal,
190        base_unit: String,
191    },
192    Policy {
193        name: String,
194        version: Option<String>,
195        metadata: PolicyMetadata,
196        expression: Expression,
197    },
198    Instance {
199        name: String,
200        entity_type: String,
201        fields: HashMap<String, Expression>,
202    },
203    ConceptChange {
204        name: String,
205        from_version: String,
206        to_version: String,
207        migration_policy: String,
208        breaking_change: bool,
209    },
210    Metric {
211        name: String,
212        expression: Expression,
213        metadata: MetricMetadata,
214    },
215    MappingDecl {
216        name: String,
217        target: TargetFormat,
218        rules: Vec<MappingRule>,
219    },
220    ProjectionDecl {
221        name: String,
222        target: TargetFormat,
223        overrides: Vec<ProjectionOverride>,
224    },
225}
226
227/// Parse source code into an AST
228pub fn parse_source(source: &str) -> ParseResult<Ast> {
229    let pairs = SeaParser::parse(Rule::program, source)?;
230    build_ast(pairs)
231}
232
233/// Build AST from pest pairs
234fn build_ast(pairs: Pairs<Rule>) -> ParseResult<Ast> {
235    let mut metadata = FileMetadata::default();
236    let mut declarations = Vec::new();
237
238    for pair in pairs {
239        match pair.as_rule() {
240            Rule::program => {
241                for inner in pair.into_inner() {
242                    match inner.as_rule() {
243                        Rule::file_header => {
244                            metadata = parse_file_header(inner)?;
245                        }
246                        Rule::declaration => {
247                            for decl in inner.into_inner() {
248                                let node = parse_declaration(decl)?;
249                                declarations.push(node);
250                            }
251                        }
252                        Rule::EOI => {}
253                        _ => {}
254                    }
255                }
256            }
257            Rule::EOI => {}
258            _ => {}
259        }
260    }
261
262    Ok(Ast {
263        metadata,
264        declarations,
265    })
266}
267
268/// Parse file header annotations
269fn parse_file_header(pair: Pair<Rule>) -> ParseResult<FileMetadata> {
270    let mut metadata = FileMetadata::default();
271
272    for annotation in pair.into_inner() {
273        match annotation.as_rule() {
274            Rule::annotation => {
275                let mut inner = annotation.into_inner();
276                let name = inner.next().ok_or_else(|| {
277                    ParseError::GrammarError("Expected annotation name".to_string())
278                })?;
279                let value = inner.next().ok_or_else(|| {
280                    ParseError::GrammarError("Expected annotation value".to_string())
281                })?;
282
283                let name_str = name.as_str().to_lowercase();
284                let value_str = parse_string_literal(value)?;
285
286                match name_str.as_str() {
287                    "namespace" => metadata.namespace = Some(value_str),
288                    "version" => metadata.version = Some(value_str),
289                    "owner" => metadata.owner = Some(value_str),
290                    "profile" => metadata.profile = Some(value_str),
291                    _ => {
292                        return Err(ParseError::GrammarError(format!(
293                            "Unknown annotation: {}",
294                            name_str
295                        )))
296                    }
297                }
298            }
299            Rule::import_decl => {
300                metadata.imports.push(parse_import_decl(annotation)?);
301            }
302            _ => {}
303        }
304    }
305
306    Ok(metadata)
307}
308
309/// Parse a single declaration
310fn parse_declaration(pair: Pair<Rule>) -> ParseResult<AstNode> {
311    match pair.as_rule() {
312        Rule::export_decl => {
313            let mut inner = pair.into_inner();
314            let wrapped = inner.next().ok_or_else(|| {
315                ParseError::GrammarError("Expected declaration after export".to_string())
316            })?;
317            let node = parse_declaration(wrapped)?;
318            Ok(AstNode::Export(Box::new(node)))
319        }
320        Rule::declaration_inner => {
321            let inner = pair
322                .into_inner()
323                .next()
324                .ok_or_else(|| ParseError::GrammarError("Empty declaration".to_string()))?;
325            parse_declaration(inner)
326        }
327        Rule::dimension_decl => parse_dimension(pair),
328        Rule::unit_decl => parse_unit_declaration(pair),
329        Rule::entity_decl => parse_entity(pair),
330        Rule::resource_decl => parse_resource(pair),
331        Rule::flow_decl => parse_flow(pair),
332        Rule::pattern_decl => parse_pattern(pair),
333        Rule::role_decl => parse_role(pair),
334        Rule::relation_decl => parse_relation(pair),
335        Rule::instance_decl => parse_instance(pair),
336        Rule::policy_decl => parse_policy(pair),
337        Rule::concept_change_decl => parse_concept_change(pair),
338        Rule::metric_decl => parse_metric(pair),
339        Rule::mapping_decl => parse_mapping(pair),
340        Rule::projection_decl => parse_projection(pair),
341        _ => Err(ParseError::GrammarError(format!(
342            "Unexpected rule: {:?}",
343            pair.as_rule()
344        ))),
345    }
346}
347
348fn parse_import_decl(pair: Pair<Rule>) -> ParseResult<ImportDecl> {
349    let mut inner = pair.into_inner();
350    let specifier_pair = inner
351        .next()
352        .ok_or_else(|| ParseError::GrammarError("Missing import specifier".to_string()))?;
353    let from_pair = inner
354        .next()
355        .ok_or_else(|| ParseError::GrammarError("Missing import source".to_string()))?;
356
357    let specifier = match specifier_pair.as_rule() {
358        Rule::import_specifier | Rule::import_named | Rule::import_wildcard => {
359            parse_import_specifier(specifier_pair)?
360        }
361        _ => {
362            return Err(ParseError::GrammarError(format!(
363                "Unexpected import specifier: {:?}",
364                specifier_pair.as_rule()
365            )))
366        }
367    };
368
369    Ok(ImportDecl {
370        specifier,
371        from_module: parse_string_literal(from_pair)?,
372    })
373}
374
375fn parse_import_specifier(pair: Pair<Rule>) -> ParseResult<ImportSpecifier> {
376    match pair.as_rule() {
377        Rule::import_wildcard => {
378            let mut inner = pair.into_inner();
379            let alias = parse_identifier(inner.next().ok_or_else(|| {
380                ParseError::GrammarError("Expected alias for wildcard import".to_string())
381            })?)?;
382            Ok(ImportSpecifier::Wildcard(alias))
383        }
384        Rule::import_specifier | Rule::import_named => {
385            let mut items = Vec::new();
386            for item in pair.into_inner() {
387                if item.as_rule() == Rule::import_item {
388                    items.push(parse_import_item(item)?);
389                }
390            }
391            Ok(ImportSpecifier::Named(items))
392        }
393        _ => Err(ParseError::GrammarError(
394            "Invalid import specifier".to_string(),
395        )),
396    }
397}
398
399fn parse_import_item(pair: Pair<Rule>) -> ParseResult<ImportItem> {
400    let mut inner = pair.into_inner();
401    let name_pair = inner
402        .next()
403        .ok_or_else(|| ParseError::GrammarError("Expected import item name".to_string()))?;
404    let alias = inner.next().map(parse_identifier).transpose()?;
405
406    Ok(ImportItem {
407        name: parse_identifier(name_pair)?,
408        alias,
409    })
410}
411
412/// Parse dimension declaration
413fn parse_dimension(pair: Pair<Rule>) -> ParseResult<AstNode> {
414    let mut inner = pair.into_inner();
415    let name = parse_string_literal(
416        inner
417            .next()
418            .ok_or_else(|| ParseError::GrammarError("Expected dimension name".to_string()))?,
419    )?;
420
421    Ok(AstNode::Dimension { name })
422}
423
424/// Parse unit declaration
425fn parse_unit_declaration(pair: Pair<Rule>) -> ParseResult<AstNode> {
426    let mut inner = pair.into_inner();
427
428    let symbol = parse_string_literal(
429        inner
430            .next()
431            .ok_or_else(|| ParseError::GrammarError("Expected unit symbol".to_string()))?,
432    )?;
433
434    let dimension = parse_string_literal(
435        inner
436            .next()
437            .ok_or_else(|| ParseError::GrammarError("Expected dimension name".to_string()))?,
438    )?;
439
440    let factor_pair = inner
441        .next()
442        .ok_or_else(|| ParseError::GrammarError("Expected factor".to_string()))?;
443    let factor = parse_decimal(factor_pair)?;
444
445    let base_unit = parse_string_literal(
446        inner
447            .next()
448            .ok_or_else(|| ParseError::GrammarError("Expected base unit".to_string()))?,
449    )?;
450
451    Ok(AstNode::UnitDeclaration {
452        symbol,
453        dimension,
454        factor,
455        base_unit,
456    })
457}
458
459/// Parse entity declaration
460fn parse_entity(pair: Pair<Rule>) -> ParseResult<AstNode> {
461    let mut inner = pair.into_inner();
462
463    let name = parse_name(
464        inner
465            .next()
466            .ok_or_else(|| ParseError::GrammarError("Expected entity name".to_string()))?,
467    )?;
468
469    let mut version = None;
470    let mut annotations = HashMap::new();
471    let mut domain = None;
472
473    for part in inner {
474        match part.as_rule() {
475            Rule::version => {
476                version = Some(part.as_str().to_string());
477            }
478            Rule::entity_annotation => {
479                let mut annotation_inner = part.into_inner();
480                let key_pair = annotation_inner
481                    .next()
482                    .ok_or_else(|| ParseError::GrammarError("Empty annotation".to_string()))?;
483
484                match key_pair.as_rule() {
485                    Rule::ea_replaces => {
486                        let target_name =
487                            parse_name(annotation_inner.next().ok_or_else(|| {
488                                ParseError::GrammarError("Expected name in replaces".to_string())
489                            })?)?;
490                        // Check for optional version
491                        let mut target_version = None;
492                        if let Some(next) = annotation_inner.next() {
493                            if next.as_rule() == Rule::version {
494                                target_version = Some(next.as_str().to_string());
495                            }
496                        }
497
498                        let value = if let Some(v) = target_version {
499                            format!("{} v{}", target_name, v)
500                        } else {
501                            target_name
502                        };
503                        annotations.insert("replaces".to_string(), JsonValue::String(value));
504                    }
505                    Rule::ea_changes => {
506                        let array_pair = annotation_inner.next().ok_or_else(|| {
507                            ParseError::GrammarError("Expected string array in changes".to_string())
508                        })?;
509                        let mut changes = Vec::new();
510                        for item in array_pair.into_inner() {
511                            changes.push(parse_string_literal(item)?);
512                        }
513                        annotations.insert(
514                            "changes".to_string(),
515                            JsonValue::Array(changes.into_iter().map(JsonValue::String).collect()),
516                        );
517                    }
518                    _ => {}
519                }
520            }
521            Rule::in_keyword => {
522                // Skip "in"
523            }
524            Rule::identifier => {
525                // This must be the domain
526                domain = Some(parse_identifier(part)?);
527            }
528            _ => {}
529        }
530    }
531
532    Ok(AstNode::Entity {
533        name,
534        version,
535        annotations,
536        domain,
537    })
538}
539
540/// Parse concept change declaration
541fn parse_concept_change(pair: Pair<Rule>) -> ParseResult<AstNode> {
542    let mut inner = pair.into_inner();
543
544    let name =
545        parse_name(inner.next().ok_or_else(|| {
546            ParseError::GrammarError("Expected concept change name".to_string())
547        })?)?;
548
549    let mut from_version = String::new();
550    let mut to_version = String::new();
551    let mut migration_policy = String::new();
552    let mut breaking_change = false;
553
554    for part in inner {
555        if part.as_rule() == Rule::concept_change_annotation {
556            let mut annotation_inner = part.into_inner();
557
558            let key_pair = annotation_inner
559                .next()
560                .ok_or_else(|| ParseError::GrammarError("Expected annotation key".to_string()))?;
561            let value_pair = annotation_inner
562                .next()
563                .ok_or_else(|| ParseError::GrammarError("Expected annotation value".to_string()))?;
564
565            match key_pair.as_rule() {
566                Rule::cc_from_version => from_version = parse_version(value_pair)?,
567                Rule::cc_to_version => to_version = parse_version(value_pair)?,
568                Rule::cc_migration_policy => migration_policy = parse_identifier(value_pair)?,
569                Rule::cc_breaking_change => {
570                    breaking_change = value_pair.as_str() == "true";
571                }
572                _ => {}
573            }
574        }
575    }
576
577    if from_version.is_empty() {
578        return Err(ParseError::GrammarError(
579            "Missing cc_from_version annotation".to_string(),
580        ));
581    }
582
583    if to_version.is_empty() {
584        return Err(ParseError::GrammarError(
585            "Missing cc_to_version annotation".to_string(),
586        ));
587    }
588
589    if migration_policy.is_empty() {
590        return Err(ParseError::GrammarError(
591            "Missing cc_migration_policy annotation".to_string(),
592        ));
593    }
594
595    Ok(AstNode::ConceptChange {
596        name,
597        from_version,
598        to_version,
599        migration_policy,
600        breaking_change,
601    })
602}
603
604/// Parse resource declaration
605fn parse_resource(pair: Pair<Rule>) -> ParseResult<AstNode> {
606    let mut inner = pair.into_inner();
607
608    let name = parse_name(
609        inner
610            .next()
611            .ok_or_else(|| ParseError::GrammarError("Expected resource name".to_string()))?,
612    )?;
613
614    let mut unit_name = None;
615    let mut domain = None;
616
617    // The grammar produces these patterns (with in_keyword as a separate token):
618    // 1. string_literal + identifier + in_keyword + identifier = unit + domain
619    // 2. string_literal + in_keyword + identifier = domain only
620    // 3. string_literal + identifier = unit only
621    // 4. string_literal only = nothing
622
623    if let Some(first) = inner.next() {
624        match first.as_rule() {
625            Rule::in_keyword => {
626                // Case 2: in_keyword + identifier (domain only)
627                domain = Some(parse_identifier(inner.next().ok_or_else(|| {
628                    ParseError::GrammarError("Expected domain after 'in'".to_string())
629                })?)?);
630            }
631            Rule::identifier => {
632                // Case 1 or 3: starts with identifier
633                unit_name = Some(parse_identifier(first)?);
634
635                // Check if followed by in_keyword + identifier
636                if let Some(second) = inner.next() {
637                    if second.as_rule() == Rule::in_keyword {
638                        // Case 1: identifier + in_keyword + identifier
639                        domain = Some(parse_identifier(inner.next().ok_or_else(|| {
640                            ParseError::GrammarError("Expected domain after 'in'".to_string())
641                        })?)?);
642                    }
643                    // If second is not in_keyword, it's unexpected (grammar shouldn't allow this)
644                }
645                // If no second token, it's case 3 (unit only)
646            }
647            _ => {
648                return Err(ParseError::GrammarError(
649                    "Unexpected token in resource declaration".to_string(),
650                ));
651            }
652        }
653    }
654
655    Ok(AstNode::Resource {
656        name,
657        unit_name,
658        domain,
659    })
660}
661
662/// Parse flow declaration
663fn parse_flow(pair: Pair<Rule>) -> ParseResult<AstNode> {
664    let mut inner = pair.into_inner();
665
666    let resource_name = parse_string_literal(
667        inner
668            .next()
669            .ok_or_else(|| ParseError::GrammarError("Expected resource name".to_string()))?,
670    )?;
671
672    let from_entity = parse_string_literal(
673        inner
674            .next()
675            .ok_or_else(|| ParseError::GrammarError("Expected from entity".to_string()))?,
676    )?;
677
678    let to_entity = parse_string_literal(
679        inner
680            .next()
681            .ok_or_else(|| ParseError::GrammarError("Expected to entity".to_string()))?,
682    )?;
683
684    let quantity = if let Some(qty_pair) = inner.next() {
685        Some(parse_number(qty_pair)?)
686    } else {
687        None
688    };
689
690    Ok(AstNode::Flow {
691        resource_name,
692        from_entity,
693        to_entity,
694        quantity,
695    })
696}
697
698/// Parse pattern declaration
699fn parse_pattern(pair: Pair<Rule>) -> ParseResult<AstNode> {
700    let mut inner = pair.into_inner();
701
702    let name = parse_name(
703        inner
704            .next()
705            .ok_or_else(|| ParseError::GrammarError("Expected pattern name".to_string()))?,
706    )?;
707
708    let regex_literal = inner
709        .next()
710        .ok_or_else(|| ParseError::GrammarError("Expected regex for pattern".to_string()))?;
711    let regex = parse_string_literal(regex_literal)?;
712
713    Ok(AstNode::Pattern { name, regex })
714}
715
716/// Parse role declaration
717fn parse_role(pair: Pair<Rule>) -> ParseResult<AstNode> {
718    let mut inner = pair.into_inner();
719
720    let name = parse_name(
721        inner
722            .next()
723            .ok_or_else(|| ParseError::GrammarError("Expected role name".to_string()))?,
724    )?;
725
726    let domain = if let Some(domain_pair) = inner.next() {
727        Some(parse_identifier(domain_pair)?)
728    } else {
729        None
730    };
731
732    Ok(AstNode::Role { name, domain })
733}
734
735/// Parse relation declaration
736fn parse_relation(pair: Pair<Rule>) -> ParseResult<AstNode> {
737    let mut inner = pair.into_inner();
738
739    let name = parse_name(
740        inner
741            .next()
742            .ok_or_else(|| ParseError::GrammarError("Expected relation name".to_string()))?,
743    )?;
744
745    let subject_literal = inner
746        .next()
747        .ok_or_else(|| ParseError::GrammarError("Expected subject role in relation".to_string()))?;
748    let subject_role = parse_string_literal(subject_literal)?;
749
750    let predicate_literal = inner
751        .next()
752        .ok_or_else(|| ParseError::GrammarError("Expected predicate in relation".to_string()))?;
753    let predicate = parse_string_literal(predicate_literal)?;
754
755    let object_literal = inner
756        .next()
757        .ok_or_else(|| ParseError::GrammarError("Expected object role in relation".to_string()))?;
758    let object_role = parse_string_literal(object_literal)?;
759
760    let via_flow = if let Some(via_pair) = inner.next() {
761        match via_pair.as_rule() {
762            Rule::string_literal => Some(parse_string_literal(via_pair)?),
763            _ => {
764                let mut via_inner = via_pair.into_inner();
765                let flow_literal = via_inner.next().ok_or_else(|| {
766                    ParseError::GrammarError("Expected flow name after via".to_string())
767                })?;
768                Some(parse_string_literal(flow_literal)?)
769            }
770        }
771    } else {
772        None
773    };
774
775    Ok(AstNode::Relation {
776        name,
777        subject_role,
778        predicate,
779        object_role,
780        via_flow,
781    })
782}
783
784/// Parse instance declaration
785fn parse_instance(pair: Pair<Rule>) -> ParseResult<AstNode> {
786    let mut inner = pair.into_inner();
787
788    let name = parse_identifier(
789        inner
790            .next()
791            .ok_or_else(|| ParseError::GrammarError("Expected instance name".to_string()))?,
792    )?;
793
794    let entity_type = parse_string_literal(
795        inner
796            .next()
797            .ok_or_else(|| ParseError::GrammarError("Expected entity type".to_string()))?,
798    )?;
799
800    let mut fields = HashMap::new();
801
802    // Parse optional instance body
803    if let Some(body_pair) = inner.next() {
804        if body_pair.as_rule() == Rule::instance_body {
805            for field_pair in body_pair.into_inner() {
806                if field_pair.as_rule() == Rule::instance_field {
807                    let span = field_pair.as_span();
808                    let mut field_inner = field_pair.into_inner();
809
810                    let field_name = parse_identifier(field_inner.next().ok_or_else(|| {
811                        ParseError::GrammarError("Expected field name".to_string())
812                    })?)?;
813
814                    if fields.contains_key(&field_name) {
815                        let (line, column) = span.start_pos().line_col();
816                        return Err(ParseError::GrammarError(format!(
817                            "Duplicate field name '{}' at line {}, column {}",
818                            field_name, line, column
819                        )));
820                    }
821
822                    let field_value = parse_expression(field_inner.next().ok_or_else(|| {
823                        ParseError::GrammarError("Expected field value".to_string())
824                    })?)?;
825
826                    fields.insert(field_name, field_value);
827                }
828            }
829        }
830    }
831
832    Ok(AstNode::Instance {
833        name,
834        entity_type,
835        fields,
836    })
837}
838
839/// Parse policy declaration
840fn parse_policy(pair: Pair<Rule>) -> ParseResult<AstNode> {
841    let mut inner = pair.into_inner();
842
843    let name = parse_identifier(
844        inner
845            .next()
846            .ok_or_else(|| ParseError::GrammarError("Expected policy name".to_string()))?,
847    )?;
848
849    let mut metadata = PolicyMetadata {
850        kind: None,
851        modality: None,
852        priority: None,
853        rationale: None,
854        tags: Vec::new(),
855    };
856    let mut version: Option<String> = None;
857
858    for next_pair in inner {
859        match next_pair.as_rule() {
860            Rule::policy_kind => {
861                metadata.kind = Some(match next_pair.as_str().to_lowercase().as_str() {
862                    "constraint" => PolicyKind::Constraint,
863                    "derivation" => PolicyKind::Derivation,
864                    "obligation" => PolicyKind::Obligation,
865                    _ => {
866                        return Err(ParseError::GrammarError(format!(
867                            "Unknown policy kind: {}",
868                            next_pair.as_str()
869                        )))
870                    }
871                });
872            }
873            Rule::policy_modality => {
874                metadata.modality = Some(match next_pair.as_str().to_lowercase().as_str() {
875                    "obligation" => PolicyModality::Obligation,
876                    "prohibition" => PolicyModality::Prohibition,
877                    "permission" => PolicyModality::Permission,
878                    _ => {
879                        return Err(ParseError::GrammarError(format!(
880                            "Unknown policy modality: {}",
881                            next_pair.as_str()
882                        )))
883                    }
884                });
885            }
886            Rule::number => {
887                metadata.priority = Some(parse_number(next_pair)?);
888            }
889            Rule::policy_annotation => {
890                parse_policy_annotation(next_pair, &mut metadata)?;
891            }
892            Rule::version => {
893                version = Some(next_pair.as_str().to_string());
894            }
895            Rule::expression => {
896                let expression = parse_expression(next_pair)?;
897                return Ok(AstNode::Policy {
898                    name,
899                    version,
900                    metadata,
901                    expression,
902                });
903            }
904            _ => {}
905        }
906    }
907
908    Err(ParseError::GrammarError(
909        "Policy missing expression".to_string(),
910    ))
911}
912
913fn parse_policy_annotation(pair: Pair<Rule>, metadata: &mut PolicyMetadata) -> ParseResult<()> {
914    let mut inner = pair.into_inner();
915
916    let name = inner
917        .next()
918        .ok_or_else(|| ParseError::GrammarError("Expected annotation name".to_string()))?;
919    let value = inner
920        .next()
921        .ok_or_else(|| ParseError::GrammarError("Expected annotation value".to_string()))?;
922
923    let name_str = name.as_str().to_lowercase();
924
925    match name_str.as_str() {
926        "rationale" => {
927            metadata.rationale = Some(parse_string_literal(value)?);
928        }
929        "tags" => {
930            if value.as_rule() == Rule::string_array {
931                for tag_pair in value.into_inner() {
932                    if tag_pair.as_rule() == Rule::string_literal {
933                        metadata.tags.push(parse_string_literal(tag_pair)?);
934                    }
935                }
936            } else {
937                metadata.tags.push(parse_string_literal(value)?);
938            }
939        }
940        _ => {
941            return Err(ParseError::GrammarError(format!(
942                "Unknown policy annotation: {}",
943                name_str
944            )))
945        }
946    }
947
948    Ok(())
949}
950
951/// Parse expression
952fn parse_expression(pair: Pair<Rule>) -> ParseResult<Expression> {
953    match pair.as_rule() {
954        Rule::expression => {
955            let inner = pair
956                .into_inner()
957                .next()
958                .ok_or_else(|| ParseError::GrammarError("Empty expression".to_string()))?;
959            parse_expression(inner)
960        }
961        Rule::or_expr => parse_or_expr(pair),
962        Rule::and_expr => parse_and_expr(pair),
963        Rule::not_expr => parse_not_expr(pair),
964        Rule::comparison_expr => parse_comparison_expr(pair),
965        Rule::additive_expr => parse_additive_expr(pair),
966        Rule::multiplicative_expr => parse_multiplicative_expr(pair),
967        Rule::unary_expr => parse_unary_expr(pair),
968        Rule::cast_expr => parse_cast_expr(pair),
969        Rule::primary_expr => parse_primary_expr(pair),
970        _ => Err(ParseError::InvalidExpression(format!(
971            "Unexpected expression rule: {:?}",
972            pair.as_rule()
973        ))),
974    }
975}
976
977/// Parse a single expression string into an Expression AST node.
978pub fn parse_expression_from_str(source: &str) -> ParseResult<Expression> {
979    let pairs = SeaParser::parse(Rule::expression, source)
980        .map_err(|e| ParseError::GrammarError(format!("Parse error: {}", e)))?;
981    let parsed_pairs: Vec<_> = pairs.collect();
982
983    if parsed_pairs.is_empty() {
984        return Err(ParseError::GrammarError("Empty expression".to_string()));
985    }
986    if parsed_pairs.len() > 1 {
987        return Err(ParseError::GrammarError(
988            "Trailing input detected after expression".to_string(),
989        ));
990    }
991
992    let pair = parsed_pairs.into_iter().next().unwrap();
993
994    // Check that the entire input was consumed (no trailing characters)
995    let consumed = pair.as_span().end();
996    let trimmed_source = source.trim_end();
997    if consumed < trimmed_source.len() {
998        return Err(ParseError::GrammarError(format!(
999            "Trailing input after expression: '{}'",
1000            &source[consumed..]
1001        )));
1002    }
1003
1004    parse_expression(pair)
1005}
1006
1007/// Parse OR expression
1008fn parse_or_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1009    let mut inner = pair.into_inner();
1010    let mut left =
1011        parse_expression(inner.next().ok_or_else(|| {
1012            ParseError::GrammarError("Expected left expression in OR".to_string())
1013        })?)?;
1014
1015    for right_pair in inner {
1016        let right = parse_expression(right_pair)?;
1017        left = Expression::Binary {
1018            left: Box::new(left),
1019            op: BinaryOp::Or,
1020            right: Box::new(right),
1021        };
1022    }
1023
1024    Ok(left)
1025}
1026
1027/// Parse AND expression
1028fn parse_and_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1029    let mut inner = pair.into_inner();
1030    let mut left =
1031        parse_expression(inner.next().ok_or_else(|| {
1032            ParseError::GrammarError("Expected left expression in AND".to_string())
1033        })?)?;
1034
1035    for right_pair in inner {
1036        let right = parse_expression(right_pair)?;
1037        left = Expression::Binary {
1038            left: Box::new(left),
1039            op: BinaryOp::And,
1040            right: Box::new(right),
1041        };
1042    }
1043
1044    Ok(left)
1045}
1046
1047/// Parse NOT expression
1048fn parse_not_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1049    let mut inner = pair.into_inner();
1050    let first = inner
1051        .next()
1052        .ok_or_else(|| ParseError::GrammarError("Expected expression in NOT".to_string()))?;
1053
1054    // Check if this is actually a NOT expression or just a comparison_expr
1055    if first.as_rule() == Rule::not_expr {
1056        // This is a recursive NOT, parse it
1057        let expr = parse_expression(first)?;
1058        Ok(Expression::Unary {
1059            op: UnaryOp::Not,
1060            operand: Box::new(expr),
1061        })
1062    } else {
1063        // This is just a comparison_expr, parse it directly
1064        parse_expression(first)
1065    }
1066}
1067
1068/// Parse comparison expression
1069fn parse_comparison_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1070    let mut inner = pair.into_inner();
1071    let mut left = parse_expression(inner.next().ok_or_else(|| {
1072        ParseError::GrammarError("Expected left expression in comparison".to_string())
1073    })?)?;
1074
1075    if let Some(op_pair) = inner.next() {
1076        let op = parse_comparison_op(op_pair)?;
1077        let right = parse_expression(inner.next().ok_or_else(|| {
1078            ParseError::GrammarError("Expected right expression in comparison".to_string())
1079        })?)?;
1080        left = Expression::Binary {
1081            left: Box::new(left),
1082            op,
1083            right: Box::new(right),
1084        };
1085    }
1086
1087    Ok(left)
1088}
1089
1090/// Parse comparison operator
1091fn parse_comparison_op(pair: Pair<Rule>) -> ParseResult<BinaryOp> {
1092    let op_str = pair.as_str();
1093    match op_str {
1094        "=" => Ok(BinaryOp::Equal),
1095        "!=" => Ok(BinaryOp::NotEqual),
1096        ">" => Ok(BinaryOp::GreaterThan),
1097        "<" => Ok(BinaryOp::LessThan),
1098        ">=" => Ok(BinaryOp::GreaterThanOrEqual),
1099        "<=" => Ok(BinaryOp::LessThanOrEqual),
1100        _ if op_str.eq_ignore_ascii_case("contains") => Ok(BinaryOp::Contains),
1101        _ if op_str.eq_ignore_ascii_case("startswith") => Ok(BinaryOp::StartsWith),
1102        _ if op_str.eq_ignore_ascii_case("endswith") => Ok(BinaryOp::EndsWith),
1103        _ if op_str.eq_ignore_ascii_case("matches") => Ok(BinaryOp::Matches),
1104        _ if op_str.eq_ignore_ascii_case("before") => Ok(BinaryOp::Before),
1105        _ if op_str.eq_ignore_ascii_case("after") => Ok(BinaryOp::After),
1106        _ if op_str.eq_ignore_ascii_case("during") => Ok(BinaryOp::During),
1107        _ if op_str.eq_ignore_ascii_case("has_role") => Ok(BinaryOp::HasRole),
1108        _ => Err(ParseError::InvalidExpression(format!(
1109            "Unknown comparison operator: {}",
1110            op_str
1111        ))),
1112    }
1113}
1114
1115/// Parse additive expression
1116fn parse_additive_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1117    let mut inner = pair.into_inner();
1118    let mut left = parse_expression(inner.next().ok_or_else(|| {
1119        ParseError::GrammarError("Expected left expression in additive".to_string())
1120    })?)?;
1121
1122    while let Some(op_pair) = inner.next() {
1123        let op = match op_pair.as_str() {
1124            "+" => BinaryOp::Plus,
1125            "-" => BinaryOp::Minus,
1126            _ => {
1127                return Err(ParseError::InvalidExpression(
1128                    "Invalid additive operator".to_string(),
1129                ))
1130            }
1131        };
1132        let right = parse_expression(inner.next().ok_or_else(|| {
1133            ParseError::GrammarError("Expected right expression in additive".to_string())
1134        })?)?;
1135        left = Expression::Binary {
1136            left: Box::new(left),
1137            op,
1138            right: Box::new(right),
1139        };
1140    }
1141
1142    Ok(left)
1143}
1144
1145/// Parse multiplicative expression
1146fn parse_multiplicative_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1147    let mut inner = pair.into_inner();
1148    let mut left = parse_expression(inner.next().ok_or_else(|| {
1149        ParseError::GrammarError("Expected left expression in multiplicative".to_string())
1150    })?)?;
1151
1152    while let Some(op_pair) = inner.next() {
1153        let op = match op_pair.as_str() {
1154            "*" => BinaryOp::Multiply,
1155            "/" => BinaryOp::Divide,
1156            _ => {
1157                return Err(ParseError::InvalidExpression(
1158                    "Invalid multiplicative operator".to_string(),
1159                ))
1160            }
1161        };
1162        let right = parse_expression(inner.next().ok_or_else(|| {
1163            ParseError::GrammarError("Expected right expression in multiplicative".to_string())
1164        })?)?;
1165        left = Expression::Binary {
1166            left: Box::new(left),
1167            op,
1168            right: Box::new(right),
1169        };
1170    }
1171
1172    Ok(left)
1173}
1174
1175/// Parse cast expression
1176fn parse_cast_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1177    let mut inner = pair.into_inner();
1178    let primary = parse_expression(inner.next().ok_or_else(|| {
1179        ParseError::GrammarError("Expected primary expression in cast".to_string())
1180    })?)?;
1181
1182    if let Some(as_pair) = inner.next() {
1183        let target_type = parse_string_literal(as_pair)?;
1184        Ok(Expression::cast(primary, target_type))
1185    } else {
1186        Ok(primary)
1187    }
1188}
1189
1190/// Parse unary expression
1191fn parse_unary_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1192    let mut inner = pair.into_inner();
1193    let first = inner
1194        .next()
1195        .ok_or_else(|| ParseError::GrammarError("Expected expression in unary".to_string()))?;
1196
1197    if first.as_str() == "-" {
1198        // Unary minus
1199        let expr = parse_expression(inner.next().ok_or_else(|| {
1200            ParseError::GrammarError("Expected expression after unary minus".to_string())
1201        })?)?;
1202        Ok(Expression::Unary {
1203            op: UnaryOp::Negate,
1204            operand: Box::new(expr),
1205        })
1206    } else {
1207        parse_expression(first)
1208    }
1209}
1210
1211/// Parse primary expression
1212fn parse_primary_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1213    let inner = pair.into_inner().next().ok_or_else(|| {
1214        ParseError::GrammarError("Expected inner expression in primary".to_string())
1215    })?;
1216
1217    match inner.as_rule() {
1218        Rule::expression => parse_expression(inner),
1219        Rule::group_by_expr => parse_group_by_expr(inner),
1220        Rule::aggregation_expr => parse_aggregation_expr(inner),
1221        Rule::quantified_expr => parse_quantified_expr(inner),
1222        Rule::member_access => parse_member_access(inner),
1223        Rule::literal => parse_literal_expr(inner),
1224        Rule::identifier => {
1225            let name = parse_identifier(inner)?;
1226            Ok(Expression::Variable(name))
1227        }
1228        _ => Err(ParseError::InvalidExpression(format!(
1229            "Unexpected primary expression: {:?}",
1230            inner.as_rule()
1231        ))),
1232    }
1233}
1234
1235/// Parse aggregation expression
1236fn parse_aggregation_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1237    let mut inner = pair.into_inner();
1238
1239    let function_pair = inner.next().ok_or_else(|| {
1240        ParseError::GrammarError(
1241            "Expected aggregate function in aggregation expression".to_string(),
1242        )
1243    })?;
1244    let function = parse_aggregate_fn(function_pair)?;
1245
1246    let collection_pair = inner.next().ok_or_else(|| {
1247        ParseError::GrammarError("Expected collection in aggregation expression".to_string())
1248    })?;
1249
1250    // Aggregation can be a simple form (e.g., sum(flows), sum(flows.quantity))
1251    // or the comprehension form (e.g., sum(f in flows where f.resource = "Money": f.quantity as "USD")).
1252    if collection_pair.as_rule() == Rule::aggregation_comprehension {
1253        // Parse aggregation comprehension
1254        let mut comp_inner = collection_pair.into_inner();
1255        let variable_pair = comp_inner.next().ok_or_else(|| {
1256            ParseError::GrammarError("Expected variable in aggregation comprehension".to_string())
1257        })?;
1258        let variable = parse_identifier(variable_pair)?;
1259        // Next token should be collection
1260        let collection_token = comp_inner.next().ok_or_else(|| {
1261            ParseError::GrammarError("Expected collection in aggregation comprehension".to_string())
1262        })?;
1263        let collection_name = parse_collection(collection_token)?;
1264        let collection = Box::new(Expression::Variable(collection_name));
1265
1266        let mut next_pair = comp_inner.next().ok_or_else(|| {
1267            ParseError::GrammarError(
1268                "Expected predicate expression, projection, or window in aggregation comprehension"
1269                    .to_string(),
1270            )
1271        })?;
1272
1273        let mut window = None;
1274        if next_pair.as_rule() == Rule::window_clause {
1275            window = Some(parse_window_clause(next_pair)?);
1276            next_pair = comp_inner.next().ok_or_else(|| {
1277                ParseError::GrammarError(
1278                    "Expected predicate or projection expression in aggregation comprehension"
1279                        .to_string(),
1280                )
1281            })?;
1282        }
1283
1284        let remaining_pairs: Vec<Pair<Rule>> =
1285            std::iter::once(next_pair).chain(comp_inner).collect();
1286
1287        let mut expr_pairs: Vec<Pair<Rule>> = Vec::new();
1288        let mut target_unit: Option<String> = None;
1289        for pair in remaining_pairs {
1290            match pair.as_rule() {
1291                Rule::expression => expr_pairs.push(pair),
1292                Rule::string_literal => {
1293                    target_unit = Some(parse_string_literal(pair)?);
1294                }
1295                Rule::identifier if pair.as_str().eq_ignore_ascii_case("as") => {
1296                    // skip explicit AS token
1297                }
1298                other => {
1299                    return Err(ParseError::GrammarError(format!(
1300                        "Unexpected token {:?} in aggregation comprehension",
1301                        other
1302                    )))
1303                }
1304            }
1305        }
1306
1307        let (predicate, projection) = match expr_pairs.len() {
1308            2 => {
1309                let mut expr_iter = expr_pairs.into_iter();
1310                let predicate_expr = parse_expression(expr_iter.next().ok_or_else(|| {
1311                    ParseError::GrammarError(
1312                        "Expected predicate expression in aggregation comprehension".to_string(),
1313                    )
1314                })?)?;
1315                let projection_expr = parse_expression(expr_iter.next().ok_or_else(|| {
1316                    ParseError::GrammarError(
1317                        "Expected projection expression in aggregation comprehension".to_string(),
1318                    )
1319                })?)?;
1320                (predicate_expr, projection_expr)
1321            }
1322            1 => {
1323                let projection_expr =
1324                    parse_expression(expr_pairs.into_iter().next().ok_or_else(|| {
1325                        ParseError::GrammarError(
1326                            "Expected projection expression in aggregation comprehension"
1327                                .to_string(),
1328                        )
1329                    })?)?;
1330                (Expression::Literal(JsonValue::Bool(true)), projection_expr)
1331            }
1332            other => {
1333                return Err(ParseError::GrammarError(format!(
1334                    "Unexpected number of expressions in aggregation comprehension: {}",
1335                    other
1336                )))
1337            }
1338        };
1339
1340        return Ok(Expression::AggregationComprehension {
1341            function,
1342            variable,
1343            collection,
1344            window,
1345            predicate: Box::new(predicate),
1346            projection: Box::new(projection),
1347            target_unit,
1348        });
1349    }
1350
1351    // Parse aggregation_simple
1352    let mut simple_inner = collection_pair.into_inner();
1353
1354    // First item is either collection or identifier
1355    let first_pair = simple_inner.next().ok_or_else(|| {
1356        ParseError::GrammarError(
1357            "Expected collection or identifier in aggregation_simple".to_string(),
1358        )
1359    })?;
1360
1361    let collection = match first_pair.as_rule() {
1362        Rule::collection => parse_collection(first_pair)?,
1363        Rule::identifier => parse_identifier(first_pair)?,
1364        _ => {
1365            return Err(ParseError::GrammarError(format!(
1366                "Expected collection or identifier, got {:?}",
1367                first_pair.as_rule()
1368            )))
1369        }
1370    };
1371
1372    let mut field: Option<String> = None;
1373    let mut filter: Option<Expression> = None;
1374
1375    // Parse optional field and filter
1376    for item in simple_inner {
1377        match item.as_rule() {
1378            Rule::identifier => {
1379                field = Some(parse_identifier(item)?);
1380            }
1381            Rule::expression => {
1382                filter = Some(parse_expression(item)?);
1383            }
1384            _ => {}
1385        }
1386    }
1387
1388    Ok(Expression::aggregation(
1389        function,
1390        Expression::Variable(collection),
1391        field,
1392        filter,
1393    ))
1394}
1395
1396/// Parse aggregate function
1397fn parse_aggregate_fn(pair: Pair<Rule>) -> ParseResult<AggregateFunction> {
1398    let fn_str = pair.as_str();
1399    match fn_str.to_lowercase().as_str() {
1400        "count" => Ok(AggregateFunction::Count),
1401        "sum" => Ok(AggregateFunction::Sum),
1402        "min" => Ok(AggregateFunction::Min),
1403        "max" => Ok(AggregateFunction::Max),
1404        "avg" => Ok(AggregateFunction::Avg),
1405        _ => Err(ParseError::InvalidExpression(format!(
1406            "Unknown aggregate function: {}",
1407            fn_str
1408        ))),
1409    }
1410}
1411
1412/// Parse quantified expression
1413fn parse_quantified_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1414    let mut inner = pair.into_inner();
1415
1416    let quantifier = parse_quantifier(inner.next().ok_or_else(|| {
1417        ParseError::GrammarError("Expected quantifier in quantified expression".to_string())
1418    })?)?;
1419    let variable = parse_identifier(inner.next().ok_or_else(|| {
1420        ParseError::GrammarError(
1421            "Expected variable identifier in quantified expression".to_string(),
1422        )
1423    })?)?;
1424    let collection = parse_collection(inner.next().ok_or_else(|| {
1425        ParseError::GrammarError(
1426            "Expected collection identifier in quantified expression".to_string(),
1427        )
1428    })?)?;
1429    let condition = parse_expression(inner.next().ok_or_else(|| {
1430        ParseError::GrammarError("Expected quantified condition expression".to_string())
1431    })?)?;
1432
1433    Ok(Expression::Quantifier {
1434        quantifier,
1435        variable,
1436        collection: Box::new(Expression::Variable(collection)),
1437        condition: Box::new(condition),
1438    })
1439}
1440
1441/// Parse quantifier
1442fn parse_quantifier(pair: Pair<Rule>) -> ParseResult<PolicyQuantifier> {
1443    let q_str = pair.as_str();
1444    match q_str.to_lowercase().as_str() {
1445        "forall" => Ok(PolicyQuantifier::ForAll),
1446        "exists" => Ok(PolicyQuantifier::Exists),
1447        "exists_unique" => Ok(PolicyQuantifier::ExistsUnique),
1448        _ => Err(ParseError::InvalidExpression(format!(
1449            "Unknown quantifier: {}",
1450            q_str
1451        ))),
1452    }
1453}
1454
1455/// Parse collection type
1456fn parse_collection(pair: Pair<Rule>) -> ParseResult<String> {
1457    Ok(pair.as_str().to_lowercase())
1458}
1459
1460/// Parse member access
1461fn parse_member_access(pair: Pair<Rule>) -> ParseResult<Expression> {
1462    let mut inner = pair.into_inner();
1463    let object = parse_identifier(inner.next().ok_or_else(|| {
1464        ParseError::GrammarError("Expected object identifier in member access".to_string())
1465    })?)?;
1466    let member = parse_identifier(inner.next().ok_or_else(|| {
1467        ParseError::GrammarError("Expected member identifier in member access".to_string())
1468    })?)?;
1469
1470    Ok(Expression::MemberAccess { object, member })
1471}
1472
1473/// Parse literal expression
1474fn parse_literal_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1475    let inner = pair
1476        .into_inner()
1477        .next()
1478        .ok_or_else(|| ParseError::GrammarError("Expected literal content".to_string()))?;
1479
1480    match inner.as_rule() {
1481        Rule::string_literal => {
1482            let s = parse_string_literal(inner)?;
1483            Ok(Expression::Literal(JsonValue::String(s)))
1484        }
1485        Rule::multiline_string => {
1486            let s = parse_multiline_string(inner)?;
1487            Ok(Expression::Literal(JsonValue::String(s)))
1488        }
1489        Rule::quantity_literal => {
1490            let mut parts = inner.into_inner();
1491            let number_part = parts.next().ok_or_else(|| {
1492                ParseError::GrammarError("Expected number in quantity literal".to_string())
1493            })?;
1494            let unit_part = parts.next().ok_or_else(|| {
1495                ParseError::GrammarError("Expected unit string in quantity literal".to_string())
1496            })?;
1497            let value = parse_decimal(number_part)?;
1498            let unit = parse_string_literal(unit_part)?;
1499            Ok(Expression::QuantityLiteral { value, unit })
1500        }
1501        Rule::time_literal => {
1502            // Parse ISO 8601 timestamp (already includes quotes in grammar)
1503            let timestamp = inner.as_str();
1504            // Remove surrounding quotes
1505            let timestamp = timestamp.trim_start_matches('"').trim_end_matches('"');
1506            Ok(Expression::TimeLiteral(timestamp.to_string()))
1507        }
1508        Rule::interval_literal => {
1509            // Parse interval("start", "end")
1510            let mut parts = inner.into_inner();
1511            let start_part = parts.next().ok_or_else(|| {
1512                ParseError::GrammarError("Expected start time in interval literal".to_string())
1513            })?;
1514            let end_part = parts.next().ok_or_else(|| {
1515                ParseError::GrammarError("Expected end time in interval literal".to_string())
1516            })?;
1517            let start = parse_string_literal(start_part)?;
1518            let end = parse_string_literal(end_part)?;
1519            Ok(Expression::IntervalLiteral { start, end })
1520        }
1521        Rule::number => {
1522            let n = parse_decimal(inner)?;
1523            // Convert Decimal to f64 for JSON Number representation
1524            let f = n.to_f64().ok_or_else(|| {
1525                ParseError::InvalidQuantity(format!(
1526                    "Decimal value {} cannot be represented as f64",
1527                    n
1528                ))
1529            })?;
1530            // Ensure the value is finite
1531            if !f.is_finite() {
1532                return Err(ParseError::InvalidQuantity(format!(
1533                    "Decimal value {} converts to non-finite f64: {}",
1534                    n, f
1535                )));
1536            }
1537            let num = serde_json::Number::from_f64(f).ok_or_else(|| {
1538                ParseError::InvalidQuantity(format!(
1539                    "Cannot create JSON Number from f64 value: {}",
1540                    f
1541                ))
1542            })?;
1543            Ok(Expression::Literal(JsonValue::Number(num)))
1544        }
1545        Rule::boolean => {
1546            let b = inner.as_str().eq_ignore_ascii_case("true");
1547            Ok(Expression::Literal(JsonValue::Bool(b)))
1548        }
1549        _ => Err(ParseError::InvalidExpression(format!(
1550            "Unknown literal type: {:?}",
1551            inner.as_rule()
1552        ))),
1553    }
1554}
1555
1556/// Parse name (handles both string_literal and multiline_string)
1557fn parse_name(pair: Pair<Rule>) -> ParseResult<String> {
1558    let inner = pair.into_inner().next().ok_or_else(|| {
1559        ParseError::GrammarError("Expected inner token for name but got empty pair".to_string())
1560    })?;
1561    match inner.as_rule() {
1562        Rule::string_literal => parse_string_literal(inner),
1563        Rule::multiline_string => parse_multiline_string(inner),
1564        _ => Err(ParseError::GrammarError(format!(
1565            "Expected string or multiline string for name, got {:?}",
1566            inner.as_rule()
1567        ))),
1568    }
1569}
1570
1571/// Parse string literal (handles escape sequences)
1572fn parse_string_literal(pair: Pair<Rule>) -> ParseResult<String> {
1573    let s = pair.as_str();
1574    if s.len() < 2 || !s.starts_with('"') || !s.ends_with('"') {
1575        return Err(ParseError::GrammarError(format!(
1576            "Invalid string literal: {}",
1577            s
1578        )));
1579    }
1580
1581    // Use serde_json to properly parse and unescape the string
1582    // The string already has quotes, so pass it directly
1583    match serde_json::from_str(s) {
1584        Ok(unescaped) => Ok(unescaped),
1585        Err(e) => Err(ParseError::GrammarError(format!(
1586            "Invalid string literal escape sequences: {} - {}",
1587            s, e
1588        ))),
1589    }
1590}
1591
1592/// Parse multiline string (removes triple quotes and handles escape sequences)
1593fn parse_multiline_string(pair: Pair<Rule>) -> ParseResult<String> {
1594    let s = pair.as_str();
1595    if s.len() < 6 || !s.starts_with("\"\"\"") || !s.ends_with("\"\"\"") {
1596        return Err(ParseError::GrammarError(format!(
1597            "Invalid multiline string: {}",
1598            s
1599        )));
1600    }
1601
1602    let content = &s[3..s.len() - 3];
1603
1604    // Escape special characters for JSON compatibility
1605    let escaped = content
1606        .replace('\\', "\\\\") // Backslash must be first
1607        .replace('"', "\\\"") // Double quotes
1608        .replace('\n', "\\n") // Newlines
1609        .replace('\r', "\\r") // Carriage returns
1610        .replace('\t', "\\t"); // Tabs
1611
1612    // Create a JSON string and parse it to handle escape sequences
1613    let json_string = format!("\"{}\"", escaped);
1614    match serde_json::from_str(&json_string) {
1615        Ok(unescaped) => Ok(unescaped),
1616        Err(e) => Err(ParseError::GrammarError(format!(
1617            "Invalid multiline string escape sequences in '{}': {}",
1618            s, e
1619        ))),
1620    }
1621}
1622
1623/// Parse identifier
1624fn parse_identifier(pair: Pair<Rule>) -> ParseResult<String> {
1625    Ok(pair.as_str().to_string())
1626}
1627
1628/// Parse semantic version (validated by grammar)
1629fn parse_version(pair: Pair<Rule>) -> ParseResult<String> {
1630    Ok(pair.as_str().to_string())
1631}
1632
1633/// Parse number as i32
1634fn parse_number(pair: Pair<Rule>) -> ParseResult<i32> {
1635    pair.as_str()
1636        .parse()
1637        .map_err(|_| ParseError::InvalidQuantity(format!("Invalid number: {}", pair.as_str())))
1638}
1639
1640/// Parse number as Decimal
1641fn parse_decimal(pair: Pair<Rule>) -> ParseResult<Decimal> {
1642    pair.as_str()
1643        .parse()
1644        .map_err(|_| ParseError::InvalidQuantity(format!("Invalid decimal: {}", pair.as_str())))
1645}
1646
1647/// Parse group_by expression
1648fn parse_group_by_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1649    let mut inner = pair.into_inner();
1650
1651    let variable_pair = inner
1652        .next()
1653        .ok_or_else(|| ParseError::GrammarError("Expected variable in group_by".to_string()))?;
1654    let variable = parse_identifier(variable_pair)?;
1655
1656    let collection_pair = inner
1657        .next()
1658        .ok_or_else(|| ParseError::GrammarError("Expected collection in group_by".to_string()))?;
1659    let collection_name = parse_collection(collection_pair)?;
1660    let collection = Box::new(Expression::Variable(collection_name));
1661
1662    let next_pair = inner.next().ok_or_else(|| {
1663        ParseError::GrammarError("Expected key or where clause in group_by".to_string())
1664    })?;
1665
1666    // Collect remaining pairs to determine structure without cloning
1667    let remaining: Vec<Pair<Rule>> = std::iter::once(next_pair).chain(inner).collect();
1668
1669    let (filter_expr, key_expr, condition_expr) = match remaining.len() {
1670        3 => {
1671            let mut iter = remaining.into_iter();
1672            let filter = parse_expression(iter.next().ok_or_else(|| {
1673                ParseError::GrammarError("Expected filter expression in group_by".to_string())
1674            })?)?;
1675            let key = parse_expression(iter.next().ok_or_else(|| {
1676                ParseError::GrammarError("Expected key expression in group_by".to_string())
1677            })?)?;
1678            let condition = parse_expression(iter.next().ok_or_else(|| {
1679                ParseError::GrammarError("Expected condition expression in group_by".to_string())
1680            })?)?;
1681            (Some(filter), key, condition)
1682        }
1683        2 => {
1684            let mut iter = remaining.into_iter();
1685            let key = parse_expression(iter.next().ok_or_else(|| {
1686                ParseError::GrammarError("Expected key expression in group_by".to_string())
1687            })?)?;
1688            let condition = parse_expression(iter.next().ok_or_else(|| {
1689                ParseError::GrammarError("Expected condition expression in group_by".to_string())
1690            })?)?;
1691            (None, key, condition)
1692        }
1693        other => {
1694            return Err(ParseError::GrammarError(format!(
1695                "Unexpected number of expressions in group_by: {}",
1696                other
1697            )))
1698        }
1699    };
1700
1701    Ok(Expression::GroupBy {
1702        variable,
1703        collection,
1704        filter: filter_expr.map(Box::new),
1705        key: Box::new(key_expr),
1706        condition: Box::new(condition_expr),
1707    })
1708}
1709
1710/// Parse window clause
1711fn parse_window_clause(pair: Pair<Rule>) -> ParseResult<WindowSpec> {
1712    let mut inner = pair.into_inner();
1713
1714    let duration_pair = inner.next().ok_or_else(|| {
1715        ParseError::GrammarError("Expected duration in window clause".to_string())
1716    })?;
1717    let duration_i32 = parse_number(duration_pair)?;
1718    if duration_i32 < 0 {
1719        return Err(ParseError::InvalidQuantity(
1720            "Window duration must be non-negative".to_string(),
1721        ));
1722    }
1723    let duration = duration_i32 as u64;
1724
1725    let unit_pair = inner
1726        .next()
1727        .ok_or_else(|| ParseError::GrammarError("Expected unit in window clause".to_string()))?;
1728    let unit = parse_string_literal(unit_pair)?;
1729
1730    Ok(WindowSpec { duration, unit })
1731}
1732
1733fn expression_kind(expr: &Expression) -> &'static str {
1734    match expr {
1735        Expression::Literal(_) => "literal",
1736        Expression::QuantityLiteral { .. } => "quantity_literal",
1737        Expression::TimeLiteral(_) => "time_literal",
1738        Expression::IntervalLiteral { .. } => "interval_literal",
1739        Expression::Variable(_) => "variable",
1740        Expression::GroupBy { .. } => "group_by",
1741        Expression::Binary { .. } => "binary",
1742        Expression::Unary { .. } => "unary",
1743        Expression::Cast { .. } => "cast",
1744        Expression::Quantifier { .. } => "quantifier",
1745        Expression::MemberAccess { .. } => "member_access",
1746        Expression::Aggregation { .. } => "aggregation",
1747        Expression::AggregationComprehension { .. } => "aggregation_comprehension",
1748    }
1749}
1750
1751/// Convert an Expression to a JSON Value for instance fields
1752fn expression_to_json(expr: &Expression) -> ParseResult<JsonValue> {
1753    match expr {
1754        Expression::Literal(v) => Ok(v.clone()),
1755        Expression::Variable(name) => Ok(JsonValue::String(name.clone())),
1756        Expression::QuantityLiteral { value, unit } => Ok(json!({
1757            "value": value.to_string(),
1758            "unit": unit
1759        })),
1760        Expression::TimeLiteral(timestamp) => Ok(JsonValue::String(timestamp.clone())),
1761        _ => Err(ParseError::UnsupportedExpression {
1762            kind: expression_kind(expr).to_string(),
1763            span: None,
1764        }),
1765    }
1766}
1767
1768/// Parse mapping declaration
1769fn parse_mapping(pair: Pair<Rule>) -> ParseResult<AstNode> {
1770    let mut inner = pair.into_inner();
1771
1772    let name = parse_string_literal(
1773        inner
1774            .next()
1775            .ok_or_else(|| ParseError::GrammarError("Expected mapping name".to_string()))?,
1776    )?;
1777
1778    let target_pair = inner
1779        .next()
1780        .ok_or_else(|| ParseError::GrammarError("Expected target format".to_string()))?;
1781    let target = parse_target_format(target_pair)?;
1782
1783    let mut rules = Vec::new();
1784
1785    for rule_pair in inner {
1786        if rule_pair.as_rule() == Rule::mapping_rule {
1787            rules.push(parse_mapping_rule(rule_pair)?);
1788        }
1789    }
1790
1791    Ok(AstNode::MappingDecl {
1792        name,
1793        target,
1794        rules,
1795    })
1796}
1797
1798fn parse_target_format(pair: Pair<Rule>) -> ParseResult<TargetFormat> {
1799    match pair.as_str().to_lowercase().as_str() {
1800        "calm" => Ok(TargetFormat::Calm),
1801        "kg" => Ok(TargetFormat::Kg),
1802        "sbvr" => Ok(TargetFormat::Sbvr),
1803        "protobuf" | "proto" => Ok(TargetFormat::Protobuf),
1804        _ => Err(ParseError::GrammarError(format!(
1805            "Unknown target format: {}",
1806            pair.as_str()
1807        ))),
1808    }
1809}
1810
1811fn parse_mapping_rule(pair: Pair<Rule>) -> ParseResult<MappingRule> {
1812    let mut inner = pair.into_inner();
1813
1814    let primitive_type = inner
1815        .next()
1816        .ok_or_else(|| ParseError::GrammarError("Expected primitive type".to_string()))?
1817        .as_str()
1818        .to_string();
1819
1820    let primitive_name = parse_string_literal(
1821        inner
1822            .next()
1823            .ok_or_else(|| ParseError::GrammarError("Expected primitive name".to_string()))?,
1824    )?;
1825
1826    let target_structure = inner
1827        .next()
1828        .ok_or_else(|| ParseError::GrammarError("Expected target structure".to_string()))?;
1829
1830    let mut target_inner = target_structure.into_inner();
1831    let target_type = parse_identifier(
1832        target_inner
1833            .next()
1834            .ok_or_else(|| ParseError::GrammarError("Expected target type".to_string()))?,
1835    )?;
1836
1837    let mut fields = HashMap::new();
1838    for field_pair in target_inner {
1839        if field_pair.as_rule() == Rule::mapping_field {
1840            let mut field_inner = field_pair.into_inner();
1841            let key = parse_identifier(
1842                field_inner
1843                    .next()
1844                    .ok_or_else(|| ParseError::GrammarError("Expected field key".to_string()))?,
1845            )?;
1846            let value_pair = field_inner
1847                .next()
1848                .ok_or_else(|| ParseError::GrammarError("Expected field value".to_string()))?;
1849
1850            let value = match value_pair.as_rule() {
1851                Rule::string_literal => JsonValue::String(parse_string_literal(value_pair)?),
1852                Rule::boolean => JsonValue::Bool(value_pair.as_str().eq_ignore_ascii_case("true")),
1853                Rule::object_literal => parse_object_literal(value_pair)?,
1854                _ => {
1855                    return Err(ParseError::GrammarError(
1856                        "Unexpected mapping field value".to_string(),
1857                    ))
1858                }
1859            };
1860            fields.insert(key, value);
1861        }
1862    }
1863
1864    Ok(MappingRule {
1865        primitive_type,
1866        primitive_name,
1867        target_type,
1868        fields,
1869    })
1870}
1871
1872fn parse_object_literal(pair: Pair<Rule>) -> ParseResult<JsonValue> {
1873    let mut map = serde_json::Map::new();
1874    let mut inner = pair.into_inner();
1875    while let Some(key_pair) = inner.next() {
1876        let key = parse_string_literal(key_pair)?;
1877        let value_pair = inner.next().ok_or_else(|| {
1878            ParseError::GrammarError("Expected value in object literal".to_string())
1879        })?;
1880        let value = match value_pair.as_rule() {
1881            Rule::string_literal => JsonValue::String(parse_string_literal(value_pair)?),
1882            Rule::boolean => JsonValue::Bool(value_pair.as_str().eq_ignore_ascii_case("true")),
1883            Rule::number => {
1884                let d = parse_decimal(value_pair)?;
1885                // Parse the decimal string as f64 to create a JSON Number
1886                let f = d.to_f64().ok_or_else(|| {
1887                    ParseError::InvalidQuantity(format!(
1888                        "Decimal value {} cannot be represented as f64",
1889                        d
1890                    ))
1891                })?;
1892                if !f.is_finite() {
1893                    return Err(ParseError::InvalidQuantity(format!(
1894                        "Decimal value {} converts to non-finite f64",
1895                        d
1896                    )));
1897                }
1898                let num = serde_json::Number::from_f64(f).ok_or_else(|| {
1899                    ParseError::InvalidQuantity(format!(
1900                        "Cannot create JSON Number from decimal {}",
1901                        d
1902                    ))
1903                })?;
1904                JsonValue::Number(num)
1905            }
1906            _ => {
1907                return Err(ParseError::GrammarError(
1908                    "Unexpected object field value".to_string(),
1909                ))
1910            }
1911        };
1912        map.insert(key, value);
1913    }
1914    Ok(JsonValue::Object(map))
1915}
1916
1917/// Parse projection declaration
1918fn parse_projection(pair: Pair<Rule>) -> ParseResult<AstNode> {
1919    let mut inner = pair.into_inner();
1920
1921    let name = parse_string_literal(
1922        inner
1923            .next()
1924            .ok_or_else(|| ParseError::GrammarError("Expected projection name".to_string()))?,
1925    )?;
1926
1927    let target_pair = inner
1928        .next()
1929        .ok_or_else(|| ParseError::GrammarError("Expected target format".to_string()))?;
1930    let target = parse_target_format(target_pair)?;
1931
1932    let mut overrides = Vec::new();
1933
1934    for rule_pair in inner {
1935        if rule_pair.as_rule() == Rule::projection_rule {
1936            overrides.push(parse_projection_rule(rule_pair)?);
1937        }
1938    }
1939
1940    Ok(AstNode::ProjectionDecl {
1941        name,
1942        target,
1943        overrides,
1944    })
1945}
1946
1947fn parse_projection_rule(pair: Pair<Rule>) -> ParseResult<ProjectionOverride> {
1948    let mut inner = pair.into_inner();
1949
1950    let primitive_type = inner
1951        .next()
1952        .ok_or_else(|| ParseError::GrammarError("Expected primitive type".to_string()))?
1953        .as_str()
1954        .to_string();
1955
1956    let primitive_name = parse_string_literal(
1957        inner
1958            .next()
1959            .ok_or_else(|| ParseError::GrammarError("Expected primitive name".to_string()))?,
1960    )?;
1961
1962    let mut fields = HashMap::new();
1963    for field_pair in inner {
1964        if field_pair.as_rule() == Rule::projection_field {
1965            let mut field_inner = field_pair.into_inner();
1966            let key = parse_identifier(
1967                field_inner
1968                    .next()
1969                    .ok_or_else(|| ParseError::GrammarError("Expected field key".to_string()))?,
1970            )?;
1971            let value_pair = field_inner
1972                .next()
1973                .ok_or_else(|| ParseError::GrammarError("Expected field value".to_string()))?;
1974
1975            let value = match value_pair.as_rule() {
1976                Rule::string_literal => JsonValue::String(parse_string_literal(value_pair)?),
1977                Rule::property_mapping => parse_property_mapping(value_pair)?,
1978                _ => {
1979                    return Err(ParseError::GrammarError(
1980                        "Unexpected projection field value".to_string(),
1981                    ))
1982                }
1983            };
1984            fields.insert(key, value);
1985        }
1986    }
1987
1988    Ok(ProjectionOverride {
1989        primitive_type,
1990        primitive_name,
1991        fields,
1992    })
1993}
1994
1995fn parse_property_mapping(pair: Pair<Rule>) -> ParseResult<JsonValue> {
1996    let mut map = serde_json::Map::new();
1997    let mut inner = pair.into_inner();
1998    while let Some(key_pair) = inner.next() {
1999        let key = parse_string_literal(key_pair)?;
2000        let value_pair = inner.next().ok_or_else(|| {
2001            ParseError::GrammarError("Expected value in property mapping".to_string())
2002        })?;
2003        let value = parse_string_literal(value_pair)?;
2004        map.insert(key, JsonValue::String(value));
2005    }
2006    Ok(JsonValue::Object(map))
2007}
2008
2009fn unwrap_export(node: &AstNode) -> &AstNode {
2010    match node {
2011        AstNode::Export(inner) => inner.as_ref(),
2012        other => other,
2013    }
2014}
2015
2016/// Convert AST to Graph
2017pub fn ast_to_graph(ast: Ast) -> ParseResult<Graph> {
2018    ast_to_graph_with_options(ast, &ParseOptions::default())
2019}
2020
2021pub fn ast_to_graph_with_options(mut ast: Ast, options: &ParseOptions) -> ParseResult<Graph> {
2022    use crate::parser::profiles::ProfileRegistry;
2023    let registry = ProfileRegistry::global();
2024    let active_profile = ast
2025        .metadata
2026        .profile
2027        .clone()
2028        .or_else(|| options.active_profile.clone())
2029        .unwrap_or_else(|| "default".to_string());
2030    ast.metadata.profile.get_or_insert(active_profile.clone());
2031
2032    if registry.get(&active_profile).is_none() {
2033        let available = registry.list_names().join(", ");
2034        let message = format!(
2035            "Unknown profile: '{}'. Available profiles: {}",
2036            active_profile, available
2037        );
2038        if options.tolerate_profile_warnings {
2039            log::warn!("{}", message);
2040        } else {
2041            return Err(ParseError::Validation(message));
2042        }
2043    }
2044
2045    let mut graph = Graph::new();
2046    let mut entity_map = HashMap::new();
2047    let mut role_map = HashMap::new();
2048    let mut resource_map = HashMap::new();
2049    let mut relation_map = HashMap::new();
2050
2051    let default_namespace = ast
2052        .metadata
2053        .namespace
2054        .clone()
2055        .or_else(|| options.default_namespace.clone())
2056        .unwrap_or_else(|| "default".to_string());
2057
2058    // First pass: Register dimensions and units
2059    {
2060        use crate::units::{Dimension, Unit, UnitError, UnitRegistry};
2061        let registry = UnitRegistry::global();
2062        let mut registry = registry.write().map_err(|e| {
2063            ParseError::GrammarError(format!("Failed to lock unit registry: {}", e))
2064        })?;
2065
2066        for node in &ast.declarations {
2067            let node = unwrap_export(node);
2068            match node {
2069                AstNode::Dimension { name } => {
2070                    let dim = Dimension::parse(name);
2071                    registry.register_dimension(dim);
2072                }
2073                AstNode::UnitDeclaration {
2074                    symbol,
2075                    dimension,
2076                    factor,
2077                    base_unit,
2078                } => {
2079                    let dim = Dimension::parse(dimension);
2080                    let unit = Unit::new(
2081                        symbol.clone(),
2082                        symbol.clone(),
2083                        dim,
2084                        *factor,
2085                        base_unit.clone(),
2086                    );
2087                    match registry.get_unit(symbol) {
2088                        Ok(existing) => {
2089                            if existing != &unit {
2090                                return Err(ParseError::GrammarError(format!(
2091                                    "Conflicting unit '{}' already registered (existing: dimension={}, base_factor={}, base_unit={}; new: dimension={}, base_factor={}, base_unit={})",
2092                                    symbol,
2093                                    existing.dimension(),
2094                                    existing.base_factor(),
2095                                    existing.base_unit(),
2096                                    unit.dimension(),
2097                                    unit.base_factor(),
2098                                    unit.base_unit(),
2099                                )));
2100                            }
2101                        }
2102                        Err(UnitError::UnitNotFound(_)) => {
2103                            registry.register(unit).map_err(|e| {
2104                                ParseError::GrammarError(format!("Failed to register unit: {}", e))
2105                            })?;
2106                        }
2107                        Err(err) => {
2108                            return Err(ParseError::GrammarError(format!(
2109                                "Failed to inspect unit '{}': {}",
2110                                symbol, err
2111                            )));
2112                        }
2113                    }
2114                }
2115                _ => {}
2116            }
2117        }
2118    }
2119
2120    // Register patterns with eager regex validation
2121    for node in &ast.declarations {
2122        let node = unwrap_export(node);
2123        if let AstNode::Pattern { name, regex } = node {
2124            let namespace = default_namespace.clone();
2125            let pattern = Pattern::new(name.clone(), namespace, regex.clone())
2126                .map_err(ParseError::GrammarError)?;
2127
2128            graph
2129                .add_pattern(pattern)
2130                .map_err(ParseError::GrammarError)?;
2131        }
2132    }
2133
2134    // Register concept changes
2135    for node in &ast.declarations {
2136        let node = unwrap_export(node);
2137        if let AstNode::ConceptChange {
2138            name,
2139            from_version,
2140            to_version,
2141            migration_policy,
2142            breaking_change,
2143        } = node
2144        {
2145            let change = ConceptChange::new(
2146                name.clone(),
2147                from_version.clone(),
2148                to_version.clone(),
2149                migration_policy.clone(),
2150                *breaking_change,
2151            );
2152            graph.add_concept_change(change).map_err(|e| {
2153                ParseError::GrammarError(format!("Failed to add concept change: {}", e))
2154            })?;
2155        }
2156    }
2157
2158    // Second pass: Add roles, entities, and resources
2159    for node in &ast.declarations {
2160        let node = unwrap_export(node);
2161        match node {
2162            AstNode::Role { name, domain } => {
2163                if role_map.contains_key(name) {
2164                    return Err(ParseError::duplicate_declaration(format!(
2165                        "Role '{}' already declared",
2166                        name
2167                    )));
2168                }
2169
2170                let namespace = domain.as_ref().unwrap_or(&default_namespace).clone();
2171                let role = Role::new_with_namespace(name.clone(), namespace);
2172                let role_id = role.id().clone();
2173                graph
2174                    .add_role(role)
2175                    .map_err(|e| ParseError::GrammarError(format!("Failed to add role: {}", e)))?;
2176                role_map.insert(name.clone(), role_id);
2177            }
2178            AstNode::Entity {
2179                name,
2180                domain,
2181                version,
2182                annotations,
2183            } => {
2184                if entity_map.contains_key(name) {
2185                    return Err(ParseError::duplicate_declaration(format!(
2186                        "Entity '{}' already declared",
2187                        name
2188                    )));
2189                }
2190
2191                let namespace = domain.as_ref().unwrap_or(&default_namespace).clone();
2192                let mut entity = Entity::new_with_namespace(name.clone(), namespace);
2193
2194                if let Some(v_str) = version {
2195                    let sem_ver = SemanticVersion::parse(v_str).map_err(|e| {
2196                        ParseError::GrammarError(format!(
2197                            "Invalid entity version '{}': {}",
2198                            v_str, e
2199                        ))
2200                    })?;
2201                    entity = entity.with_version(sem_ver);
2202                }
2203
2204                if let Some(replaces_val) = annotations.get("replaces") {
2205                    if let Some(replaces_str) = replaces_val.as_str() {
2206                        entity = entity.with_replaces(replaces_str.to_string());
2207                    }
2208                }
2209
2210                if let Some(changes_val) = annotations.get("changes") {
2211                    if let Some(changes_arr) = changes_val.as_array() {
2212                        let changes: Vec<String> = changes_arr
2213                            .iter()
2214                            .filter_map(|v| v.as_str().map(|s| s.to_string()))
2215                            .collect();
2216                        entity = entity.with_changes(changes);
2217                    }
2218                }
2219
2220                let entity_id = entity.id().clone();
2221                graph.add_entity(entity).map_err(|e| {
2222                    ParseError::GrammarError(format!("Failed to add entity: {}", e))
2223                })?;
2224                entity_map.insert(name.clone(), entity_id);
2225            }
2226            AstNode::Resource {
2227                name,
2228                unit_name,
2229                domain,
2230            } => {
2231                if resource_map.contains_key(name) {
2232                    return Err(ParseError::duplicate_declaration(format!(
2233                        "Resource '{}' already declared",
2234                        name
2235                    )));
2236                }
2237
2238                let namespace = domain.as_ref().unwrap_or(&default_namespace).clone();
2239                let unit = unit_from_string(unit_name.as_deref().unwrap_or("units"));
2240                let resource = Resource::new_with_namespace(name.clone(), unit, namespace);
2241                let resource_id = resource.id().clone();
2242                graph.add_resource(resource).map_err(|e| {
2243                    ParseError::GrammarError(format!("Failed to add resource: {}", e))
2244                })?;
2245                resource_map.insert(name.clone(), resource_id);
2246            }
2247            _ => {}
2248        }
2249    }
2250
2251    // Third pass: Add flows
2252    for node in &ast.declarations {
2253        let node = unwrap_export(node);
2254        if let AstNode::Flow {
2255            resource_name,
2256            from_entity,
2257            to_entity,
2258            quantity,
2259        } = node
2260        {
2261            let from_id = entity_map
2262                .get(from_entity)
2263                .ok_or_else(|| ParseError::undefined_entity(from_entity))?;
2264
2265            let to_id = entity_map
2266                .get(to_entity)
2267                .ok_or_else(|| ParseError::undefined_entity(to_entity))?;
2268
2269            let resource_id = resource_map
2270                .get(resource_name)
2271                .ok_or_else(|| ParseError::undefined_resource(resource_name))?;
2272
2273            let qty = quantity.map(Decimal::from).unwrap_or(Decimal::ZERO);
2274            let flow = Flow::new(resource_id.clone(), from_id.clone(), to_id.clone(), qty);
2275
2276            graph
2277                .add_flow(flow)
2278                .map_err(|e| ParseError::GrammarError(format!("Failed to add flow: {}", e)))?;
2279        }
2280    }
2281
2282    // Fourth pass: Add relations
2283    for node in &ast.declarations {
2284        let node = unwrap_export(node);
2285        if let AstNode::Relation {
2286            name,
2287            subject_role,
2288            predicate,
2289            object_role,
2290            via_flow,
2291        } = node
2292        {
2293            if relation_map.contains_key(name) {
2294                return Err(ParseError::duplicate_declaration(format!(
2295                    "Relation '{}' already declared",
2296                    name
2297                )));
2298            }
2299
2300            let subject_id = role_map.get(subject_role).ok_or_else(|| {
2301                ParseError::GrammarError(format!("Undefined subject role '{}'", subject_role))
2302            })?;
2303
2304            let object_id = role_map.get(object_role).ok_or_else(|| {
2305                ParseError::GrammarError(format!("Undefined object role '{}'", object_role))
2306            })?;
2307
2308            let via_flow_id = if let Some(flow_name) = via_flow {
2309                Some(
2310                    resource_map
2311                        .get(flow_name)
2312                        .cloned()
2313                        .ok_or_else(|| ParseError::undefined_resource(flow_name))?,
2314                )
2315            } else {
2316                None
2317            };
2318
2319            let relation = RelationType::new(
2320                name.clone(),
2321                default_namespace.clone(),
2322                subject_id.clone(),
2323                predicate.clone(),
2324                object_id.clone(),
2325                via_flow_id,
2326            );
2327
2328            let relation_id = relation.id().clone();
2329            graph.add_relation_type(relation).map_err(|e| {
2330                ParseError::GrammarError(format!("Failed to add relation '{}': {}", name, e))
2331            })?;
2332            relation_map.insert(name.clone(), relation_id);
2333        }
2334    }
2335
2336    // Instance pass: Add instances (after entities are created)
2337    for node in &ast.declarations {
2338        let node = unwrap_export(node);
2339        if let AstNode::Instance {
2340            name,
2341            entity_type,
2342            fields,
2343        } = node
2344        {
2345            let namespace = default_namespace.clone();
2346            let mut instance = crate::primitives::Instance::new_with_namespace(
2347                name.clone(),
2348                entity_type.clone(),
2349                namespace,
2350            );
2351
2352            // Evaluate and set fields
2353            for (field_name, field_expr) in fields {
2354                let value = expression_to_json(field_expr)?;
2355                instance.set_field(field_name.clone(), value);
2356            }
2357
2358            graph.add_entity_instance(instance).map_err(|e| {
2359                ParseError::GrammarError(format!("Failed to add entity instance '{}': {}", name, e))
2360            })?;
2361        }
2362    }
2363
2364    // Fifth pass: Add policies
2365    for node in &ast.declarations {
2366        let node = unwrap_export(node);
2367        if let AstNode::Policy {
2368            name,
2369            version,
2370            metadata,
2371            expression,
2372        } = node
2373        {
2374            let namespace = ast
2375                .metadata
2376                .namespace
2377                .as_ref()
2378                .cloned()
2379                .or_else(|| options.default_namespace.clone())
2380                .unwrap_or_else(|| "default".to_string());
2381
2382            let kind = metadata.kind.as_ref().map(|kind| match kind {
2383                PolicyKind::Constraint => CorePolicyKind::Constraint,
2384                PolicyKind::Derivation => CorePolicyKind::Derivation,
2385                PolicyKind::Obligation => CorePolicyKind::Obligation,
2386            });
2387
2388            let modality = metadata.modality.as_ref().map(|modality| match modality {
2389                PolicyModality::Obligation => CorePolicyModality::Obligation,
2390                PolicyModality::Prohibition => CorePolicyModality::Prohibition,
2391                PolicyModality::Permission => CorePolicyModality::Permission,
2392            });
2393
2394            let mut policy =
2395                Policy::new_with_namespace(name.clone(), namespace, expression.clone())
2396                    .with_metadata(
2397                        kind,
2398                        modality,
2399                        metadata.priority,
2400                        metadata.rationale.clone(),
2401                        metadata.tags.clone(),
2402                    );
2403
2404            let version_to_apply = version
2405                .as_ref()
2406                .cloned()
2407                .or_else(|| ast.metadata.version.clone());
2408
2409            if let Some(version_str) = version_to_apply {
2410                let semantic_version = SemanticVersion::parse(&version_str).map_err(|err| {
2411                    ParseError::GrammarError(format!(
2412                        "Invalid policy version '{}': {}",
2413                        version_str, err
2414                    ))
2415                })?;
2416                policy = policy.with_version(semantic_version);
2417            }
2418
2419            graph.add_policy(policy).map_err(|e| {
2420                ParseError::GrammarError(format!("Failed to add policy '{}': {}", name, e))
2421            })?;
2422        }
2423    }
2424
2425    // Sixth pass: Add metrics
2426    for node in &ast.declarations {
2427        let node = unwrap_export(node);
2428        if let AstNode::Metric {
2429            name,
2430            expression,
2431            metadata,
2432        } = node
2433        {
2434            let namespace = ast
2435                .metadata
2436                .namespace
2437                .as_ref()
2438                .cloned()
2439                .or_else(|| options.default_namespace.clone())
2440                .unwrap_or_else(|| "default".to_string());
2441
2442            let mut metric =
2443                crate::primitives::Metric::new(name.clone(), namespace, expression.clone());
2444
2445            if let Some(duration) = metadata.refresh_interval {
2446                metric = metric.with_refresh_interval(duration);
2447            }
2448
2449            if let Some(unit) = &metadata.unit {
2450                metric = metric.with_unit(unit.clone());
2451            }
2452
2453            if let Some(threshold) = metadata.threshold {
2454                metric = metric.with_threshold(threshold);
2455            }
2456
2457            if let Some(severity) = metadata.severity.clone() {
2458                metric = metric.with_severity(severity);
2459            }
2460
2461            if let Some(target) = metadata.target {
2462                metric = metric.with_target(target);
2463            }
2464
2465            if let Some(duration) = metadata.window {
2466                metric = metric.with_window(duration);
2467            }
2468
2469            graph.add_metric(metric).map_err(|e| {
2470                ParseError::GrammarError(format!("Failed to add metric '{}': {}", name, e))
2471            })?;
2472        }
2473    }
2474
2475    // Seventh pass: Add mappings
2476    for node in &ast.declarations {
2477        let node = unwrap_export(node);
2478        if let AstNode::MappingDecl {
2479            name,
2480            target,
2481            rules,
2482        } = node
2483        {
2484            let namespace = ast
2485                .metadata
2486                .namespace
2487                .clone()
2488                .or_else(|| options.default_namespace.clone())
2489                .unwrap_or_else(|| "default".to_string());
2490            let mapping = crate::primitives::MappingContract::new(
2491                crate::ConceptId::from_concept(&namespace, name),
2492                name.clone(),
2493                namespace,
2494                target.clone(),
2495                rules.clone(),
2496            );
2497            graph
2498                .add_mapping(mapping)
2499                .map_err(|e| ParseError::GrammarError(format!("Failed to add mapping: {}", e)))?;
2500        }
2501    }
2502
2503    // Eighth pass: Add projections
2504    for node in &ast.declarations {
2505        let node = unwrap_export(node);
2506        if let AstNode::ProjectionDecl {
2507            name,
2508            target,
2509            overrides,
2510        } = node
2511        {
2512            let namespace = ast
2513                .metadata
2514                .namespace
2515                .clone()
2516                .or_else(|| options.default_namespace.clone())
2517                .unwrap_or_else(|| "default".to_string());
2518            let projection = crate::primitives::ProjectionContract::new(
2519                crate::ConceptId::from_concept(&namespace, name),
2520                name.clone(),
2521                namespace,
2522                target.clone(),
2523                overrides.clone(),
2524            );
2525            graph.add_projection(projection).map_err(|e| {
2526                ParseError::GrammarError(format!("Failed to add projection: {}", e))
2527            })?;
2528        }
2529    }
2530
2531    Ok(graph)
2532}
2533
2534/// Parse metric declaration
2535fn parse_metric(pair: Pair<Rule>) -> ParseResult<AstNode> {
2536    let mut inner = pair.into_inner();
2537
2538    let name = parse_name(
2539        inner
2540            .next()
2541            .ok_or_else(|| ParseError::GrammarError("Expected metric name".to_string()))?,
2542    )?;
2543
2544    let mut metadata = MetricMetadata {
2545        refresh_interval: None,
2546        unit: None,
2547        threshold: None,
2548        severity: None,
2549        target: None,
2550        window: None,
2551    };
2552
2553    let mut expression_pair = None;
2554
2555    for part in inner {
2556        match part.as_rule() {
2557            Rule::metric_annotation => {
2558                let mut annotation_inner = part.into_inner();
2559                let key_pair = annotation_inner.next().ok_or_else(|| {
2560                    ParseError::GrammarError("Expected annotation key".to_string())
2561                })?;
2562
2563                match key_pair.as_rule() {
2564                    Rule::ma_refresh_interval => {
2565                        let value_pair = annotation_inner.next().ok_or_else(|| {
2566                            ParseError::GrammarError("Expected refresh interval value".to_string())
2567                        })?;
2568                        let value = parse_number_i64(value_pair)?;
2569                        let unit_pair = annotation_inner.next().ok_or_else(|| {
2570                            ParseError::GrammarError("Expected refresh interval unit".to_string())
2571                        })?;
2572                        let unit = parse_string_literal(unit_pair.clone())?;
2573                        let duration = parse_duration_with_unit(value, &unit, unit_pair.as_span())?;
2574                        metadata.refresh_interval = Some(duration);
2575                    }
2576                    Rule::ma_unit => {
2577                        let unit_pair = annotation_inner
2578                            .next()
2579                            .ok_or_else(|| ParseError::GrammarError("Expected unit".to_string()))?;
2580                        metadata.unit = Some(parse_string_literal(unit_pair)?);
2581                    }
2582                    Rule::ma_threshold => {
2583                        let value_pair = annotation_inner.next().ok_or_else(|| {
2584                            ParseError::GrammarError("Expected threshold value".to_string())
2585                        })?;
2586                        metadata.threshold = Some(parse_decimal(value_pair)?);
2587                    }
2588                    Rule::ma_severity => {
2589                        let severity_pair = annotation_inner.next().ok_or_else(|| {
2590                            ParseError::GrammarError("Expected severity".to_string())
2591                        })?;
2592                        let severity_str = parse_string_literal(severity_pair.clone())?;
2593                        let severity =
2594                            parse_severity_value(&severity_str, severity_pair.as_span())?;
2595                        metadata.severity = Some(severity);
2596                    }
2597                    Rule::ma_target => {
2598                        let value_pair = annotation_inner.next().ok_or_else(|| {
2599                            ParseError::GrammarError("Expected target value".to_string())
2600                        })?;
2601                        metadata.target = Some(parse_decimal(value_pair)?);
2602                    }
2603                    Rule::ma_window => {
2604                        let value_pair = annotation_inner.next().ok_or_else(|| {
2605                            ParseError::GrammarError("Expected window value".to_string())
2606                        })?;
2607                        let value = parse_number_i64(value_pair)?;
2608                        let unit_pair = annotation_inner.next().ok_or_else(|| {
2609                            ParseError::GrammarError("Expected window unit".to_string())
2610                        })?;
2611                        let unit = parse_string_literal(unit_pair.clone())?;
2612                        let duration = parse_duration_with_unit(value, &unit, unit_pair.as_span())?;
2613                        metadata.window = Some(duration);
2614                    }
2615                    _ => {
2616                        let (line, column) = key_pair.as_span().start_pos().line_col();
2617                        return Err(ParseError::GrammarError(format!(
2618                            "Unknown metric annotation '{}' at {}:{}",
2619                            key_pair.as_str(),
2620                            line,
2621                            column
2622                        )));
2623                    }
2624                }
2625            }
2626            Rule::expression => {
2627                expression_pair = Some(part);
2628            }
2629            _ => {}
2630        }
2631    }
2632
2633    let expression = parse_expression(
2634        expression_pair
2635            .ok_or_else(|| ParseError::GrammarError("Expected metric expression".to_string()))?,
2636    )?;
2637
2638    Ok(AstNode::Metric {
2639        name,
2640        expression,
2641        metadata,
2642    })
2643}
2644
2645fn parse_duration_with_unit(value: i64, unit: &str, span: Span<'_>) -> ParseResult<Duration> {
2646    let normalized_unit = unit.to_ascii_lowercase();
2647    let multiplier = match normalized_unit.as_str() {
2648        "second" => Some(1),
2649        "seconds" | "s" => Some(1),
2650        "minute" => Some(60),
2651        "minutes" | "m" => Some(60),
2652        "hour" => Some(60 * 60),
2653        "hours" | "h" => Some(60 * 60),
2654        "day" => Some(60 * 60 * 24),
2655        "days" | "d" => Some(60 * 60 * 24),
2656        _ => None,
2657    }
2658    .ok_or_else(|| {
2659        let (line, column) = span.start_pos().line_col();
2660        ParseError::GrammarError(format!(
2661            "Invalid duration unit '{}' at {}:{} (allowed: second(s)/s, minute(s)/m, hour(s)/h, day(s)/d)",
2662            unit, line, column
2663        ))
2664    })?;
2665
2666    let total_seconds = value.checked_mul(multiplier).ok_or_else(|| {
2667        let (line, column) = span.start_pos().line_col();
2668        ParseError::GrammarError(format!(
2669            "Duration overflow for value {} {} at {}:{}",
2670            value, unit, line, column
2671        ))
2672    })?;
2673
2674    Ok(Duration::seconds(total_seconds))
2675}
2676
2677fn parse_severity_value(value: &str, span: Span<'_>) -> ParseResult<Severity> {
2678    let normalized = value.to_ascii_lowercase();
2679    match normalized.as_str() {
2680        "info" => Ok(Severity::Info),
2681        "warning" => Ok(Severity::Warning),
2682        "error" => Ok(Severity::Error),
2683        "critical" => Ok(Severity::Critical),
2684        _ => {
2685            let (line, column) = span.start_pos().line_col();
2686            Err(ParseError::GrammarError(format!(
2687                "Unknown severity '{}' at {}:{} (expected one of: info, warning, error, critical)",
2688                value, line, column
2689            )))
2690        }
2691    }
2692}
2693
2694fn parse_number_i64(pair: Pair<Rule>) -> ParseResult<i64> {
2695    let s = pair.as_str();
2696    s.parse::<i64>()
2697        .map_err(|_| ParseError::GrammarError(format!("Invalid integer: {}", s)))
2698}