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