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)]
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#[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
237pub fn parse_source(source: &str) -> ParseResult<Ast> {
239 let pairs = SeaParser::parse(Rule::program, source)?;
240 build_ast(pairs)
241}
242
243fn 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
278fn 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
319fn 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 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
428fn 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
440fn 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
475fn 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 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 Rule::identifier => {
535 let key = parse_identifier(key_pair)?.to_lowercase();
536 let value_pair = annotation_inner.next().ok_or_else(|| {
537 ParseError::GrammarError("Expected annotation value".to_string())
538 })?;
539 let value = parse_annotation_value(value_pair)?;
540 println!("debug insert annotation {} = {:?}", key, value);
541 annotations.insert(key, value);
542 }
543 _ => {
544 return Err(ParseError::GrammarError(format!(
545 "Unexpected flow annotation: {}",
546 key_pair.as_str()
547 )));
548 }
549 }
550 }
551 Rule::in_keyword => {
552 }
554 Rule::identifier => {
555 domain = Some(parse_identifier(part)?);
557 }
558 _ => {}
559 }
560 }
561
562 Ok(AstNode::Entity {
563 name,
564 version,
565 annotations,
566 domain,
567 })
568}
569
570fn parse_concept_change(pair: Pair<Rule>) -> ParseResult<AstNode> {
572 let mut inner = pair.into_inner();
573
574 let name =
575 parse_name(inner.next().ok_or_else(|| {
576 ParseError::GrammarError("Expected concept change name".to_string())
577 })?)?;
578
579 let mut from_version = String::new();
580 let mut to_version = String::new();
581 let mut migration_policy = String::new();
582 let mut breaking_change = false;
583
584 for part in inner {
585 if part.as_rule() == Rule::concept_change_annotation {
586 let mut annotation_inner = part.into_inner();
587
588 let key_pair = annotation_inner
589 .next()
590 .ok_or_else(|| ParseError::GrammarError("Expected annotation key".to_string()))?;
591 let value_pair = annotation_inner
592 .next()
593 .ok_or_else(|| ParseError::GrammarError("Expected annotation value".to_string()))?;
594
595 match key_pair.as_rule() {
596 Rule::cc_from_version => from_version = parse_version(value_pair)?,
597 Rule::cc_to_version => to_version = parse_version(value_pair)?,
598 Rule::cc_migration_policy => migration_policy = parse_identifier(value_pair)?,
599 Rule::cc_breaking_change => {
600 breaking_change = value_pair.as_str() == "true";
601 }
602 _ => {}
603 }
604 }
605 }
606
607 if from_version.is_empty() {
608 return Err(ParseError::GrammarError(
609 "Missing cc_from_version annotation".to_string(),
610 ));
611 }
612
613 if to_version.is_empty() {
614 return Err(ParseError::GrammarError(
615 "Missing cc_to_version annotation".to_string(),
616 ));
617 }
618
619 if migration_policy.is_empty() {
620 return Err(ParseError::GrammarError(
621 "Missing cc_migration_policy annotation".to_string(),
622 ));
623 }
624
625 Ok(AstNode::ConceptChange {
626 name,
627 from_version,
628 to_version,
629 migration_policy,
630 breaking_change,
631 })
632}
633
634fn parse_resource(pair: Pair<Rule>) -> ParseResult<AstNode> {
636 let mut inner = pair.into_inner();
637
638 let name = parse_name(
639 inner
640 .next()
641 .ok_or_else(|| ParseError::GrammarError("Expected resource name".to_string()))?,
642 )?;
643
644 let mut annotations = HashMap::new();
645 let mut unit_name = None;
646 let mut domain = None;
647 let mut saw_in_keyword = false;
648
649 for part in inner {
650 match part.as_rule() {
651 Rule::resource_annotation => {
652 let mut annotation_inner = part.into_inner();
653 let key_pair = annotation_inner
654 .next()
655 .ok_or_else(|| ParseError::GrammarError("Empty annotation".to_string()))?;
656
657 match key_pair.as_rule() {
658 Rule::ea_replaces => {
659 let target_name =
660 parse_name(annotation_inner.next().ok_or_else(|| {
661 ParseError::GrammarError("Expected name in replaces".to_string())
662 })?)?;
663 let mut target_version = None;
665 if let Some(next) = annotation_inner.next() {
666 if next.as_rule() == Rule::version {
667 target_version = Some(next.as_str().to_string());
668 }
669 }
670
671 let value = if let Some(v) = target_version {
672 format!("{} v{}", target_name, v)
673 } else {
674 target_name
675 };
676 annotations.insert("replaces".to_string(), JsonValue::String(value));
677 }
678 Rule::ea_changes => {
679 let array_pair = annotation_inner.next().ok_or_else(|| {
680 ParseError::GrammarError("Expected string array in changes".to_string())
681 })?;
682 let mut changes = Vec::new();
683 for item in array_pair.into_inner() {
684 changes.push(parse_string_literal(item)?);
685 }
686 annotations.insert(
687 "changes".to_string(),
688 JsonValue::Array(changes.into_iter().map(JsonValue::String).collect()),
689 );
690 }
691 Rule::identifier => {
692 let key = parse_identifier(key_pair)?.to_lowercase();
693 let value_pair = annotation_inner.next().ok_or_else(|| {
694 ParseError::GrammarError("Expected annotation value".to_string())
695 })?;
696 let value = parse_annotation_value(value_pair)?;
697 annotations.insert(key, value);
698 }
699 _ => {
700 return Err(ParseError::GrammarError(format!(
701 "Unexpected flow annotation: {}",
702 key_pair.as_str()
703 )));
704 }
705 }
706 }
707 Rule::in_keyword => {
708 saw_in_keyword = true;
710 }
711 Rule::identifier => {
712 if saw_in_keyword {
714 domain = Some(parse_identifier(part)?);
715 saw_in_keyword = false; } else {
717 unit_name = Some(parse_identifier(part)?);
718 }
719 }
720 _ => {}
721 }
722 }
723
724 Ok(AstNode::Resource {
725 name,
726 annotations,
727 unit_name,
728 domain,
729 })
730}
731
732fn parse_flow(pair: Pair<Rule>) -> ParseResult<AstNode> {
734 let mut inner = pair.into_inner();
735
736 let resource_name = parse_string_literal(
737 inner
738 .next()
739 .ok_or_else(|| ParseError::GrammarError("Expected resource name".to_string()))?,
740 )?;
741
742 let mut annotations = HashMap::new();
743 let mut from_entity = None;
744 let mut to_entity = None;
745 let mut quantity = None;
746 let mut pending_annotation_key: Option<String> = None;
747
748 for part in inner {
749 match part.as_rule() {
750 Rule::flow_annotation => {
751 let mut annotation_inner = part.into_inner();
752 let key_pair = annotation_inner
753 .next()
754 .ok_or_else(|| ParseError::GrammarError("Empty annotation".to_string()))?;
755
756 match key_pair.as_rule() {
757 Rule::ea_replaces => {
758 let target_name =
759 parse_name(annotation_inner.next().ok_or_else(|| {
760 ParseError::GrammarError("Expected name in replaces".to_string())
761 })?)?;
762 let mut target_version = None;
764 if let Some(next) = annotation_inner.next() {
765 if next.as_rule() == Rule::version {
766 target_version = Some(next.as_str().to_string());
767 }
768 }
769
770 let value = if let Some(v) = target_version {
771 format!("{} v{}", target_name, v)
772 } else {
773 target_name
774 };
775 annotations.insert("replaces".to_string(), JsonValue::String(value));
776 }
777 Rule::ea_changes => {
778 let array_pair = annotation_inner.next().ok_or_else(|| {
779 ParseError::GrammarError("Expected string array in changes".to_string())
780 })?;
781 let mut changes = Vec::new();
782 for item in array_pair.into_inner() {
783 changes.push(parse_string_literal(item)?);
784 }
785 annotations.insert(
786 "changes".to_string(),
787 JsonValue::Array(changes.into_iter().map(JsonValue::String).collect()),
788 );
789 }
790 Rule::identifier => {
791 let key = parse_identifier(key_pair)?.to_lowercase();
792 let value_pair = annotation_inner.next().ok_or_else(|| {
793 ParseError::GrammarError("Expected annotation value".to_string())
794 })?;
795 let value = parse_annotation_value(value_pair)?;
796 annotations.insert(key, value);
797 }
798 _ => {
799 return Err(ParseError::GrammarError(format!(
800 "Unexpected flow annotation: {}",
801 key_pair.as_str()
802 )));
803 }
804 }
805 }
806 Rule::identifier => {
807 if pending_annotation_key.is_some() {
808 return Err(ParseError::GrammarError(
809 "Unexpected annotation key without value".to_string(),
810 ));
811 }
812 pending_annotation_key = Some(parse_identifier(part)?.to_lowercase());
813 }
814 Rule::annotation_value
815 | Rule::object_literal
816 | Rule::string_array
817 | Rule::boolean
818 | Rule::number
819 | Rule::string_literal => {
820 if let Some(key) = pending_annotation_key.take() {
821 let value = parse_annotation_value(part)?;
822 annotations.insert(key, value);
823 continue;
824 }
825
826 if part.as_rule() == Rule::string_literal {
827 let parsed = parse_string_literal(part)?;
829 if from_entity.is_none() {
830 from_entity = Some(parsed);
831 } else if to_entity.is_none() {
832 to_entity = Some(parsed);
833 }
834 } else if part.as_rule() == Rule::number {
835 quantity = Some(parse_number(part)?);
836 }
837 }
838 _ => {}
839 }
840 }
841
842 Ok(AstNode::Flow {
843 resource_name,
844 annotations,
845 from_entity: from_entity
846 .ok_or_else(|| ParseError::GrammarError("Expected from entity".to_string()))?,
847 to_entity: to_entity
848 .ok_or_else(|| ParseError::GrammarError("Expected to entity".to_string()))?,
849 quantity,
850 })
851}
852
853fn parse_pattern(pair: Pair<Rule>) -> ParseResult<AstNode> {
855 let mut inner = pair.into_inner();
856
857 let name = parse_name(
858 inner
859 .next()
860 .ok_or_else(|| ParseError::GrammarError("Expected pattern name".to_string()))?,
861 )?;
862
863 let regex_literal = inner
864 .next()
865 .ok_or_else(|| ParseError::GrammarError("Expected regex for pattern".to_string()))?;
866 let regex = parse_string_literal(regex_literal)?;
867
868 Ok(AstNode::Pattern { name, regex })
869}
870
871fn parse_role(pair: Pair<Rule>) -> ParseResult<AstNode> {
873 let mut inner = pair.into_inner();
874
875 let name = parse_name(
876 inner
877 .next()
878 .ok_or_else(|| ParseError::GrammarError("Expected role name".to_string()))?,
879 )?;
880
881 let domain = if let Some(domain_pair) = inner.next() {
882 Some(parse_identifier(domain_pair)?)
883 } else {
884 None
885 };
886
887 Ok(AstNode::Role { name, domain })
888}
889
890fn parse_relation(pair: Pair<Rule>) -> ParseResult<AstNode> {
892 let mut inner = pair.into_inner();
893
894 let name = parse_name(
895 inner
896 .next()
897 .ok_or_else(|| ParseError::GrammarError("Expected relation name".to_string()))?,
898 )?;
899
900 let subject_literal = inner
901 .next()
902 .ok_or_else(|| ParseError::GrammarError("Expected subject role in relation".to_string()))?;
903 let subject_role = parse_string_literal(subject_literal)?;
904
905 let predicate_literal = inner
906 .next()
907 .ok_or_else(|| ParseError::GrammarError("Expected predicate in relation".to_string()))?;
908 let predicate = parse_string_literal(predicate_literal)?;
909
910 let object_literal = inner
911 .next()
912 .ok_or_else(|| ParseError::GrammarError("Expected object role in relation".to_string()))?;
913 let object_role = parse_string_literal(object_literal)?;
914
915 let via_flow = if let Some(via_pair) = inner.next() {
916 match via_pair.as_rule() {
917 Rule::string_literal => Some(parse_string_literal(via_pair)?),
918 _ => {
919 let mut via_inner = via_pair.into_inner();
920 let flow_literal = via_inner.next().ok_or_else(|| {
921 ParseError::GrammarError("Expected flow name after via".to_string())
922 })?;
923 Some(parse_string_literal(flow_literal)?)
924 }
925 }
926 } else {
927 None
928 };
929
930 Ok(AstNode::Relation {
931 name,
932 subject_role,
933 predicate,
934 object_role,
935 via_flow,
936 })
937}
938
939fn parse_instance(pair: Pair<Rule>) -> ParseResult<AstNode> {
941 let mut inner = pair.into_inner();
942
943 let name = parse_identifier(
944 inner
945 .next()
946 .ok_or_else(|| ParseError::GrammarError("Expected instance name".to_string()))?,
947 )?;
948
949 let entity_type = parse_string_literal(
950 inner
951 .next()
952 .ok_or_else(|| ParseError::GrammarError("Expected entity type".to_string()))?,
953 )?;
954
955 let mut fields = HashMap::new();
956
957 if let Some(body_pair) = inner.next() {
959 if body_pair.as_rule() == Rule::instance_body {
960 for field_pair in body_pair.into_inner() {
961 if field_pair.as_rule() == Rule::instance_field {
962 let span = field_pair.as_span();
963 let mut field_inner = field_pair.into_inner();
964
965 let field_name = parse_identifier(field_inner.next().ok_or_else(|| {
966 ParseError::GrammarError("Expected field name".to_string())
967 })?)?;
968
969 if fields.contains_key(&field_name) {
970 let (line, column) = span.start_pos().line_col();
971 return Err(ParseError::GrammarError(format!(
972 "Duplicate field name '{}' at line {}, column {}",
973 field_name, line, column
974 )));
975 }
976
977 let field_value = parse_expression(field_inner.next().ok_or_else(|| {
978 ParseError::GrammarError("Expected field value".to_string())
979 })?)?;
980
981 fields.insert(field_name, field_value);
982 }
983 }
984 }
985 }
986
987 Ok(AstNode::Instance {
988 name,
989 entity_type,
990 fields,
991 })
992}
993
994fn parse_policy(pair: Pair<Rule>) -> ParseResult<AstNode> {
996 let mut inner = pair.into_inner();
997
998 let name = parse_identifier(
999 inner
1000 .next()
1001 .ok_or_else(|| ParseError::GrammarError("Expected policy name".to_string()))?,
1002 )?;
1003
1004 let mut metadata = PolicyMetadata {
1005 kind: None,
1006 modality: None,
1007 priority: None,
1008 rationale: None,
1009 tags: Vec::new(),
1010 };
1011 let mut version: Option<String> = None;
1012
1013 for next_pair in inner {
1014 match next_pair.as_rule() {
1015 Rule::policy_kind => {
1016 metadata.kind = Some(match next_pair.as_str().to_lowercase().as_str() {
1017 "constraint" => PolicyKind::Constraint,
1018 "derivation" => PolicyKind::Derivation,
1019 "obligation" => PolicyKind::Obligation,
1020 _ => {
1021 return Err(ParseError::GrammarError(format!(
1022 "Unknown policy kind: {}",
1023 next_pair.as_str()
1024 )))
1025 }
1026 });
1027 }
1028 Rule::policy_modality => {
1029 metadata.modality = Some(match next_pair.as_str().to_lowercase().as_str() {
1030 "obligation" => PolicyModality::Obligation,
1031 "prohibition" => PolicyModality::Prohibition,
1032 "permission" => PolicyModality::Permission,
1033 _ => {
1034 return Err(ParseError::GrammarError(format!(
1035 "Unknown policy modality: {}",
1036 next_pair.as_str()
1037 )))
1038 }
1039 });
1040 }
1041 Rule::number => {
1042 metadata.priority = Some(parse_number(next_pair)?);
1043 }
1044 Rule::policy_annotation => {
1045 parse_policy_annotation(next_pair, &mut metadata)?;
1046 }
1047 Rule::version => {
1048 version = Some(next_pair.as_str().to_string());
1049 }
1050 Rule::expression => {
1051 let expression = parse_expression(next_pair)?;
1052 return Ok(AstNode::Policy {
1053 name,
1054 version,
1055 metadata,
1056 expression,
1057 });
1058 }
1059 _ => {}
1060 }
1061 }
1062
1063 Err(ParseError::GrammarError(
1064 "Policy missing expression".to_string(),
1065 ))
1066}
1067
1068fn parse_policy_annotation(pair: Pair<Rule>, metadata: &mut PolicyMetadata) -> ParseResult<()> {
1069 let mut inner = pair.into_inner();
1070
1071 let name = inner
1072 .next()
1073 .ok_or_else(|| ParseError::GrammarError("Expected annotation name".to_string()))?;
1074 let value = inner
1075 .next()
1076 .ok_or_else(|| ParseError::GrammarError("Expected annotation value".to_string()))?;
1077
1078 let name_str = name.as_str().to_lowercase();
1079
1080 match name_str.as_str() {
1081 "rationale" => {
1082 metadata.rationale = Some(parse_string_literal(value)?);
1083 }
1084 "tags" => {
1085 if value.as_rule() == Rule::string_array {
1086 for tag_pair in value.into_inner() {
1087 if tag_pair.as_rule() == Rule::string_literal {
1088 metadata.tags.push(parse_string_literal(tag_pair)?);
1089 }
1090 }
1091 } else {
1092 metadata.tags.push(parse_string_literal(value)?);
1093 }
1094 }
1095 _ => {
1096 return Err(ParseError::GrammarError(format!(
1097 "Unknown policy annotation: {}",
1098 name_str
1099 )))
1100 }
1101 }
1102
1103 Ok(())
1104}
1105
1106fn parse_expression(pair: Pair<Rule>) -> ParseResult<Expression> {
1108 match pair.as_rule() {
1109 Rule::expression => {
1110 let inner = pair
1111 .into_inner()
1112 .next()
1113 .ok_or_else(|| ParseError::GrammarError("Empty expression".to_string()))?;
1114 parse_expression(inner)
1115 }
1116 Rule::or_expr => parse_or_expr(pair),
1117 Rule::and_expr => parse_and_expr(pair),
1118 Rule::not_expr => parse_not_expr(pair),
1119 Rule::comparison_expr => parse_comparison_expr(pair),
1120 Rule::additive_expr => parse_additive_expr(pair),
1121 Rule::multiplicative_expr => parse_multiplicative_expr(pair),
1122 Rule::unary_expr => parse_unary_expr(pair),
1123 Rule::cast_expr => parse_cast_expr(pair),
1124 Rule::primary_expr => parse_primary_expr(pair),
1125 _ => Err(ParseError::InvalidExpression(format!(
1126 "Unexpected expression rule: {:?}",
1127 pair.as_rule()
1128 ))),
1129 }
1130}
1131
1132pub fn parse_expression_from_str(source: &str) -> ParseResult<Expression> {
1134 let pairs = SeaParser::parse(Rule::expression, source)
1135 .map_err(|e| ParseError::GrammarError(format!("Parse error: {}", e)))?;
1136 let parsed_pairs: Vec<_> = pairs.collect();
1137
1138 if parsed_pairs.is_empty() {
1139 return Err(ParseError::GrammarError("Empty expression".to_string()));
1140 }
1141 if parsed_pairs.len() > 1 {
1142 return Err(ParseError::GrammarError(
1143 "Trailing input detected after expression".to_string(),
1144 ));
1145 }
1146
1147 let pair = parsed_pairs.into_iter().next().unwrap();
1148
1149 let consumed = pair.as_span().end();
1151 let trimmed_source = source.trim_end();
1152 if consumed < trimmed_source.len() {
1153 return Err(ParseError::GrammarError(format!(
1154 "Trailing input after expression: '{}'",
1155 &source[consumed..]
1156 )));
1157 }
1158
1159 parse_expression(pair)
1160}
1161
1162fn parse_or_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1164 let mut inner = pair.into_inner();
1165 let mut left =
1166 parse_expression(inner.next().ok_or_else(|| {
1167 ParseError::GrammarError("Expected left expression in OR".to_string())
1168 })?)?;
1169
1170 for right_pair in inner {
1171 let right = parse_expression(right_pair)?;
1172 left = Expression::Binary {
1173 left: Box::new(left),
1174 op: BinaryOp::Or,
1175 right: Box::new(right),
1176 };
1177 }
1178
1179 Ok(left)
1180}
1181
1182fn parse_and_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1184 let mut inner = pair.into_inner();
1185 let mut left =
1186 parse_expression(inner.next().ok_or_else(|| {
1187 ParseError::GrammarError("Expected left expression in AND".to_string())
1188 })?)?;
1189
1190 for right_pair in inner {
1191 let right = parse_expression(right_pair)?;
1192 left = Expression::Binary {
1193 left: Box::new(left),
1194 op: BinaryOp::And,
1195 right: Box::new(right),
1196 };
1197 }
1198
1199 Ok(left)
1200}
1201
1202fn parse_not_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1204 let mut inner = pair.into_inner();
1205 let first = inner
1206 .next()
1207 .ok_or_else(|| ParseError::GrammarError("Expected expression in NOT".to_string()))?;
1208
1209 if first.as_rule() == Rule::not_expr {
1211 let expr = parse_expression(first)?;
1213 Ok(Expression::Unary {
1214 op: UnaryOp::Not,
1215 operand: Box::new(expr),
1216 })
1217 } else {
1218 parse_expression(first)
1220 }
1221}
1222
1223fn parse_comparison_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1225 let mut inner = pair.into_inner();
1226 let mut left = parse_expression(inner.next().ok_or_else(|| {
1227 ParseError::GrammarError("Expected left expression in comparison".to_string())
1228 })?)?;
1229
1230 if let Some(op_pair) = inner.next() {
1231 let op = parse_comparison_op(op_pair)?;
1232 let right = parse_expression(inner.next().ok_or_else(|| {
1233 ParseError::GrammarError("Expected right expression in comparison".to_string())
1234 })?)?;
1235 left = Expression::Binary {
1236 left: Box::new(left),
1237 op,
1238 right: Box::new(right),
1239 };
1240 }
1241
1242 Ok(left)
1243}
1244
1245fn parse_comparison_op(pair: Pair<Rule>) -> ParseResult<BinaryOp> {
1247 let op_str = pair.as_str();
1248 match op_str {
1249 "=" => Ok(BinaryOp::Equal),
1250 "!=" => Ok(BinaryOp::NotEqual),
1251 ">" => Ok(BinaryOp::GreaterThan),
1252 "<" => Ok(BinaryOp::LessThan),
1253 ">=" => Ok(BinaryOp::GreaterThanOrEqual),
1254 "<=" => Ok(BinaryOp::LessThanOrEqual),
1255 _ if op_str.eq_ignore_ascii_case("contains") => Ok(BinaryOp::Contains),
1256 _ if op_str.eq_ignore_ascii_case("startswith") => Ok(BinaryOp::StartsWith),
1257 _ if op_str.eq_ignore_ascii_case("endswith") => Ok(BinaryOp::EndsWith),
1258 _ if op_str.eq_ignore_ascii_case("matches") => Ok(BinaryOp::Matches),
1259 _ if op_str.eq_ignore_ascii_case("before") => Ok(BinaryOp::Before),
1260 _ if op_str.eq_ignore_ascii_case("after") => Ok(BinaryOp::After),
1261 _ if op_str.eq_ignore_ascii_case("during") => Ok(BinaryOp::During),
1262 _ if op_str.eq_ignore_ascii_case("has_role") => Ok(BinaryOp::HasRole),
1263 _ => Err(ParseError::InvalidExpression(format!(
1264 "Unknown comparison operator: {}",
1265 op_str
1266 ))),
1267 }
1268}
1269
1270fn parse_additive_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1272 let mut inner = pair.into_inner();
1273 let mut left = parse_expression(inner.next().ok_or_else(|| {
1274 ParseError::GrammarError("Expected left expression in additive".to_string())
1275 })?)?;
1276
1277 while let Some(op_pair) = inner.next() {
1278 let op = match op_pair.as_str() {
1279 "+" => BinaryOp::Plus,
1280 "-" => BinaryOp::Minus,
1281 _ => {
1282 return Err(ParseError::InvalidExpression(
1283 "Invalid additive operator".to_string(),
1284 ))
1285 }
1286 };
1287 let right = parse_expression(inner.next().ok_or_else(|| {
1288 ParseError::GrammarError("Expected right expression in additive".to_string())
1289 })?)?;
1290 left = Expression::Binary {
1291 left: Box::new(left),
1292 op,
1293 right: Box::new(right),
1294 };
1295 }
1296
1297 Ok(left)
1298}
1299
1300fn parse_multiplicative_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1302 let mut inner = pair.into_inner();
1303 let mut left = parse_expression(inner.next().ok_or_else(|| {
1304 ParseError::GrammarError("Expected left expression in multiplicative".to_string())
1305 })?)?;
1306
1307 while let Some(op_pair) = inner.next() {
1308 let op = match op_pair.as_str() {
1309 "*" => BinaryOp::Multiply,
1310 "/" => BinaryOp::Divide,
1311 _ => {
1312 return Err(ParseError::InvalidExpression(
1313 "Invalid multiplicative operator".to_string(),
1314 ))
1315 }
1316 };
1317 let right = parse_expression(inner.next().ok_or_else(|| {
1318 ParseError::GrammarError("Expected right expression in multiplicative".to_string())
1319 })?)?;
1320 left = Expression::Binary {
1321 left: Box::new(left),
1322 op,
1323 right: Box::new(right),
1324 };
1325 }
1326
1327 Ok(left)
1328}
1329
1330fn parse_cast_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1332 let mut inner = pair.into_inner();
1333 let primary = parse_expression(inner.next().ok_or_else(|| {
1334 ParseError::GrammarError("Expected primary expression in cast".to_string())
1335 })?)?;
1336
1337 if let Some(as_pair) = inner.next() {
1338 let target_type = parse_string_literal(as_pair)?;
1339 Ok(Expression::cast(primary, target_type))
1340 } else {
1341 Ok(primary)
1342 }
1343}
1344
1345fn parse_unary_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1347 let mut inner = pair.into_inner();
1348 let first = inner
1349 .next()
1350 .ok_or_else(|| ParseError::GrammarError("Expected expression in unary".to_string()))?;
1351
1352 if first.as_str() == "-" {
1353 let expr = parse_expression(inner.next().ok_or_else(|| {
1355 ParseError::GrammarError("Expected expression after unary minus".to_string())
1356 })?)?;
1357 Ok(Expression::Unary {
1358 op: UnaryOp::Negate,
1359 operand: Box::new(expr),
1360 })
1361 } else {
1362 parse_expression(first)
1363 }
1364}
1365
1366fn parse_primary_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1368 let inner = pair.into_inner().next().ok_or_else(|| {
1369 ParseError::GrammarError("Expected inner expression in primary".to_string())
1370 })?;
1371
1372 match inner.as_rule() {
1373 Rule::expression => parse_expression(inner),
1374 Rule::group_by_expr => parse_group_by_expr(inner),
1375 Rule::aggregation_expr => parse_aggregation_expr(inner),
1376 Rule::quantified_expr => parse_quantified_expr(inner),
1377 Rule::member_access => parse_member_access(inner),
1378 Rule::literal => parse_literal_expr(inner),
1379 Rule::identifier => {
1380 let name = parse_identifier(inner)?;
1381 Ok(Expression::Variable(name))
1382 }
1383 _ => Err(ParseError::InvalidExpression(format!(
1384 "Unexpected primary expression: {:?}",
1385 inner.as_rule()
1386 ))),
1387 }
1388}
1389
1390fn parse_aggregation_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1392 let mut inner = pair.into_inner();
1393
1394 let function_pair = inner.next().ok_or_else(|| {
1395 ParseError::GrammarError(
1396 "Expected aggregate function in aggregation expression".to_string(),
1397 )
1398 })?;
1399 let function = parse_aggregate_fn(function_pair)?;
1400
1401 let collection_pair = inner.next().ok_or_else(|| {
1402 ParseError::GrammarError("Expected collection in aggregation expression".to_string())
1403 })?;
1404
1405 if collection_pair.as_rule() == Rule::aggregation_comprehension {
1408 let mut comp_inner = collection_pair.into_inner();
1410 let variable_pair = comp_inner.next().ok_or_else(|| {
1411 ParseError::GrammarError("Expected variable in aggregation comprehension".to_string())
1412 })?;
1413 let variable = parse_identifier(variable_pair)?;
1414 let collection_token = comp_inner.next().ok_or_else(|| {
1416 ParseError::GrammarError("Expected collection in aggregation comprehension".to_string())
1417 })?;
1418 let collection_name = parse_collection(collection_token)?;
1419 let collection = Box::new(Expression::Variable(collection_name));
1420
1421 let mut next_pair = comp_inner.next().ok_or_else(|| {
1422 ParseError::GrammarError(
1423 "Expected predicate expression, projection, or window in aggregation comprehension"
1424 .to_string(),
1425 )
1426 })?;
1427
1428 let mut window = None;
1429 if next_pair.as_rule() == Rule::window_clause {
1430 window = Some(parse_window_clause(next_pair)?);
1431 next_pair = comp_inner.next().ok_or_else(|| {
1432 ParseError::GrammarError(
1433 "Expected predicate or projection expression in aggregation comprehension"
1434 .to_string(),
1435 )
1436 })?;
1437 }
1438
1439 let remaining_pairs: Vec<Pair<Rule>> =
1440 std::iter::once(next_pair).chain(comp_inner).collect();
1441
1442 let mut expr_pairs: Vec<Pair<Rule>> = Vec::new();
1443 let mut target_unit: Option<String> = None;
1444 for pair in remaining_pairs {
1445 match pair.as_rule() {
1446 Rule::expression => expr_pairs.push(pair),
1447 Rule::string_literal => {
1448 target_unit = Some(parse_string_literal(pair)?);
1449 }
1450 Rule::identifier if pair.as_str().eq_ignore_ascii_case("as") => {
1451 }
1453 other => {
1454 return Err(ParseError::GrammarError(format!(
1455 "Unexpected token {:?} in aggregation comprehension",
1456 other
1457 )))
1458 }
1459 }
1460 }
1461
1462 let (predicate, projection) = match expr_pairs.len() {
1463 2 => {
1464 let mut expr_iter = expr_pairs.into_iter();
1465 let predicate_expr = parse_expression(expr_iter.next().ok_or_else(|| {
1466 ParseError::GrammarError(
1467 "Expected predicate expression in aggregation comprehension".to_string(),
1468 )
1469 })?)?;
1470 let projection_expr = parse_expression(expr_iter.next().ok_or_else(|| {
1471 ParseError::GrammarError(
1472 "Expected projection expression in aggregation comprehension".to_string(),
1473 )
1474 })?)?;
1475 (predicate_expr, projection_expr)
1476 }
1477 1 => {
1478 let projection_expr =
1479 parse_expression(expr_pairs.into_iter().next().ok_or_else(|| {
1480 ParseError::GrammarError(
1481 "Expected projection expression in aggregation comprehension"
1482 .to_string(),
1483 )
1484 })?)?;
1485 (Expression::Literal(JsonValue::Bool(true)), projection_expr)
1486 }
1487 other => {
1488 return Err(ParseError::GrammarError(format!(
1489 "Unexpected number of expressions in aggregation comprehension: {}",
1490 other
1491 )))
1492 }
1493 };
1494
1495 return Ok(Expression::AggregationComprehension {
1496 function,
1497 variable,
1498 collection,
1499 window,
1500 predicate: Box::new(predicate),
1501 projection: Box::new(projection),
1502 target_unit,
1503 });
1504 }
1505
1506 let mut simple_inner = collection_pair.into_inner();
1508
1509 let first_pair = simple_inner.next().ok_or_else(|| {
1511 ParseError::GrammarError(
1512 "Expected collection or identifier in aggregation_simple".to_string(),
1513 )
1514 })?;
1515
1516 let collection = match first_pair.as_rule() {
1517 Rule::collection => parse_collection(first_pair)?,
1518 Rule::identifier => parse_identifier(first_pair)?,
1519 _ => {
1520 return Err(ParseError::GrammarError(format!(
1521 "Expected collection or identifier, got {:?}",
1522 first_pair.as_rule()
1523 )))
1524 }
1525 };
1526
1527 let mut field: Option<String> = None;
1528 let mut filter: Option<Expression> = None;
1529
1530 for item in simple_inner {
1532 match item.as_rule() {
1533 Rule::identifier => {
1534 field = Some(parse_identifier(item)?);
1535 }
1536 Rule::expression => {
1537 filter = Some(parse_expression(item)?);
1538 }
1539 _ => {}
1540 }
1541 }
1542
1543 Ok(Expression::aggregation(
1544 function,
1545 Expression::Variable(collection),
1546 field,
1547 filter,
1548 ))
1549}
1550
1551fn parse_aggregate_fn(pair: Pair<Rule>) -> ParseResult<AggregateFunction> {
1553 let fn_str = pair.as_str();
1554 match fn_str.to_lowercase().as_str() {
1555 "count" => Ok(AggregateFunction::Count),
1556 "sum" => Ok(AggregateFunction::Sum),
1557 "min" => Ok(AggregateFunction::Min),
1558 "max" => Ok(AggregateFunction::Max),
1559 "avg" => Ok(AggregateFunction::Avg),
1560 _ => Err(ParseError::InvalidExpression(format!(
1561 "Unknown aggregate function: {}",
1562 fn_str
1563 ))),
1564 }
1565}
1566
1567fn parse_quantified_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1569 let mut inner = pair.into_inner();
1570
1571 let quantifier = parse_quantifier(inner.next().ok_or_else(|| {
1572 ParseError::GrammarError("Expected quantifier in quantified expression".to_string())
1573 })?)?;
1574 let variable = parse_identifier(inner.next().ok_or_else(|| {
1575 ParseError::GrammarError(
1576 "Expected variable identifier in quantified expression".to_string(),
1577 )
1578 })?)?;
1579 let collection = parse_collection(inner.next().ok_or_else(|| {
1580 ParseError::GrammarError(
1581 "Expected collection identifier in quantified expression".to_string(),
1582 )
1583 })?)?;
1584 let condition = parse_expression(inner.next().ok_or_else(|| {
1585 ParseError::GrammarError("Expected quantified condition expression".to_string())
1586 })?)?;
1587
1588 Ok(Expression::Quantifier {
1589 quantifier,
1590 variable,
1591 collection: Box::new(Expression::Variable(collection)),
1592 condition: Box::new(condition),
1593 })
1594}
1595
1596fn parse_quantifier(pair: Pair<Rule>) -> ParseResult<PolicyQuantifier> {
1598 let q_str = pair.as_str();
1599 match q_str.to_lowercase().as_str() {
1600 "forall" => Ok(PolicyQuantifier::ForAll),
1601 "exists" => Ok(PolicyQuantifier::Exists),
1602 "exists_unique" => Ok(PolicyQuantifier::ExistsUnique),
1603 _ => Err(ParseError::InvalidExpression(format!(
1604 "Unknown quantifier: {}",
1605 q_str
1606 ))),
1607 }
1608}
1609
1610fn parse_collection(pair: Pair<Rule>) -> ParseResult<String> {
1612 Ok(pair.as_str().to_lowercase())
1613}
1614
1615fn parse_member_access(pair: Pair<Rule>) -> ParseResult<Expression> {
1617 let mut inner = pair.into_inner();
1618 let object = parse_identifier(inner.next().ok_or_else(|| {
1619 ParseError::GrammarError("Expected object identifier in member access".to_string())
1620 })?)?;
1621 let member = parse_identifier(inner.next().ok_or_else(|| {
1622 ParseError::GrammarError("Expected member identifier in member access".to_string())
1623 })?)?;
1624
1625 Ok(Expression::MemberAccess { object, member })
1626}
1627
1628fn parse_literal_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1630 let inner = pair
1631 .into_inner()
1632 .next()
1633 .ok_or_else(|| ParseError::GrammarError("Expected literal content".to_string()))?;
1634
1635 match inner.as_rule() {
1636 Rule::string_literal => {
1637 let s = parse_string_literal(inner)?;
1638 Ok(Expression::Literal(JsonValue::String(s)))
1639 }
1640 Rule::multiline_string => {
1641 let s = parse_multiline_string(inner)?;
1642 Ok(Expression::Literal(JsonValue::String(s)))
1643 }
1644 Rule::quantity_literal => {
1645 let mut parts = inner.into_inner();
1646 let number_part = parts.next().ok_or_else(|| {
1647 ParseError::GrammarError("Expected number in quantity literal".to_string())
1648 })?;
1649 let unit_part = parts.next().ok_or_else(|| {
1650 ParseError::GrammarError("Expected unit string in quantity literal".to_string())
1651 })?;
1652 let value = parse_decimal(number_part)?;
1653 let unit = parse_string_literal(unit_part)?;
1654 Ok(Expression::QuantityLiteral { value, unit })
1655 }
1656 Rule::time_literal => {
1657 let timestamp = inner.as_str();
1659 let timestamp = timestamp.trim_start_matches('"').trim_end_matches('"');
1661 Ok(Expression::TimeLiteral(timestamp.to_string()))
1662 }
1663 Rule::interval_literal => {
1664 let mut parts = inner.into_inner();
1666 let start_part = parts.next().ok_or_else(|| {
1667 ParseError::GrammarError("Expected start time in interval literal".to_string())
1668 })?;
1669 let end_part = parts.next().ok_or_else(|| {
1670 ParseError::GrammarError("Expected end time in interval literal".to_string())
1671 })?;
1672 let start = parse_string_literal(start_part)?;
1673 let end = parse_string_literal(end_part)?;
1674 Ok(Expression::IntervalLiteral { start, end })
1675 }
1676 Rule::number => {
1677 let n = parse_decimal(inner)?;
1678 let f = n.to_f64().ok_or_else(|| {
1680 ParseError::InvalidQuantity(format!(
1681 "Decimal value {} cannot be represented as f64",
1682 n
1683 ))
1684 })?;
1685 if !f.is_finite() {
1687 return Err(ParseError::InvalidQuantity(format!(
1688 "Decimal value {} converts to non-finite f64: {}",
1689 n, f
1690 )));
1691 }
1692 let num = serde_json::Number::from_f64(f).ok_or_else(|| {
1693 ParseError::InvalidQuantity(format!(
1694 "Cannot create JSON Number from f64 value: {}",
1695 f
1696 ))
1697 })?;
1698 Ok(Expression::Literal(JsonValue::Number(num)))
1699 }
1700 Rule::boolean => {
1701 let b = inner.as_str().eq_ignore_ascii_case("true");
1702 Ok(Expression::Literal(JsonValue::Bool(b)))
1703 }
1704 _ => Err(ParseError::InvalidExpression(format!(
1705 "Unknown literal type: {:?}",
1706 inner.as_rule()
1707 ))),
1708 }
1709}
1710
1711fn parse_name(pair: Pair<Rule>) -> ParseResult<String> {
1713 let inner = pair.into_inner().next().ok_or_else(|| {
1714 ParseError::GrammarError("Expected inner token for name but got empty pair".to_string())
1715 })?;
1716 match inner.as_rule() {
1717 Rule::string_literal => parse_string_literal(inner),
1718 Rule::multiline_string => parse_multiline_string(inner),
1719 _ => Err(ParseError::GrammarError(format!(
1720 "Expected string or multiline string for name, got {:?}",
1721 inner.as_rule()
1722 ))),
1723 }
1724}
1725
1726fn parse_string_literal(pair: Pair<Rule>) -> ParseResult<String> {
1728 let s = pair.as_str();
1729 if s.len() < 2 || !s.starts_with('"') || !s.ends_with('"') {
1730 return Err(ParseError::GrammarError(format!(
1731 "Invalid string literal: {}",
1732 s
1733 )));
1734 }
1735
1736 match serde_json::from_str(s) {
1739 Ok(unescaped) => Ok(unescaped),
1740 Err(e) => Err(ParseError::GrammarError(format!(
1741 "Invalid string literal escape sequences: {} - {}",
1742 s, e
1743 ))),
1744 }
1745}
1746
1747fn parse_multiline_string(pair: Pair<Rule>) -> ParseResult<String> {
1749 let s = pair.as_str();
1750 if s.len() < 6 || !s.starts_with("\"\"\"") || !s.ends_with("\"\"\"") {
1751 return Err(ParseError::GrammarError(format!(
1752 "Invalid multiline string: {}",
1753 s
1754 )));
1755 }
1756
1757 let content = &s[3..s.len() - 3];
1758
1759 let escaped = content
1761 .replace('\\', "\\\\") .replace('"', "\\\"") .replace('\n', "\\n") .replace('\r', "\\r") .replace('\t', "\\t"); let json_string = format!("\"{}\"", escaped);
1769 match serde_json::from_str(&json_string) {
1770 Ok(unescaped) => Ok(unescaped),
1771 Err(e) => Err(ParseError::GrammarError(format!(
1772 "Invalid multiline string escape sequences in '{}': {}",
1773 s, e
1774 ))),
1775 }
1776}
1777
1778fn parse_identifier(pair: Pair<Rule>) -> ParseResult<String> {
1780 Ok(pair.as_str().to_string())
1781}
1782
1783fn parse_version(pair: Pair<Rule>) -> ParseResult<String> {
1785 Ok(pair.as_str().to_string())
1786}
1787
1788fn parse_number(pair: Pair<Rule>) -> ParseResult<i32> {
1790 pair.as_str()
1791 .parse()
1792 .map_err(|_| ParseError::InvalidQuantity(format!("Invalid number: {}", pair.as_str())))
1793}
1794
1795fn parse_decimal(pair: Pair<Rule>) -> ParseResult<Decimal> {
1797 pair.as_str()
1798 .parse()
1799 .map_err(|_| ParseError::InvalidQuantity(format!("Invalid decimal: {}", pair.as_str())))
1800}
1801
1802fn parse_group_by_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1804 let mut inner = pair.into_inner();
1805
1806 let variable_pair = inner
1807 .next()
1808 .ok_or_else(|| ParseError::GrammarError("Expected variable in group_by".to_string()))?;
1809 let variable = parse_identifier(variable_pair)?;
1810
1811 let collection_pair = inner
1812 .next()
1813 .ok_or_else(|| ParseError::GrammarError("Expected collection in group_by".to_string()))?;
1814 let collection_name = parse_collection(collection_pair)?;
1815 let collection = Box::new(Expression::Variable(collection_name));
1816
1817 let next_pair = inner.next().ok_or_else(|| {
1818 ParseError::GrammarError("Expected key or where clause in group_by".to_string())
1819 })?;
1820
1821 let remaining: Vec<Pair<Rule>> = std::iter::once(next_pair).chain(inner).collect();
1823
1824 let (filter_expr, key_expr, condition_expr) = match remaining.len() {
1825 3 => {
1826 let mut iter = remaining.into_iter();
1827 let filter = parse_expression(iter.next().ok_or_else(|| {
1828 ParseError::GrammarError("Expected filter expression in group_by".to_string())
1829 })?)?;
1830 let key = parse_expression(iter.next().ok_or_else(|| {
1831 ParseError::GrammarError("Expected key expression in group_by".to_string())
1832 })?)?;
1833 let condition = parse_expression(iter.next().ok_or_else(|| {
1834 ParseError::GrammarError("Expected condition expression in group_by".to_string())
1835 })?)?;
1836 (Some(filter), key, condition)
1837 }
1838 2 => {
1839 let mut iter = remaining.into_iter();
1840 let key = parse_expression(iter.next().ok_or_else(|| {
1841 ParseError::GrammarError("Expected key expression in group_by".to_string())
1842 })?)?;
1843 let condition = parse_expression(iter.next().ok_or_else(|| {
1844 ParseError::GrammarError("Expected condition expression in group_by".to_string())
1845 })?)?;
1846 (None, key, condition)
1847 }
1848 other => {
1849 return Err(ParseError::GrammarError(format!(
1850 "Unexpected number of expressions in group_by: {}",
1851 other
1852 )))
1853 }
1854 };
1855
1856 Ok(Expression::GroupBy {
1857 variable,
1858 collection,
1859 filter: filter_expr.map(Box::new),
1860 key: Box::new(key_expr),
1861 condition: Box::new(condition_expr),
1862 })
1863}
1864
1865fn parse_window_clause(pair: Pair<Rule>) -> ParseResult<WindowSpec> {
1867 let mut inner = pair.into_inner();
1868
1869 let duration_pair = inner.next().ok_or_else(|| {
1870 ParseError::GrammarError("Expected duration in window clause".to_string())
1871 })?;
1872 let duration_i32 = parse_number(duration_pair)?;
1873 if duration_i32 < 0 {
1874 return Err(ParseError::InvalidQuantity(
1875 "Window duration must be non-negative".to_string(),
1876 ));
1877 }
1878 let duration = duration_i32 as u64;
1879
1880 let unit_pair = inner
1881 .next()
1882 .ok_or_else(|| ParseError::GrammarError("Expected unit in window clause".to_string()))?;
1883 let unit = parse_string_literal(unit_pair)?;
1884
1885 Ok(WindowSpec { duration, unit })
1886}
1887
1888fn expression_kind(expr: &Expression) -> &'static str {
1889 match expr {
1890 Expression::Literal(_) => "literal",
1891 Expression::QuantityLiteral { .. } => "quantity_literal",
1892 Expression::TimeLiteral(_) => "time_literal",
1893 Expression::IntervalLiteral { .. } => "interval_literal",
1894 Expression::Variable(_) => "variable",
1895 Expression::GroupBy { .. } => "group_by",
1896 Expression::Binary { .. } => "binary",
1897 Expression::Unary { .. } => "unary",
1898 Expression::Cast { .. } => "cast",
1899 Expression::Quantifier { .. } => "quantifier",
1900 Expression::MemberAccess { .. } => "member_access",
1901 Expression::Aggregation { .. } => "aggregation",
1902 Expression::AggregationComprehension { .. } => "aggregation_comprehension",
1903 }
1904}
1905
1906fn expression_to_json(expr: &Expression) -> ParseResult<JsonValue> {
1908 match expr {
1909 Expression::Literal(v) => Ok(v.clone()),
1910 Expression::Variable(name) => Ok(JsonValue::String(name.clone())),
1911 Expression::QuantityLiteral { value, unit } => Ok(json!({
1912 "value": value.to_string(),
1913 "unit": unit
1914 })),
1915 Expression::TimeLiteral(timestamp) => Ok(JsonValue::String(timestamp.clone())),
1916 _ => Err(ParseError::UnsupportedExpression {
1917 kind: expression_kind(expr).to_string(),
1918 span: None,
1919 }),
1920 }
1921}
1922
1923fn parse_mapping(pair: Pair<Rule>) -> ParseResult<AstNode> {
1925 let mut inner = pair.into_inner();
1926
1927 let name = parse_string_literal(
1928 inner
1929 .next()
1930 .ok_or_else(|| ParseError::GrammarError("Expected mapping name".to_string()))?,
1931 )?;
1932
1933 let target_pair = inner
1934 .next()
1935 .ok_or_else(|| ParseError::GrammarError("Expected target format".to_string()))?;
1936 let target = parse_target_format(target_pair)?;
1937
1938 let mut rules = Vec::new();
1939
1940 for rule_pair in inner {
1941 if rule_pair.as_rule() == Rule::mapping_rule {
1942 rules.push(parse_mapping_rule(rule_pair)?);
1943 }
1944 }
1945
1946 Ok(AstNode::MappingDecl {
1947 name,
1948 target,
1949 rules,
1950 })
1951}
1952
1953fn parse_target_format(pair: Pair<Rule>) -> ParseResult<TargetFormat> {
1954 match pair.as_str().to_lowercase().as_str() {
1955 "calm" => Ok(TargetFormat::Calm),
1956 "kg" => Ok(TargetFormat::Kg),
1957 "sbvr" => Ok(TargetFormat::Sbvr),
1958 "protobuf" | "proto" => Ok(TargetFormat::Protobuf),
1959 _ => Err(ParseError::GrammarError(format!(
1960 "Unknown target format: {}",
1961 pair.as_str()
1962 ))),
1963 }
1964}
1965
1966fn parse_mapping_rule(pair: Pair<Rule>) -> ParseResult<MappingRule> {
1967 let mut inner = pair.into_inner();
1968
1969 let primitive_type = inner
1970 .next()
1971 .ok_or_else(|| ParseError::GrammarError("Expected primitive type".to_string()))?
1972 .as_str()
1973 .to_string();
1974
1975 let primitive_name = parse_string_literal(
1976 inner
1977 .next()
1978 .ok_or_else(|| ParseError::GrammarError("Expected primitive name".to_string()))?,
1979 )?;
1980
1981 let target_structure = inner
1982 .next()
1983 .ok_or_else(|| ParseError::GrammarError("Expected target structure".to_string()))?;
1984
1985 let mut target_inner = target_structure.into_inner();
1986 let target_type = parse_identifier(
1987 target_inner
1988 .next()
1989 .ok_or_else(|| ParseError::GrammarError("Expected target type".to_string()))?,
1990 )?;
1991
1992 let mut fields = HashMap::new();
1993 for field_pair in target_inner {
1994 if field_pair.as_rule() == Rule::mapping_field {
1995 let mut field_inner = field_pair.into_inner();
1996 let key = parse_identifier(
1997 field_inner
1998 .next()
1999 .ok_or_else(|| ParseError::GrammarError("Expected field key".to_string()))?,
2000 )?;
2001 let value_pair = field_inner
2002 .next()
2003 .ok_or_else(|| ParseError::GrammarError("Expected field value".to_string()))?;
2004
2005 let value = match value_pair.as_rule() {
2006 Rule::string_literal => JsonValue::String(parse_string_literal(value_pair)?),
2007 Rule::boolean => JsonValue::Bool(value_pair.as_str().eq_ignore_ascii_case("true")),
2008 Rule::object_literal => parse_object_literal(value_pair)?,
2009 _ => {
2010 return Err(ParseError::GrammarError(
2011 "Unexpected mapping field value".to_string(),
2012 ))
2013 }
2014 };
2015 fields.insert(key, value);
2016 }
2017 }
2018
2019 Ok(MappingRule {
2020 primitive_type,
2021 primitive_name,
2022 target_type,
2023 fields,
2024 })
2025}
2026
2027fn parse_object_literal(pair: Pair<Rule>) -> ParseResult<JsonValue> {
2028 let mut map = serde_json::Map::new();
2029 let mut inner = pair.into_inner();
2030 while let Some(key_pair) = inner.next() {
2031 let key = parse_string_literal(key_pair)?;
2032 let value_pair = inner.next().ok_or_else(|| {
2033 ParseError::GrammarError("Expected value in object literal".to_string())
2034 })?;
2035 let value = parse_annotation_value(value_pair)?;
2036 map.insert(key, value);
2037 }
2038 Ok(JsonValue::Object(map))
2039}
2040
2041fn parse_annotation_value(pair: Pair<Rule>) -> ParseResult<JsonValue> {
2042 match pair.as_rule() {
2043 Rule::annotation_value => {
2044 let mut inner = pair.into_inner();
2045 let value_pair = inner
2046 .next()
2047 .ok_or_else(|| ParseError::GrammarError("Expected annotation value".to_string()))?;
2048 parse_annotation_value(value_pair)
2049 }
2050 Rule::string_literal => Ok(JsonValue::String(parse_string_literal(pair)?)),
2051 Rule::string_array => {
2052 let mut values = Vec::new();
2053 for item in pair.into_inner() {
2054 values.push(JsonValue::String(parse_string_literal(item)?));
2055 }
2056 Ok(JsonValue::Array(values))
2057 }
2058 Rule::boolean => Ok(JsonValue::Bool(pair.as_str().eq_ignore_ascii_case("true"))),
2059 Rule::number => {
2060 let d = parse_decimal(pair)?;
2061 let f = d.to_f64().ok_or_else(|| {
2062 ParseError::InvalidQuantity(format!(
2063 "Decimal value {} cannot be represented as f64",
2064 d
2065 ))
2066 })?;
2067 if !f.is_finite() {
2068 return Err(ParseError::InvalidQuantity(format!(
2069 "Decimal value {} converts to non-finite f64",
2070 d
2071 )));
2072 }
2073 let num = serde_json::Number::from_f64(f).ok_or_else(|| {
2074 ParseError::InvalidQuantity(format!("Cannot create JSON Number from decimal {}", d))
2075 })?;
2076 Ok(JsonValue::Number(num))
2077 }
2078 Rule::object_literal => parse_object_literal(pair),
2079 _ => Err(ParseError::GrammarError(format!(
2080 "Unexpected annotation value: {}",
2081 pair.as_str()
2082 ))),
2083 }
2084}
2085
2086fn parse_projection(pair: Pair<Rule>) -> ParseResult<AstNode> {
2088 let mut inner = pair.into_inner();
2089
2090 let name = parse_string_literal(
2091 inner
2092 .next()
2093 .ok_or_else(|| ParseError::GrammarError("Expected projection name".to_string()))?,
2094 )?;
2095
2096 let target_pair = inner
2097 .next()
2098 .ok_or_else(|| ParseError::GrammarError("Expected target format".to_string()))?;
2099 let target = parse_target_format(target_pair)?;
2100
2101 let mut overrides = Vec::new();
2102
2103 for rule_pair in inner {
2104 if rule_pair.as_rule() == Rule::projection_rule {
2105 overrides.push(parse_projection_rule(rule_pair)?);
2106 }
2107 }
2108
2109 Ok(AstNode::ProjectionDecl {
2110 name,
2111 target,
2112 overrides,
2113 })
2114}
2115
2116fn parse_projection_rule(pair: Pair<Rule>) -> ParseResult<ProjectionOverride> {
2117 let mut inner = pair.into_inner();
2118
2119 let primitive_type = inner
2120 .next()
2121 .ok_or_else(|| ParseError::GrammarError("Expected primitive type".to_string()))?
2122 .as_str()
2123 .to_string();
2124
2125 let primitive_name = parse_string_literal(
2126 inner
2127 .next()
2128 .ok_or_else(|| ParseError::GrammarError("Expected primitive name".to_string()))?,
2129 )?;
2130
2131 let mut fields = HashMap::new();
2132 for field_pair in inner {
2133 if field_pair.as_rule() == Rule::projection_field {
2134 let mut field_inner = field_pair.into_inner();
2135 let key = parse_identifier(
2136 field_inner
2137 .next()
2138 .ok_or_else(|| ParseError::GrammarError("Expected field key".to_string()))?,
2139 )?;
2140 let value_pair = field_inner
2141 .next()
2142 .ok_or_else(|| ParseError::GrammarError("Expected field value".to_string()))?;
2143
2144 let value = match value_pair.as_rule() {
2145 Rule::string_literal => JsonValue::String(parse_string_literal(value_pair)?),
2146 Rule::property_mapping => parse_property_mapping(value_pair)?,
2147 _ => {
2148 return Err(ParseError::GrammarError(
2149 "Unexpected projection field value".to_string(),
2150 ))
2151 }
2152 };
2153 fields.insert(key, value);
2154 }
2155 }
2156
2157 Ok(ProjectionOverride {
2158 primitive_type,
2159 primitive_name,
2160 fields,
2161 })
2162}
2163
2164fn parse_property_mapping(pair: Pair<Rule>) -> ParseResult<JsonValue> {
2165 let mut map = serde_json::Map::new();
2166 let mut inner = pair.into_inner();
2167 while let Some(key_pair) = inner.next() {
2168 let key = parse_string_literal(key_pair)?;
2169 let value_pair = inner.next().ok_or_else(|| {
2170 ParseError::GrammarError("Expected value in property mapping".to_string())
2171 })?;
2172 let value = parse_string_literal(value_pair)?;
2173 map.insert(key, JsonValue::String(value));
2174 }
2175 Ok(JsonValue::Object(map))
2176}
2177
2178fn unwrap_export(spanned: &Spanned<AstNode>) -> &AstNode {
2179 match &spanned.node {
2180 AstNode::Export(inner) => &inner.node,
2181 other => other,
2182 }
2183}
2184
2185pub fn ast_to_graph(ast: Ast) -> ParseResult<Graph> {
2187 ast_to_graph_with_options(ast, &ParseOptions::default())
2188}
2189
2190pub fn ast_to_graph_with_options(mut ast: Ast, options: &ParseOptions) -> ParseResult<Graph> {
2191 use crate::parser::profiles::ProfileRegistry;
2192 let registry = ProfileRegistry::global();
2193 let active_profile = ast
2194 .metadata
2195 .profile
2196 .clone()
2197 .or_else(|| options.active_profile.clone())
2198 .unwrap_or_else(|| "default".to_string());
2199 ast.metadata.profile.get_or_insert(active_profile.clone());
2200
2201 if registry.get(&active_profile).is_none() {
2202 let available = registry.list_names().join(", ");
2203 let message = format!(
2204 "Unknown profile: '{}'. Available profiles: {}",
2205 active_profile, available
2206 );
2207 if options.tolerate_profile_warnings {
2208 log::warn!("{}", message);
2209 } else {
2210 return Err(ParseError::Validation(message));
2211 }
2212 }
2213
2214 let mut graph = Graph::new();
2215 let mut entity_map = HashMap::new();
2216 let mut role_map = HashMap::new();
2217 let mut resource_map = HashMap::new();
2218 let mut relation_map = HashMap::new();
2219
2220 let default_namespace = ast
2221 .metadata
2222 .namespace
2223 .clone()
2224 .or_else(|| options.default_namespace.clone())
2225 .unwrap_or_else(|| "default".to_string());
2226
2227 {
2229 use crate::units::{Dimension, Unit, UnitError, UnitRegistry};
2230 let registry = UnitRegistry::global();
2231 let mut registry = registry.write().map_err(|e| {
2232 ParseError::GrammarError(format!("Failed to lock unit registry: {}", e))
2233 })?;
2234
2235 for node in &ast.declarations {
2236 let node = unwrap_export(node);
2237 match node {
2238 AstNode::Dimension { name } => {
2239 let dim = Dimension::parse(name);
2240 registry.register_dimension(dim);
2241 }
2242 AstNode::UnitDeclaration {
2243 symbol,
2244 dimension,
2245 factor,
2246 base_unit,
2247 } => {
2248 let dim = Dimension::parse(dimension);
2249 let unit = Unit::new(
2250 symbol.clone(),
2251 symbol.clone(),
2252 dim,
2253 *factor,
2254 base_unit.clone(),
2255 );
2256 match registry.get_unit(symbol) {
2257 Ok(existing) => {
2258 if existing != &unit {
2259 return Err(ParseError::GrammarError(format!(
2260 "Conflicting unit '{}' already registered (existing: dimension={}, base_factor={}, base_unit={}; new: dimension={}, base_factor={}, base_unit={})",
2261 symbol,
2262 existing.dimension(),
2263 existing.base_factor(),
2264 existing.base_unit(),
2265 unit.dimension(),
2266 unit.base_factor(),
2267 unit.base_unit(),
2268 )));
2269 }
2270 }
2271 Err(UnitError::UnitNotFound(_)) => {
2272 registry.register(unit).map_err(|e| {
2273 ParseError::GrammarError(format!("Failed to register unit: {}", e))
2274 })?;
2275 }
2276 Err(err) => {
2277 return Err(ParseError::GrammarError(format!(
2278 "Failed to inspect unit '{}': {}",
2279 symbol, err
2280 )));
2281 }
2282 }
2283 }
2284 _ => {}
2285 }
2286 }
2287 }
2288
2289 for node in &ast.declarations {
2291 let node = unwrap_export(node);
2292 if let AstNode::Pattern { name, regex } = node {
2293 let namespace = default_namespace.clone();
2294 let pattern = Pattern::new(name.clone(), namespace, regex.clone())
2295 .map_err(ParseError::GrammarError)?;
2296
2297 graph
2298 .add_pattern(pattern)
2299 .map_err(ParseError::GrammarError)?;
2300 }
2301 }
2302
2303 for node in &ast.declarations {
2305 let node = unwrap_export(node);
2306 if let AstNode::ConceptChange {
2307 name,
2308 from_version,
2309 to_version,
2310 migration_policy,
2311 breaking_change,
2312 } = node
2313 {
2314 let change = ConceptChange::new(
2315 name.clone(),
2316 from_version.clone(),
2317 to_version.clone(),
2318 migration_policy.clone(),
2319 *breaking_change,
2320 );
2321 graph.add_concept_change(change).map_err(|e| {
2322 ParseError::GrammarError(format!("Failed to add concept change: {}", e))
2323 })?;
2324 }
2325 }
2326
2327 for node in &ast.declarations {
2329 let node = unwrap_export(node);
2330 match node {
2331 AstNode::Role { name, domain } => {
2332 if role_map.contains_key(name) {
2333 return Err(ParseError::duplicate_declaration_no_loc(format!(
2334 "Role '{}' already declared",
2335 name
2336 )));
2337 }
2338
2339 let namespace = domain.as_ref().unwrap_or(&default_namespace).clone();
2340 let role = Role::new_with_namespace(name.clone(), namespace);
2341 let role_id = role.id().clone();
2342 graph
2343 .add_role(role)
2344 .map_err(|e| ParseError::GrammarError(format!("Failed to add role: {}", e)))?;
2345 role_map.insert(name.clone(), role_id);
2346 }
2347 AstNode::Entity {
2348 name,
2349 domain,
2350 version,
2351 annotations,
2352 } => {
2353 if entity_map.contains_key(name) {
2354 return Err(ParseError::duplicate_declaration_no_loc(format!(
2355 "Entity '{}' already declared",
2356 name
2357 )));
2358 }
2359
2360 let namespace = domain.as_ref().unwrap_or(&default_namespace).clone();
2361 let mut entity = Entity::new_with_namespace(name.clone(), namespace);
2362
2363 if let Some(v_str) = version {
2364 let sem_ver = SemanticVersion::parse(v_str).map_err(|e| {
2365 ParseError::GrammarError(format!(
2366 "Invalid entity version '{}': {}",
2367 v_str, e
2368 ))
2369 })?;
2370 entity = entity.with_version(sem_ver);
2371 }
2372
2373 if let Some(replaces_val) = annotations.get("replaces") {
2374 if let Some(replaces_str) = replaces_val.as_str() {
2375 entity = entity.with_replaces(replaces_str.to_string());
2376 }
2377 }
2378
2379 if let Some(changes_val) = annotations.get("changes") {
2380 if let Some(changes_arr) = changes_val.as_array() {
2381 let changes: Vec<String> = changes_arr
2382 .iter()
2383 .filter_map(|v| v.as_str().map(|s| s.to_string()))
2384 .collect();
2385 entity = entity.with_changes(changes);
2386 }
2387 }
2388
2389 let entity_id = entity.id().clone();
2390 graph.add_entity(entity).map_err(|e| {
2391 ParseError::GrammarError(format!("Failed to add entity: {}", e))
2392 })?;
2393 entity_map.insert(name.clone(), entity_id);
2394 }
2395 AstNode::Resource {
2396 name,
2397 unit_name,
2398 domain,
2399 ..
2400 } => {
2401 if resource_map.contains_key(name) {
2402 return Err(ParseError::duplicate_declaration_no_loc(format!(
2403 "Resource '{}' already declared",
2404 name
2405 )));
2406 }
2407
2408 let namespace = domain.as_ref().unwrap_or(&default_namespace).clone();
2409 let unit = unit_from_string(unit_name.as_deref().unwrap_or("units"));
2410 let resource = Resource::new_with_namespace(name.clone(), unit, namespace);
2411 let resource_id = resource.id().clone();
2412 graph.add_resource(resource).map_err(|e| {
2413 ParseError::GrammarError(format!("Failed to add resource: {}", e))
2414 })?;
2415 resource_map.insert(name.clone(), resource_id);
2416 }
2417 _ => {}
2418 }
2419 }
2420
2421 for node in &ast.declarations {
2423 let node = unwrap_export(node);
2424 if let AstNode::Flow {
2425 resource_name,
2426 from_entity,
2427 to_entity,
2428 quantity,
2429 ..
2430 } = node
2431 {
2432 let from_id = entity_map
2433 .get(from_entity)
2434 .ok_or_else(|| ParseError::undefined_entity_no_loc(from_entity))?;
2435
2436 let to_id = entity_map
2437 .get(to_entity)
2438 .ok_or_else(|| ParseError::undefined_entity_no_loc(to_entity))?;
2439
2440 let resource_id = resource_map
2441 .get(resource_name)
2442 .ok_or_else(|| ParseError::undefined_resource_no_loc(resource_name))?;
2443
2444 let qty = quantity.map(Decimal::from).unwrap_or(Decimal::ZERO);
2445 let flow = Flow::new(resource_id.clone(), from_id.clone(), to_id.clone(), qty);
2446
2447 graph
2448 .add_flow(flow)
2449 .map_err(|e| ParseError::GrammarError(format!("Failed to add flow: {}", e)))?;
2450 }
2451 }
2452
2453 for node in &ast.declarations {
2455 let node = unwrap_export(node);
2456 if let AstNode::Relation {
2457 name,
2458 subject_role,
2459 predicate,
2460 object_role,
2461 via_flow,
2462 } = node
2463 {
2464 if relation_map.contains_key(name) {
2465 return Err(ParseError::duplicate_declaration_no_loc(format!(
2466 "Relation '{}' already declared",
2467 name
2468 )));
2469 }
2470
2471 let subject_id = role_map.get(subject_role).ok_or_else(|| {
2472 ParseError::GrammarError(format!("Undefined subject role '{}'", subject_role))
2473 })?;
2474
2475 let object_id = role_map.get(object_role).ok_or_else(|| {
2476 ParseError::GrammarError(format!("Undefined object role '{}'", object_role))
2477 })?;
2478
2479 let via_flow_id = if let Some(flow_name) = via_flow {
2480 Some(
2481 resource_map
2482 .get(flow_name)
2483 .cloned()
2484 .ok_or_else(|| ParseError::undefined_resource_no_loc(flow_name))?,
2485 )
2486 } else {
2487 None
2488 };
2489
2490 let relation = RelationType::new(
2491 name.clone(),
2492 default_namespace.clone(),
2493 subject_id.clone(),
2494 predicate.clone(),
2495 object_id.clone(),
2496 via_flow_id,
2497 );
2498
2499 let relation_id = relation.id().clone();
2500 graph.add_relation_type(relation).map_err(|e| {
2501 ParseError::GrammarError(format!("Failed to add relation '{}': {}", name, e))
2502 })?;
2503 relation_map.insert(name.clone(), relation_id);
2504 }
2505 }
2506
2507 for node in &ast.declarations {
2509 let node = unwrap_export(node);
2510 if let AstNode::Instance {
2511 name,
2512 entity_type,
2513 fields,
2514 } = node
2515 {
2516 let namespace = default_namespace.clone();
2517 let mut instance = crate::primitives::Instance::new_with_namespace(
2518 name.clone(),
2519 entity_type.clone(),
2520 namespace,
2521 );
2522
2523 for (field_name, field_expr) in fields {
2525 let value = expression_to_json(field_expr)?;
2526 instance.set_field(field_name.clone(), value);
2527 }
2528
2529 graph.add_entity_instance(instance).map_err(|e| {
2530 ParseError::GrammarError(format!("Failed to add entity instance '{}': {}", name, e))
2531 })?;
2532 }
2533 }
2534
2535 for node in &ast.declarations {
2537 let node = unwrap_export(node);
2538 if let AstNode::Policy {
2539 name,
2540 version,
2541 metadata,
2542 expression,
2543 } = node
2544 {
2545 let namespace = ast
2546 .metadata
2547 .namespace
2548 .as_ref()
2549 .cloned()
2550 .or_else(|| options.default_namespace.clone())
2551 .unwrap_or_else(|| "default".to_string());
2552
2553 let kind = metadata.kind.as_ref().map(|kind| match kind {
2554 PolicyKind::Constraint => CorePolicyKind::Constraint,
2555 PolicyKind::Derivation => CorePolicyKind::Derivation,
2556 PolicyKind::Obligation => CorePolicyKind::Obligation,
2557 });
2558
2559 let modality = metadata.modality.as_ref().map(|modality| match modality {
2560 PolicyModality::Obligation => CorePolicyModality::Obligation,
2561 PolicyModality::Prohibition => CorePolicyModality::Prohibition,
2562 PolicyModality::Permission => CorePolicyModality::Permission,
2563 });
2564
2565 let mut policy =
2566 Policy::new_with_namespace(name.clone(), namespace, expression.clone())
2567 .with_metadata(
2568 kind,
2569 modality,
2570 metadata.priority,
2571 metadata.rationale.clone(),
2572 metadata.tags.clone(),
2573 );
2574
2575 let version_to_apply = version
2576 .as_ref()
2577 .cloned()
2578 .or_else(|| ast.metadata.version.clone());
2579
2580 if let Some(version_str) = version_to_apply {
2581 let semantic_version = SemanticVersion::parse(&version_str).map_err(|err| {
2582 ParseError::GrammarError(format!(
2583 "Invalid policy version '{}': {}",
2584 version_str, err
2585 ))
2586 })?;
2587 policy = policy.with_version(semantic_version);
2588 }
2589
2590 graph.add_policy(policy).map_err(|e| {
2591 ParseError::GrammarError(format!("Failed to add policy '{}': {}", name, e))
2592 })?;
2593 }
2594 }
2595
2596 for node in &ast.declarations {
2598 let node = unwrap_export(node);
2599 if let AstNode::Metric {
2600 name,
2601 expression,
2602 metadata,
2603 } = node
2604 {
2605 let namespace = ast
2606 .metadata
2607 .namespace
2608 .as_ref()
2609 .cloned()
2610 .or_else(|| options.default_namespace.clone())
2611 .unwrap_or_else(|| "default".to_string());
2612
2613 let mut metric =
2614 crate::primitives::Metric::new(name.clone(), namespace, expression.clone());
2615
2616 if let Some(duration) = metadata.refresh_interval {
2617 metric = metric.with_refresh_interval(duration);
2618 }
2619
2620 if let Some(unit) = &metadata.unit {
2621 metric = metric.with_unit(unit.clone());
2622 }
2623
2624 if let Some(threshold) = metadata.threshold {
2625 metric = metric.with_threshold(threshold);
2626 }
2627
2628 if let Some(severity) = metadata.severity.clone() {
2629 metric = metric.with_severity(severity);
2630 }
2631
2632 if let Some(target) = metadata.target {
2633 metric = metric.with_target(target);
2634 }
2635
2636 if let Some(duration) = metadata.window {
2637 metric = metric.with_window(duration);
2638 }
2639
2640 graph.add_metric(metric).map_err(|e| {
2641 ParseError::GrammarError(format!("Failed to add metric '{}': {}", name, e))
2642 })?;
2643 }
2644 }
2645
2646 for node in &ast.declarations {
2648 let node = unwrap_export(node);
2649 if let AstNode::MappingDecl {
2650 name,
2651 target,
2652 rules,
2653 } = node
2654 {
2655 let namespace = ast
2656 .metadata
2657 .namespace
2658 .clone()
2659 .or_else(|| options.default_namespace.clone())
2660 .unwrap_or_else(|| "default".to_string());
2661 let mapping = crate::primitives::MappingContract::new(
2662 crate::ConceptId::from_concept(&namespace, name),
2663 name.clone(),
2664 namespace,
2665 target.clone(),
2666 rules.clone(),
2667 );
2668 graph
2669 .add_mapping(mapping)
2670 .map_err(|e| ParseError::GrammarError(format!("Failed to add mapping: {}", e)))?;
2671 }
2672 }
2673
2674 for node in &ast.declarations {
2676 let node = unwrap_export(node);
2677 if let AstNode::ProjectionDecl {
2678 name,
2679 target,
2680 overrides,
2681 } = node
2682 {
2683 let namespace = ast
2684 .metadata
2685 .namespace
2686 .clone()
2687 .or_else(|| options.default_namespace.clone())
2688 .unwrap_or_else(|| "default".to_string());
2689 let projection = crate::primitives::ProjectionContract::new(
2690 crate::ConceptId::from_concept(&namespace, name),
2691 name.clone(),
2692 namespace,
2693 target.clone(),
2694 overrides.clone(),
2695 );
2696 graph.add_projection(projection).map_err(|e| {
2697 ParseError::GrammarError(format!("Failed to add projection: {}", e))
2698 })?;
2699 }
2700 }
2701
2702 Ok(graph)
2703}
2704
2705fn parse_metric(pair: Pair<Rule>) -> ParseResult<AstNode> {
2707 let mut inner = pair.into_inner();
2708
2709 let name = parse_name(
2710 inner
2711 .next()
2712 .ok_or_else(|| ParseError::GrammarError("Expected metric name".to_string()))?,
2713 )?;
2714
2715 let mut metadata = MetricMetadata {
2716 refresh_interval: None,
2717 unit: None,
2718 threshold: None,
2719 severity: None,
2720 target: None,
2721 window: None,
2722 };
2723
2724 let mut expression_pair = None;
2725
2726 for part in inner {
2727 match part.as_rule() {
2728 Rule::metric_annotation => {
2729 let mut annotation_inner = part.into_inner();
2730 let key_pair = annotation_inner.next().ok_or_else(|| {
2731 ParseError::GrammarError("Expected annotation key".to_string())
2732 })?;
2733
2734 match key_pair.as_rule() {
2735 Rule::ma_refresh_interval => {
2736 let value_pair = annotation_inner.next().ok_or_else(|| {
2737 ParseError::GrammarError("Expected refresh interval value".to_string())
2738 })?;
2739 let value = parse_number_i64(value_pair)?;
2740 let unit_pair = annotation_inner.next().ok_or_else(|| {
2741 ParseError::GrammarError("Expected refresh interval unit".to_string())
2742 })?;
2743 let unit = parse_string_literal(unit_pair.clone())?;
2744 let duration = parse_duration_with_unit(value, &unit, unit_pair.as_span())?;
2745 metadata.refresh_interval = Some(duration);
2746 }
2747 Rule::ma_unit => {
2748 let unit_pair = annotation_inner
2749 .next()
2750 .ok_or_else(|| ParseError::GrammarError("Expected unit".to_string()))?;
2751 metadata.unit = Some(parse_string_literal(unit_pair)?);
2752 }
2753 Rule::ma_threshold => {
2754 let value_pair = annotation_inner.next().ok_or_else(|| {
2755 ParseError::GrammarError("Expected threshold value".to_string())
2756 })?;
2757 metadata.threshold = Some(parse_decimal(value_pair)?);
2758 }
2759 Rule::ma_severity => {
2760 let severity_pair = annotation_inner.next().ok_or_else(|| {
2761 ParseError::GrammarError("Expected severity".to_string())
2762 })?;
2763 let severity_str = parse_string_literal(severity_pair.clone())?;
2764 let severity =
2765 parse_severity_value(&severity_str, severity_pair.as_span())?;
2766 metadata.severity = Some(severity);
2767 }
2768 Rule::ma_target => {
2769 let value_pair = annotation_inner.next().ok_or_else(|| {
2770 ParseError::GrammarError("Expected target value".to_string())
2771 })?;
2772 metadata.target = Some(parse_decimal(value_pair)?);
2773 }
2774 Rule::ma_window => {
2775 let value_pair = annotation_inner.next().ok_or_else(|| {
2776 ParseError::GrammarError("Expected window value".to_string())
2777 })?;
2778 let value = parse_number_i64(value_pair)?;
2779 let unit_pair = annotation_inner.next().ok_or_else(|| {
2780 ParseError::GrammarError("Expected window unit".to_string())
2781 })?;
2782 let unit = parse_string_literal(unit_pair.clone())?;
2783 let duration = parse_duration_with_unit(value, &unit, unit_pair.as_span())?;
2784 metadata.window = Some(duration);
2785 }
2786 _ => {
2787 let (line, column) = key_pair.as_span().start_pos().line_col();
2788 return Err(ParseError::GrammarError(format!(
2789 "Unknown metric annotation '{}' at {}:{}",
2790 key_pair.as_str(),
2791 line,
2792 column
2793 )));
2794 }
2795 }
2796 }
2797 Rule::expression => {
2798 expression_pair = Some(part);
2799 }
2800 _ => {}
2801 }
2802 }
2803
2804 let expression = parse_expression(
2805 expression_pair
2806 .ok_or_else(|| ParseError::GrammarError("Expected metric expression".to_string()))?,
2807 )?;
2808
2809 Ok(AstNode::Metric {
2810 name,
2811 expression,
2812 metadata,
2813 })
2814}
2815
2816fn parse_duration_with_unit(value: i64, unit: &str, span: Span<'_>) -> ParseResult<Duration> {
2817 let normalized_unit = unit.to_ascii_lowercase();
2818 let multiplier = match normalized_unit.as_str() {
2819 "second" => Some(1),
2820 "seconds" | "s" => Some(1),
2821 "minute" => Some(60),
2822 "minutes" | "m" => Some(60),
2823 "hour" => Some(60 * 60),
2824 "hours" | "h" => Some(60 * 60),
2825 "day" => Some(60 * 60 * 24),
2826 "days" | "d" => Some(60 * 60 * 24),
2827 _ => None,
2828 }
2829 .ok_or_else(|| {
2830 let (line, column) = span.start_pos().line_col();
2831 ParseError::GrammarError(format!(
2832 "Invalid duration unit '{}' at {}:{} (allowed: second(s)/s, minute(s)/m, hour(s)/h, day(s)/d)",
2833 unit, line, column
2834 ))
2835 })?;
2836
2837 let total_seconds = value.checked_mul(multiplier).ok_or_else(|| {
2838 let (line, column) = span.start_pos().line_col();
2839 ParseError::GrammarError(format!(
2840 "Duration overflow for value {} {} at {}:{}",
2841 value, unit, line, column
2842 ))
2843 })?;
2844
2845 Ok(Duration::seconds(total_seconds))
2846}
2847
2848fn parse_severity_value(value: &str, span: Span<'_>) -> ParseResult<Severity> {
2849 let normalized = value.to_ascii_lowercase();
2850 match normalized.as_str() {
2851 "info" => Ok(Severity::Info),
2852 "warning" => Ok(Severity::Warning),
2853 "error" => Ok(Severity::Error),
2854 "critical" => Ok(Severity::Critical),
2855 _ => {
2856 let (line, column) = span.start_pos().line_col();
2857 Err(ParseError::GrammarError(format!(
2858 "Unknown severity '{}' at {}:{} (expected one of: info, warning, error, critical)",
2859 value, line, column
2860 )))
2861 }
2862 }
2863}
2864
2865fn parse_number_i64(pair: Pair<Rule>) -> ParseResult<i64> {
2866 let s = pair.as_str();
2867 s.parse::<i64>()
2868 .map_err(|_| ParseError::GrammarError(format!("Invalid integer: {}", s)))
2869}