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