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 parse_expression(pair)
994}
995
996fn parse_or_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
998 let mut inner = pair.into_inner();
999 let mut left =
1000 parse_expression(inner.next().ok_or_else(|| {
1001 ParseError::GrammarError("Expected left expression in OR".to_string())
1002 })?)?;
1003
1004 for right_pair in inner {
1005 let right = parse_expression(right_pair)?;
1006 left = Expression::Binary {
1007 left: Box::new(left),
1008 op: BinaryOp::Or,
1009 right: Box::new(right),
1010 };
1011 }
1012
1013 Ok(left)
1014}
1015
1016fn parse_and_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1018 let mut inner = pair.into_inner();
1019 let mut left =
1020 parse_expression(inner.next().ok_or_else(|| {
1021 ParseError::GrammarError("Expected left expression in AND".to_string())
1022 })?)?;
1023
1024 for right_pair in inner {
1025 let right = parse_expression(right_pair)?;
1026 left = Expression::Binary {
1027 left: Box::new(left),
1028 op: BinaryOp::And,
1029 right: Box::new(right),
1030 };
1031 }
1032
1033 Ok(left)
1034}
1035
1036fn parse_not_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1038 let mut inner = pair.into_inner();
1039 let first = inner
1040 .next()
1041 .ok_or_else(|| ParseError::GrammarError("Expected expression in NOT".to_string()))?;
1042
1043 if first.as_rule() == Rule::not_expr {
1045 let expr = parse_expression(first)?;
1047 Ok(Expression::Unary {
1048 op: UnaryOp::Not,
1049 operand: Box::new(expr),
1050 })
1051 } else {
1052 parse_expression(first)
1054 }
1055}
1056
1057fn parse_comparison_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1059 let mut inner = pair.into_inner();
1060 let mut left = parse_expression(inner.next().ok_or_else(|| {
1061 ParseError::GrammarError("Expected left expression in comparison".to_string())
1062 })?)?;
1063
1064 if let Some(op_pair) = inner.next() {
1065 let op = parse_comparison_op(op_pair)?;
1066 let right = parse_expression(inner.next().ok_or_else(|| {
1067 ParseError::GrammarError("Expected right expression in comparison".to_string())
1068 })?)?;
1069 left = Expression::Binary {
1070 left: Box::new(left),
1071 op,
1072 right: Box::new(right),
1073 };
1074 }
1075
1076 Ok(left)
1077}
1078
1079fn parse_comparison_op(pair: Pair<Rule>) -> ParseResult<BinaryOp> {
1081 let op_str = pair.as_str();
1082 match op_str {
1083 "=" => Ok(BinaryOp::Equal),
1084 "!=" => Ok(BinaryOp::NotEqual),
1085 ">" => Ok(BinaryOp::GreaterThan),
1086 "<" => Ok(BinaryOp::LessThan),
1087 ">=" => Ok(BinaryOp::GreaterThanOrEqual),
1088 "<=" => Ok(BinaryOp::LessThanOrEqual),
1089 _ if op_str.eq_ignore_ascii_case("contains") => Ok(BinaryOp::Contains),
1090 _ if op_str.eq_ignore_ascii_case("startswith") => Ok(BinaryOp::StartsWith),
1091 _ if op_str.eq_ignore_ascii_case("endswith") => Ok(BinaryOp::EndsWith),
1092 _ if op_str.eq_ignore_ascii_case("matches") => Ok(BinaryOp::Matches),
1093 _ if op_str.eq_ignore_ascii_case("before") => Ok(BinaryOp::Before),
1094 _ if op_str.eq_ignore_ascii_case("after") => Ok(BinaryOp::After),
1095 _ if op_str.eq_ignore_ascii_case("during") => Ok(BinaryOp::During),
1096 _ if op_str.eq_ignore_ascii_case("has_role") => Ok(BinaryOp::HasRole),
1097 _ => Err(ParseError::InvalidExpression(format!(
1098 "Unknown comparison operator: {}",
1099 op_str
1100 ))),
1101 }
1102}
1103
1104fn parse_additive_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1106 let mut inner = pair.into_inner();
1107 let mut left = parse_expression(inner.next().ok_or_else(|| {
1108 ParseError::GrammarError("Expected left expression in additive".to_string())
1109 })?)?;
1110
1111 while let Some(op_pair) = inner.next() {
1112 let op = match op_pair.as_str() {
1113 "+" => BinaryOp::Plus,
1114 "-" => BinaryOp::Minus,
1115 _ => {
1116 return Err(ParseError::InvalidExpression(
1117 "Invalid additive operator".to_string(),
1118 ))
1119 }
1120 };
1121 let right = parse_expression(inner.next().ok_or_else(|| {
1122 ParseError::GrammarError("Expected right expression in additive".to_string())
1123 })?)?;
1124 left = Expression::Binary {
1125 left: Box::new(left),
1126 op,
1127 right: Box::new(right),
1128 };
1129 }
1130
1131 Ok(left)
1132}
1133
1134fn parse_multiplicative_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1136 let mut inner = pair.into_inner();
1137 let mut left = parse_expression(inner.next().ok_or_else(|| {
1138 ParseError::GrammarError("Expected left expression in multiplicative".to_string())
1139 })?)?;
1140
1141 while let Some(op_pair) = inner.next() {
1142 let op = match op_pair.as_str() {
1143 "*" => BinaryOp::Multiply,
1144 "/" => BinaryOp::Divide,
1145 _ => {
1146 return Err(ParseError::InvalidExpression(
1147 "Invalid multiplicative operator".to_string(),
1148 ))
1149 }
1150 };
1151 let right = parse_expression(inner.next().ok_or_else(|| {
1152 ParseError::GrammarError("Expected right expression in multiplicative".to_string())
1153 })?)?;
1154 left = Expression::Binary {
1155 left: Box::new(left),
1156 op,
1157 right: Box::new(right),
1158 };
1159 }
1160
1161 Ok(left)
1162}
1163
1164fn parse_cast_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1166 let mut inner = pair.into_inner();
1167 let primary = parse_expression(inner.next().ok_or_else(|| {
1168 ParseError::GrammarError("Expected primary expression in cast".to_string())
1169 })?)?;
1170
1171 if let Some(as_pair) = inner.next() {
1172 let target_type = parse_string_literal(as_pair)?;
1173 Ok(Expression::cast(primary, target_type))
1174 } else {
1175 Ok(primary)
1176 }
1177}
1178
1179fn parse_unary_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1181 let mut inner = pair.into_inner();
1182 let first = inner
1183 .next()
1184 .ok_or_else(|| ParseError::GrammarError("Expected expression in unary".to_string()))?;
1185
1186 if first.as_str() == "-" {
1187 let expr = parse_expression(inner.next().ok_or_else(|| {
1189 ParseError::GrammarError("Expected expression after unary minus".to_string())
1190 })?)?;
1191 Ok(Expression::Unary {
1192 op: UnaryOp::Negate,
1193 operand: Box::new(expr),
1194 })
1195 } else {
1196 parse_expression(first)
1197 }
1198}
1199
1200fn parse_primary_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1202 let inner = pair.into_inner().next().ok_or_else(|| {
1203 ParseError::GrammarError("Expected inner expression in primary".to_string())
1204 })?;
1205
1206 match inner.as_rule() {
1207 Rule::expression => parse_expression(inner),
1208 Rule::group_by_expr => parse_group_by_expr(inner),
1209 Rule::aggregation_expr => parse_aggregation_expr(inner),
1210 Rule::quantified_expr => parse_quantified_expr(inner),
1211 Rule::member_access => parse_member_access(inner),
1212 Rule::literal => parse_literal_expr(inner),
1213 Rule::identifier => {
1214 let name = parse_identifier(inner)?;
1215 Ok(Expression::Variable(name))
1216 }
1217 _ => Err(ParseError::InvalidExpression(format!(
1218 "Unexpected primary expression: {:?}",
1219 inner.as_rule()
1220 ))),
1221 }
1222}
1223
1224fn parse_aggregation_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1226 let mut inner = pair.into_inner();
1227
1228 let function_pair = inner.next().ok_or_else(|| {
1229 ParseError::GrammarError(
1230 "Expected aggregate function in aggregation expression".to_string(),
1231 )
1232 })?;
1233 let function = parse_aggregate_fn(function_pair)?;
1234
1235 let collection_pair = inner.next().ok_or_else(|| {
1236 ParseError::GrammarError("Expected collection in aggregation expression".to_string())
1237 })?;
1238
1239 if collection_pair.as_rule() == Rule::aggregation_comprehension {
1242 let mut comp_inner = collection_pair.into_inner();
1244 let variable_pair = comp_inner.next().ok_or_else(|| {
1245 ParseError::GrammarError("Expected variable in aggregation comprehension".to_string())
1246 })?;
1247 let variable = parse_identifier(variable_pair)?;
1248 let collection_token = comp_inner.next().ok_or_else(|| {
1250 ParseError::GrammarError("Expected collection in aggregation comprehension".to_string())
1251 })?;
1252 let collection_name = parse_collection(collection_token)?;
1253 let collection = Box::new(Expression::Variable(collection_name));
1254
1255 let mut next_pair = comp_inner.next().ok_or_else(|| {
1256 ParseError::GrammarError(
1257 "Expected predicate expression, projection, or window in aggregation comprehension"
1258 .to_string(),
1259 )
1260 })?;
1261
1262 let mut window = None;
1263 if next_pair.as_rule() == Rule::window_clause {
1264 window = Some(parse_window_clause(next_pair)?);
1265 next_pair = comp_inner.next().ok_or_else(|| {
1266 ParseError::GrammarError(
1267 "Expected predicate or projection expression in aggregation comprehension"
1268 .to_string(),
1269 )
1270 })?;
1271 }
1272
1273 let remaining_pairs: Vec<Pair<Rule>> =
1274 std::iter::once(next_pair).chain(comp_inner).collect();
1275
1276 let mut expr_pairs: Vec<Pair<Rule>> = Vec::new();
1277 let mut target_unit: Option<String> = None;
1278 for pair in remaining_pairs {
1279 match pair.as_rule() {
1280 Rule::expression => expr_pairs.push(pair),
1281 Rule::string_literal => {
1282 target_unit = Some(parse_string_literal(pair)?);
1283 }
1284 Rule::identifier if pair.as_str().eq_ignore_ascii_case("as") => {
1285 }
1287 other => {
1288 return Err(ParseError::GrammarError(format!(
1289 "Unexpected token {:?} in aggregation comprehension",
1290 other
1291 )))
1292 }
1293 }
1294 }
1295
1296 let (predicate, projection) = match expr_pairs.len() {
1297 2 => {
1298 let mut expr_iter = expr_pairs.into_iter();
1299 let predicate_expr = parse_expression(expr_iter.next().ok_or_else(|| {
1300 ParseError::GrammarError(
1301 "Expected predicate expression in aggregation comprehension".to_string(),
1302 )
1303 })?)?;
1304 let projection_expr = parse_expression(expr_iter.next().ok_or_else(|| {
1305 ParseError::GrammarError(
1306 "Expected projection expression in aggregation comprehension".to_string(),
1307 )
1308 })?)?;
1309 (predicate_expr, projection_expr)
1310 }
1311 1 => {
1312 let projection_expr =
1313 parse_expression(expr_pairs.into_iter().next().ok_or_else(|| {
1314 ParseError::GrammarError(
1315 "Expected projection expression in aggregation comprehension"
1316 .to_string(),
1317 )
1318 })?)?;
1319 (Expression::Literal(JsonValue::Bool(true)), projection_expr)
1320 }
1321 other => {
1322 return Err(ParseError::GrammarError(format!(
1323 "Unexpected number of expressions in aggregation comprehension: {}",
1324 other
1325 )))
1326 }
1327 };
1328
1329 return Ok(Expression::AggregationComprehension {
1330 function,
1331 variable,
1332 collection,
1333 window,
1334 predicate: Box::new(predicate),
1335 projection: Box::new(projection),
1336 target_unit,
1337 });
1338 }
1339
1340 let mut simple_inner = collection_pair.into_inner();
1342
1343 let first_pair = simple_inner.next().ok_or_else(|| {
1345 ParseError::GrammarError(
1346 "Expected collection or identifier in aggregation_simple".to_string(),
1347 )
1348 })?;
1349
1350 let collection = match first_pair.as_rule() {
1351 Rule::collection => parse_collection(first_pair)?,
1352 Rule::identifier => parse_identifier(first_pair)?,
1353 _ => {
1354 return Err(ParseError::GrammarError(format!(
1355 "Expected collection or identifier, got {:?}",
1356 first_pair.as_rule()
1357 )))
1358 }
1359 };
1360
1361 let mut field: Option<String> = None;
1362 let mut filter: Option<Expression> = None;
1363
1364 for item in simple_inner {
1366 match item.as_rule() {
1367 Rule::identifier => {
1368 field = Some(parse_identifier(item)?);
1369 }
1370 Rule::expression => {
1371 filter = Some(parse_expression(item)?);
1372 }
1373 _ => {}
1374 }
1375 }
1376
1377 Ok(Expression::aggregation(
1378 function,
1379 Expression::Variable(collection),
1380 field,
1381 filter,
1382 ))
1383}
1384
1385fn parse_aggregate_fn(pair: Pair<Rule>) -> ParseResult<AggregateFunction> {
1387 let fn_str = pair.as_str();
1388 match fn_str.to_lowercase().as_str() {
1389 "count" => Ok(AggregateFunction::Count),
1390 "sum" => Ok(AggregateFunction::Sum),
1391 "min" => Ok(AggregateFunction::Min),
1392 "max" => Ok(AggregateFunction::Max),
1393 "avg" => Ok(AggregateFunction::Avg),
1394 _ => Err(ParseError::InvalidExpression(format!(
1395 "Unknown aggregate function: {}",
1396 fn_str
1397 ))),
1398 }
1399}
1400
1401fn parse_quantified_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1403 let mut inner = pair.into_inner();
1404
1405 let quantifier = parse_quantifier(inner.next().ok_or_else(|| {
1406 ParseError::GrammarError("Expected quantifier in quantified expression".to_string())
1407 })?)?;
1408 let variable = parse_identifier(inner.next().ok_or_else(|| {
1409 ParseError::GrammarError(
1410 "Expected variable identifier in quantified expression".to_string(),
1411 )
1412 })?)?;
1413 let collection = parse_collection(inner.next().ok_or_else(|| {
1414 ParseError::GrammarError(
1415 "Expected collection identifier in quantified expression".to_string(),
1416 )
1417 })?)?;
1418 let condition = parse_expression(inner.next().ok_or_else(|| {
1419 ParseError::GrammarError("Expected quantified condition expression".to_string())
1420 })?)?;
1421
1422 Ok(Expression::Quantifier {
1423 quantifier,
1424 variable,
1425 collection: Box::new(Expression::Variable(collection)),
1426 condition: Box::new(condition),
1427 })
1428}
1429
1430fn parse_quantifier(pair: Pair<Rule>) -> ParseResult<PolicyQuantifier> {
1432 let q_str = pair.as_str();
1433 match q_str.to_lowercase().as_str() {
1434 "forall" => Ok(PolicyQuantifier::ForAll),
1435 "exists" => Ok(PolicyQuantifier::Exists),
1436 "exists_unique" => Ok(PolicyQuantifier::ExistsUnique),
1437 _ => Err(ParseError::InvalidExpression(format!(
1438 "Unknown quantifier: {}",
1439 q_str
1440 ))),
1441 }
1442}
1443
1444fn parse_collection(pair: Pair<Rule>) -> ParseResult<String> {
1446 Ok(pair.as_str().to_lowercase())
1447}
1448
1449fn parse_member_access(pair: Pair<Rule>) -> ParseResult<Expression> {
1451 let mut inner = pair.into_inner();
1452 let object = parse_identifier(inner.next().ok_or_else(|| {
1453 ParseError::GrammarError("Expected object identifier in member access".to_string())
1454 })?)?;
1455 let member = parse_identifier(inner.next().ok_or_else(|| {
1456 ParseError::GrammarError("Expected member identifier in member access".to_string())
1457 })?)?;
1458
1459 Ok(Expression::MemberAccess { object, member })
1460}
1461
1462fn parse_literal_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1464 let inner = pair
1465 .into_inner()
1466 .next()
1467 .ok_or_else(|| ParseError::GrammarError("Expected literal content".to_string()))?;
1468
1469 match inner.as_rule() {
1470 Rule::string_literal => {
1471 let s = parse_string_literal(inner)?;
1472 Ok(Expression::Literal(JsonValue::String(s)))
1473 }
1474 Rule::multiline_string => {
1475 let s = parse_multiline_string(inner)?;
1476 Ok(Expression::Literal(JsonValue::String(s)))
1477 }
1478 Rule::quantity_literal => {
1479 let mut parts = inner.into_inner();
1480 let number_part = parts.next().ok_or_else(|| {
1481 ParseError::GrammarError("Expected number in quantity literal".to_string())
1482 })?;
1483 let unit_part = parts.next().ok_or_else(|| {
1484 ParseError::GrammarError("Expected unit string in quantity literal".to_string())
1485 })?;
1486 let value = parse_decimal(number_part)?;
1487 let unit = parse_string_literal(unit_part)?;
1488 Ok(Expression::QuantityLiteral { value, unit })
1489 }
1490 Rule::time_literal => {
1491 let timestamp = inner.as_str();
1493 let timestamp = timestamp.trim_start_matches('"').trim_end_matches('"');
1495 Ok(Expression::TimeLiteral(timestamp.to_string()))
1496 }
1497 Rule::interval_literal => {
1498 let mut parts = inner.into_inner();
1500 let start_part = parts.next().ok_or_else(|| {
1501 ParseError::GrammarError("Expected start time in interval literal".to_string())
1502 })?;
1503 let end_part = parts.next().ok_or_else(|| {
1504 ParseError::GrammarError("Expected end time in interval literal".to_string())
1505 })?;
1506 let start = parse_string_literal(start_part)?;
1507 let end = parse_string_literal(end_part)?;
1508 Ok(Expression::IntervalLiteral { start, end })
1509 }
1510 Rule::number => {
1511 let n = parse_decimal(inner)?;
1512 let f = n.to_f64().ok_or_else(|| {
1514 ParseError::InvalidQuantity(format!(
1515 "Decimal value {} cannot be represented as f64",
1516 n
1517 ))
1518 })?;
1519 if !f.is_finite() {
1521 return Err(ParseError::InvalidQuantity(format!(
1522 "Decimal value {} converts to non-finite f64: {}",
1523 n, f
1524 )));
1525 }
1526 let num = serde_json::Number::from_f64(f).ok_or_else(|| {
1527 ParseError::InvalidQuantity(format!(
1528 "Cannot create JSON Number from f64 value: {}",
1529 f
1530 ))
1531 })?;
1532 Ok(Expression::Literal(JsonValue::Number(num)))
1533 }
1534 Rule::boolean => {
1535 let b = inner.as_str().eq_ignore_ascii_case("true");
1536 Ok(Expression::Literal(JsonValue::Bool(b)))
1537 }
1538 _ => Err(ParseError::InvalidExpression(format!(
1539 "Unknown literal type: {:?}",
1540 inner.as_rule()
1541 ))),
1542 }
1543}
1544
1545fn parse_name(pair: Pair<Rule>) -> ParseResult<String> {
1547 let inner = pair.into_inner().next().ok_or_else(|| {
1548 ParseError::GrammarError("Expected inner token for name but got empty pair".to_string())
1549 })?;
1550 match inner.as_rule() {
1551 Rule::string_literal => parse_string_literal(inner),
1552 Rule::multiline_string => parse_multiline_string(inner),
1553 _ => Err(ParseError::GrammarError(format!(
1554 "Expected string or multiline string for name, got {:?}",
1555 inner.as_rule()
1556 ))),
1557 }
1558}
1559
1560fn parse_string_literal(pair: Pair<Rule>) -> ParseResult<String> {
1562 let s = pair.as_str();
1563 if s.len() < 2 || !s.starts_with('"') || !s.ends_with('"') {
1564 return Err(ParseError::GrammarError(format!(
1565 "Invalid string literal: {}",
1566 s
1567 )));
1568 }
1569
1570 match serde_json::from_str(s) {
1573 Ok(unescaped) => Ok(unescaped),
1574 Err(e) => Err(ParseError::GrammarError(format!(
1575 "Invalid string literal escape sequences: {} - {}",
1576 s, e
1577 ))),
1578 }
1579}
1580
1581fn parse_multiline_string(pair: Pair<Rule>) -> ParseResult<String> {
1583 let s = pair.as_str();
1584 if s.len() < 6 || !s.starts_with("\"\"\"") || !s.ends_with("\"\"\"") {
1585 return Err(ParseError::GrammarError(format!(
1586 "Invalid multiline string: {}",
1587 s
1588 )));
1589 }
1590
1591 let content = &s[3..s.len() - 3];
1592
1593 let escaped = content
1595 .replace('\\', "\\\\") .replace('"', "\\\"") .replace('\n', "\\n") .replace('\r', "\\r") .replace('\t', "\\t"); let json_string = format!("\"{}\"", escaped);
1603 match serde_json::from_str(&json_string) {
1604 Ok(unescaped) => Ok(unescaped),
1605 Err(e) => Err(ParseError::GrammarError(format!(
1606 "Invalid multiline string escape sequences in '{}': {}",
1607 s, e
1608 ))),
1609 }
1610}
1611
1612fn parse_identifier(pair: Pair<Rule>) -> ParseResult<String> {
1614 Ok(pair.as_str().to_string())
1615}
1616
1617fn parse_version(pair: Pair<Rule>) -> ParseResult<String> {
1619 Ok(pair.as_str().to_string())
1620}
1621
1622fn parse_number(pair: Pair<Rule>) -> ParseResult<i32> {
1624 pair.as_str()
1625 .parse()
1626 .map_err(|_| ParseError::InvalidQuantity(format!("Invalid number: {}", pair.as_str())))
1627}
1628
1629fn parse_decimal(pair: Pair<Rule>) -> ParseResult<Decimal> {
1631 pair.as_str()
1632 .parse()
1633 .map_err(|_| ParseError::InvalidQuantity(format!("Invalid decimal: {}", pair.as_str())))
1634}
1635
1636fn parse_group_by_expr(pair: Pair<Rule>) -> ParseResult<Expression> {
1638 let mut inner = pair.into_inner();
1639
1640 let variable_pair = inner
1641 .next()
1642 .ok_or_else(|| ParseError::GrammarError("Expected variable in group_by".to_string()))?;
1643 let variable = parse_identifier(variable_pair)?;
1644
1645 let collection_pair = inner
1646 .next()
1647 .ok_or_else(|| ParseError::GrammarError("Expected collection in group_by".to_string()))?;
1648 let collection_name = parse_collection(collection_pair)?;
1649 let collection = Box::new(Expression::Variable(collection_name));
1650
1651 let next_pair = inner.next().ok_or_else(|| {
1652 ParseError::GrammarError("Expected key or where clause in group_by".to_string())
1653 })?;
1654
1655 let remaining: Vec<Pair<Rule>> = std::iter::once(next_pair).chain(inner).collect();
1657
1658 let (filter_expr, key_expr, condition_expr) = match remaining.len() {
1659 3 => {
1660 let mut iter = remaining.into_iter();
1661 let filter = parse_expression(iter.next().ok_or_else(|| {
1662 ParseError::GrammarError("Expected filter expression in group_by".to_string())
1663 })?)?;
1664 let key = parse_expression(iter.next().ok_or_else(|| {
1665 ParseError::GrammarError("Expected key expression in group_by".to_string())
1666 })?)?;
1667 let condition = parse_expression(iter.next().ok_or_else(|| {
1668 ParseError::GrammarError("Expected condition expression in group_by".to_string())
1669 })?)?;
1670 (Some(filter), key, condition)
1671 }
1672 2 => {
1673 let mut iter = remaining.into_iter();
1674 let key = parse_expression(iter.next().ok_or_else(|| {
1675 ParseError::GrammarError("Expected key expression in group_by".to_string())
1676 })?)?;
1677 let condition = parse_expression(iter.next().ok_or_else(|| {
1678 ParseError::GrammarError("Expected condition expression in group_by".to_string())
1679 })?)?;
1680 (None, key, condition)
1681 }
1682 other => {
1683 return Err(ParseError::GrammarError(format!(
1684 "Unexpected number of expressions in group_by: {}",
1685 other
1686 )))
1687 }
1688 };
1689
1690 Ok(Expression::GroupBy {
1691 variable,
1692 collection,
1693 filter: filter_expr.map(Box::new),
1694 key: Box::new(key_expr),
1695 condition: Box::new(condition_expr),
1696 })
1697}
1698
1699fn parse_window_clause(pair: Pair<Rule>) -> ParseResult<WindowSpec> {
1701 let mut inner = pair.into_inner();
1702
1703 let duration_pair = inner.next().ok_or_else(|| {
1704 ParseError::GrammarError("Expected duration in window clause".to_string())
1705 })?;
1706 let duration_i32 = parse_number(duration_pair)?;
1707 if duration_i32 < 0 {
1708 return Err(ParseError::InvalidQuantity(
1709 "Window duration must be non-negative".to_string(),
1710 ));
1711 }
1712 let duration = duration_i32 as u64;
1713
1714 let unit_pair = inner
1715 .next()
1716 .ok_or_else(|| ParseError::GrammarError("Expected unit in window clause".to_string()))?;
1717 let unit = parse_string_literal(unit_pair)?;
1718
1719 Ok(WindowSpec { duration, unit })
1720}
1721
1722fn expression_kind(expr: &Expression) -> &'static str {
1723 match expr {
1724 Expression::Literal(_) => "literal",
1725 Expression::QuantityLiteral { .. } => "quantity_literal",
1726 Expression::TimeLiteral(_) => "time_literal",
1727 Expression::IntervalLiteral { .. } => "interval_literal",
1728 Expression::Variable(_) => "variable",
1729 Expression::GroupBy { .. } => "group_by",
1730 Expression::Binary { .. } => "binary",
1731 Expression::Unary { .. } => "unary",
1732 Expression::Cast { .. } => "cast",
1733 Expression::Quantifier { .. } => "quantifier",
1734 Expression::MemberAccess { .. } => "member_access",
1735 Expression::Aggregation { .. } => "aggregation",
1736 Expression::AggregationComprehension { .. } => "aggregation_comprehension",
1737 }
1738}
1739
1740fn expression_to_json(expr: &Expression) -> ParseResult<JsonValue> {
1742 match expr {
1743 Expression::Literal(v) => Ok(v.clone()),
1744 Expression::Variable(name) => Ok(JsonValue::String(name.clone())),
1745 Expression::QuantityLiteral { value, unit } => Ok(json!({
1746 "value": value.to_string(),
1747 "unit": unit
1748 })),
1749 Expression::TimeLiteral(timestamp) => Ok(JsonValue::String(timestamp.clone())),
1750 _ => Err(ParseError::UnsupportedExpression {
1751 kind: expression_kind(expr).to_string(),
1752 span: None,
1753 }),
1754 }
1755}
1756
1757fn parse_mapping(pair: Pair<Rule>) -> ParseResult<AstNode> {
1759 let mut inner = pair.into_inner();
1760
1761 let name = parse_string_literal(
1762 inner
1763 .next()
1764 .ok_or_else(|| ParseError::GrammarError("Expected mapping name".to_string()))?,
1765 )?;
1766
1767 let target_pair = inner
1768 .next()
1769 .ok_or_else(|| ParseError::GrammarError("Expected target format".to_string()))?;
1770 let target = parse_target_format(target_pair)?;
1771
1772 let mut rules = Vec::new();
1773
1774 for rule_pair in inner {
1775 if rule_pair.as_rule() == Rule::mapping_rule {
1776 rules.push(parse_mapping_rule(rule_pair)?);
1777 }
1778 }
1779
1780 Ok(AstNode::MappingDecl {
1781 name,
1782 target,
1783 rules,
1784 })
1785}
1786
1787fn parse_target_format(pair: Pair<Rule>) -> ParseResult<TargetFormat> {
1788 match pair.as_str().to_lowercase().as_str() {
1789 "calm" => Ok(TargetFormat::Calm),
1790 "kg" => Ok(TargetFormat::Kg),
1791 "sbvr" => Ok(TargetFormat::Sbvr),
1792 "protobuf" | "proto" => Ok(TargetFormat::Protobuf),
1793 _ => Err(ParseError::GrammarError(format!(
1794 "Unknown target format: {}",
1795 pair.as_str()
1796 ))),
1797 }
1798}
1799
1800fn parse_mapping_rule(pair: Pair<Rule>) -> ParseResult<MappingRule> {
1801 let mut inner = pair.into_inner();
1802
1803 let primitive_type = inner
1804 .next()
1805 .ok_or_else(|| ParseError::GrammarError("Expected primitive type".to_string()))?
1806 .as_str()
1807 .to_string();
1808
1809 let primitive_name = parse_string_literal(
1810 inner
1811 .next()
1812 .ok_or_else(|| ParseError::GrammarError("Expected primitive name".to_string()))?,
1813 )?;
1814
1815 let target_structure = inner
1816 .next()
1817 .ok_or_else(|| ParseError::GrammarError("Expected target structure".to_string()))?;
1818
1819 let mut target_inner = target_structure.into_inner();
1820 let target_type = parse_identifier(
1821 target_inner
1822 .next()
1823 .ok_or_else(|| ParseError::GrammarError("Expected target type".to_string()))?,
1824 )?;
1825
1826 let mut fields = HashMap::new();
1827 for field_pair in target_inner {
1828 if field_pair.as_rule() == Rule::mapping_field {
1829 let mut field_inner = field_pair.into_inner();
1830 let key = parse_identifier(
1831 field_inner
1832 .next()
1833 .ok_or_else(|| ParseError::GrammarError("Expected field key".to_string()))?,
1834 )?;
1835 let value_pair = field_inner
1836 .next()
1837 .ok_or_else(|| ParseError::GrammarError("Expected field value".to_string()))?;
1838
1839 let value = match value_pair.as_rule() {
1840 Rule::string_literal => JsonValue::String(parse_string_literal(value_pair)?),
1841 Rule::boolean => JsonValue::Bool(value_pair.as_str().eq_ignore_ascii_case("true")),
1842 Rule::object_literal => parse_object_literal(value_pair)?,
1843 _ => {
1844 return Err(ParseError::GrammarError(
1845 "Unexpected mapping field value".to_string(),
1846 ))
1847 }
1848 };
1849 fields.insert(key, value);
1850 }
1851 }
1852
1853 Ok(MappingRule {
1854 primitive_type,
1855 primitive_name,
1856 target_type,
1857 fields,
1858 })
1859}
1860
1861fn parse_object_literal(pair: Pair<Rule>) -> ParseResult<JsonValue> {
1862 let mut map = serde_json::Map::new();
1863 let mut inner = pair.into_inner();
1864 while let Some(key_pair) = inner.next() {
1865 let key = parse_string_literal(key_pair)?;
1866 let value_pair = inner.next().ok_or_else(|| {
1867 ParseError::GrammarError("Expected value in object literal".to_string())
1868 })?;
1869 let value = match value_pair.as_rule() {
1870 Rule::string_literal => JsonValue::String(parse_string_literal(value_pair)?),
1871 Rule::boolean => JsonValue::Bool(value_pair.as_str().eq_ignore_ascii_case("true")),
1872 Rule::number => {
1873 let d = parse_decimal(value_pair)?;
1874 let f = d.to_f64().ok_or_else(|| {
1876 ParseError::InvalidQuantity(format!(
1877 "Decimal value {} cannot be represented as f64",
1878 d
1879 ))
1880 })?;
1881 if !f.is_finite() {
1882 return Err(ParseError::InvalidQuantity(format!(
1883 "Decimal value {} converts to non-finite f64",
1884 d
1885 )));
1886 }
1887 let num = serde_json::Number::from_f64(f).ok_or_else(|| {
1888 ParseError::InvalidQuantity(format!(
1889 "Cannot create JSON Number from decimal {}",
1890 d
1891 ))
1892 })?;
1893 JsonValue::Number(num)
1894 }
1895 _ => {
1896 return Err(ParseError::GrammarError(
1897 "Unexpected object field value".to_string(),
1898 ))
1899 }
1900 };
1901 map.insert(key, value);
1902 }
1903 Ok(JsonValue::Object(map))
1904}
1905
1906fn parse_projection(pair: Pair<Rule>) -> ParseResult<AstNode> {
1908 let mut inner = pair.into_inner();
1909
1910 let name = parse_string_literal(
1911 inner
1912 .next()
1913 .ok_or_else(|| ParseError::GrammarError("Expected projection name".to_string()))?,
1914 )?;
1915
1916 let target_pair = inner
1917 .next()
1918 .ok_or_else(|| ParseError::GrammarError("Expected target format".to_string()))?;
1919 let target = parse_target_format(target_pair)?;
1920
1921 let mut overrides = Vec::new();
1922
1923 for rule_pair in inner {
1924 if rule_pair.as_rule() == Rule::projection_rule {
1925 overrides.push(parse_projection_rule(rule_pair)?);
1926 }
1927 }
1928
1929 Ok(AstNode::ProjectionDecl {
1930 name,
1931 target,
1932 overrides,
1933 })
1934}
1935
1936fn parse_projection_rule(pair: Pair<Rule>) -> ParseResult<ProjectionOverride> {
1937 let mut inner = pair.into_inner();
1938
1939 let primitive_type = inner
1940 .next()
1941 .ok_or_else(|| ParseError::GrammarError("Expected primitive type".to_string()))?
1942 .as_str()
1943 .to_string();
1944
1945 let primitive_name = parse_string_literal(
1946 inner
1947 .next()
1948 .ok_or_else(|| ParseError::GrammarError("Expected primitive name".to_string()))?,
1949 )?;
1950
1951 let mut fields = HashMap::new();
1952 for field_pair in inner {
1953 if field_pair.as_rule() == Rule::projection_field {
1954 let mut field_inner = field_pair.into_inner();
1955 let key = parse_identifier(
1956 field_inner
1957 .next()
1958 .ok_or_else(|| ParseError::GrammarError("Expected field key".to_string()))?,
1959 )?;
1960 let value_pair = field_inner
1961 .next()
1962 .ok_or_else(|| ParseError::GrammarError("Expected field value".to_string()))?;
1963
1964 let value = match value_pair.as_rule() {
1965 Rule::string_literal => JsonValue::String(parse_string_literal(value_pair)?),
1966 Rule::property_mapping => parse_property_mapping(value_pair)?,
1967 _ => {
1968 return Err(ParseError::GrammarError(
1969 "Unexpected projection field value".to_string(),
1970 ))
1971 }
1972 };
1973 fields.insert(key, value);
1974 }
1975 }
1976
1977 Ok(ProjectionOverride {
1978 primitive_type,
1979 primitive_name,
1980 fields,
1981 })
1982}
1983
1984fn parse_property_mapping(pair: Pair<Rule>) -> ParseResult<JsonValue> {
1985 let mut map = serde_json::Map::new();
1986 let mut inner = pair.into_inner();
1987 while let Some(key_pair) = inner.next() {
1988 let key = parse_string_literal(key_pair)?;
1989 let value_pair = inner.next().ok_or_else(|| {
1990 ParseError::GrammarError("Expected value in property mapping".to_string())
1991 })?;
1992 let value = parse_string_literal(value_pair)?;
1993 map.insert(key, JsonValue::String(value));
1994 }
1995 Ok(JsonValue::Object(map))
1996}
1997
1998fn unwrap_export(node: &AstNode) -> &AstNode {
1999 match node {
2000 AstNode::Export(inner) => inner.as_ref(),
2001 other => other,
2002 }
2003}
2004
2005pub fn ast_to_graph(ast: Ast) -> ParseResult<Graph> {
2007 ast_to_graph_with_options(ast, &ParseOptions::default())
2008}
2009
2010pub fn ast_to_graph_with_options(mut ast: Ast, options: &ParseOptions) -> ParseResult<Graph> {
2011 use crate::parser::profiles::ProfileRegistry;
2012 let registry = ProfileRegistry::global();
2013 let active_profile = ast
2014 .metadata
2015 .profile
2016 .clone()
2017 .or_else(|| options.active_profile.clone())
2018 .unwrap_or_else(|| "default".to_string());
2019 ast.metadata.profile.get_or_insert(active_profile.clone());
2020
2021 if registry.get(&active_profile).is_none() {
2022 let available = registry.list_names().join(", ");
2023 let message = format!(
2024 "Unknown profile: '{}'. Available profiles: {}",
2025 active_profile, available
2026 );
2027 if options.tolerate_profile_warnings {
2028 log::warn!("{}", message);
2029 } else {
2030 return Err(ParseError::Validation(message));
2031 }
2032 }
2033
2034 let mut graph = Graph::new();
2035 let mut entity_map = HashMap::new();
2036 let mut role_map = HashMap::new();
2037 let mut resource_map = HashMap::new();
2038 let mut relation_map = HashMap::new();
2039
2040 let default_namespace = ast
2041 .metadata
2042 .namespace
2043 .clone()
2044 .or_else(|| options.default_namespace.clone())
2045 .unwrap_or_else(|| "default".to_string());
2046
2047 {
2049 use crate::units::{Dimension, Unit, UnitError, UnitRegistry};
2050 let registry = UnitRegistry::global();
2051 let mut registry = registry.write().map_err(|e| {
2052 ParseError::GrammarError(format!("Failed to lock unit registry: {}", e))
2053 })?;
2054
2055 for node in &ast.declarations {
2056 let node = unwrap_export(node);
2057 match node {
2058 AstNode::Dimension { name } => {
2059 let dim = Dimension::parse(name);
2060 registry.register_dimension(dim);
2061 }
2062 AstNode::UnitDeclaration {
2063 symbol,
2064 dimension,
2065 factor,
2066 base_unit,
2067 } => {
2068 let dim = Dimension::parse(dimension);
2069 let unit = Unit::new(
2070 symbol.clone(),
2071 symbol.clone(),
2072 dim,
2073 *factor,
2074 base_unit.clone(),
2075 );
2076 match registry.get_unit(symbol) {
2077 Ok(existing) => {
2078 if existing != &unit {
2079 return Err(ParseError::GrammarError(format!(
2080 "Conflicting unit '{}' already registered (existing: dimension={}, base_factor={}, base_unit={}; new: dimension={}, base_factor={}, base_unit={})",
2081 symbol,
2082 existing.dimension(),
2083 existing.base_factor(),
2084 existing.base_unit(),
2085 unit.dimension(),
2086 unit.base_factor(),
2087 unit.base_unit(),
2088 )));
2089 }
2090 }
2091 Err(UnitError::UnitNotFound(_)) => {
2092 registry.register(unit).map_err(|e| {
2093 ParseError::GrammarError(format!("Failed to register unit: {}", e))
2094 })?;
2095 }
2096 Err(err) => {
2097 return Err(ParseError::GrammarError(format!(
2098 "Failed to inspect unit '{}': {}",
2099 symbol, err
2100 )));
2101 }
2102 }
2103 }
2104 _ => {}
2105 }
2106 }
2107 }
2108
2109 for node in &ast.declarations {
2111 let node = unwrap_export(node);
2112 if let AstNode::Pattern { name, regex } = node {
2113 let namespace = default_namespace.clone();
2114 let pattern = Pattern::new(name.clone(), namespace, regex.clone())
2115 .map_err(ParseError::GrammarError)?;
2116
2117 graph
2118 .add_pattern(pattern)
2119 .map_err(ParseError::GrammarError)?;
2120 }
2121 }
2122
2123 for node in &ast.declarations {
2125 let node = unwrap_export(node);
2126 if let AstNode::ConceptChange {
2127 name,
2128 from_version,
2129 to_version,
2130 migration_policy,
2131 breaking_change,
2132 } = node
2133 {
2134 let change = ConceptChange::new(
2135 name.clone(),
2136 from_version.clone(),
2137 to_version.clone(),
2138 migration_policy.clone(),
2139 *breaking_change,
2140 );
2141 graph.add_concept_change(change).map_err(|e| {
2142 ParseError::GrammarError(format!("Failed to add concept change: {}", e))
2143 })?;
2144 }
2145 }
2146
2147 for node in &ast.declarations {
2149 let node = unwrap_export(node);
2150 match node {
2151 AstNode::Role { name, domain } => {
2152 if role_map.contains_key(name) {
2153 return Err(ParseError::duplicate_declaration(format!(
2154 "Role '{}' already declared",
2155 name
2156 )));
2157 }
2158
2159 let namespace = domain.as_ref().unwrap_or(&default_namespace).clone();
2160 let role = Role::new_with_namespace(name.clone(), namespace);
2161 let role_id = role.id().clone();
2162 graph
2163 .add_role(role)
2164 .map_err(|e| ParseError::GrammarError(format!("Failed to add role: {}", e)))?;
2165 role_map.insert(name.clone(), role_id);
2166 }
2167 AstNode::Entity {
2168 name,
2169 domain,
2170 version,
2171 annotations,
2172 } => {
2173 if entity_map.contains_key(name) {
2174 return Err(ParseError::duplicate_declaration(format!(
2175 "Entity '{}' already declared",
2176 name
2177 )));
2178 }
2179
2180 let namespace = domain.as_ref().unwrap_or(&default_namespace).clone();
2181 let mut entity = Entity::new_with_namespace(name.clone(), namespace);
2182
2183 if let Some(v_str) = version {
2184 let sem_ver = SemanticVersion::parse(v_str).map_err(|e| {
2185 ParseError::GrammarError(format!(
2186 "Invalid entity version '{}': {}",
2187 v_str, e
2188 ))
2189 })?;
2190 entity = entity.with_version(sem_ver);
2191 }
2192
2193 if let Some(replaces_val) = annotations.get("replaces") {
2194 if let Some(replaces_str) = replaces_val.as_str() {
2195 entity = entity.with_replaces(replaces_str.to_string());
2196 }
2197 }
2198
2199 if let Some(changes_val) = annotations.get("changes") {
2200 if let Some(changes_arr) = changes_val.as_array() {
2201 let changes: Vec<String> = changes_arr
2202 .iter()
2203 .filter_map(|v| v.as_str().map(|s| s.to_string()))
2204 .collect();
2205 entity = entity.with_changes(changes);
2206 }
2207 }
2208
2209 let entity_id = entity.id().clone();
2210 graph.add_entity(entity).map_err(|e| {
2211 ParseError::GrammarError(format!("Failed to add entity: {}", e))
2212 })?;
2213 entity_map.insert(name.clone(), entity_id);
2214 }
2215 AstNode::Resource {
2216 name,
2217 unit_name,
2218 domain,
2219 } => {
2220 if resource_map.contains_key(name) {
2221 return Err(ParseError::duplicate_declaration(format!(
2222 "Resource '{}' already declared",
2223 name
2224 )));
2225 }
2226
2227 let namespace = domain.as_ref().unwrap_or(&default_namespace).clone();
2228 let unit = unit_from_string(unit_name.as_deref().unwrap_or("units"));
2229 let resource = Resource::new_with_namespace(name.clone(), unit, namespace);
2230 let resource_id = resource.id().clone();
2231 graph.add_resource(resource).map_err(|e| {
2232 ParseError::GrammarError(format!("Failed to add resource: {}", e))
2233 })?;
2234 resource_map.insert(name.clone(), resource_id);
2235 }
2236 _ => {}
2237 }
2238 }
2239
2240 for node in &ast.declarations {
2242 let node = unwrap_export(node);
2243 if let AstNode::Flow {
2244 resource_name,
2245 from_entity,
2246 to_entity,
2247 quantity,
2248 } = node
2249 {
2250 let from_id = entity_map
2251 .get(from_entity)
2252 .ok_or_else(|| ParseError::undefined_entity(from_entity))?;
2253
2254 let to_id = entity_map
2255 .get(to_entity)
2256 .ok_or_else(|| ParseError::undefined_entity(to_entity))?;
2257
2258 let resource_id = resource_map
2259 .get(resource_name)
2260 .ok_or_else(|| ParseError::undefined_resource(resource_name))?;
2261
2262 let qty = quantity.map(Decimal::from).unwrap_or(Decimal::ZERO);
2263 let flow = Flow::new(resource_id.clone(), from_id.clone(), to_id.clone(), qty);
2264
2265 graph
2266 .add_flow(flow)
2267 .map_err(|e| ParseError::GrammarError(format!("Failed to add flow: {}", e)))?;
2268 }
2269 }
2270
2271 for node in &ast.declarations {
2273 let node = unwrap_export(node);
2274 if let AstNode::Relation {
2275 name,
2276 subject_role,
2277 predicate,
2278 object_role,
2279 via_flow,
2280 } = node
2281 {
2282 if relation_map.contains_key(name) {
2283 return Err(ParseError::duplicate_declaration(format!(
2284 "Relation '{}' already declared",
2285 name
2286 )));
2287 }
2288
2289 let subject_id = role_map.get(subject_role).ok_or_else(|| {
2290 ParseError::GrammarError(format!("Undefined subject role '{}'", subject_role))
2291 })?;
2292
2293 let object_id = role_map.get(object_role).ok_or_else(|| {
2294 ParseError::GrammarError(format!("Undefined object role '{}'", object_role))
2295 })?;
2296
2297 let via_flow_id = if let Some(flow_name) = via_flow {
2298 Some(
2299 resource_map
2300 .get(flow_name)
2301 .cloned()
2302 .ok_or_else(|| ParseError::undefined_resource(flow_name))?,
2303 )
2304 } else {
2305 None
2306 };
2307
2308 let relation = RelationType::new(
2309 name.clone(),
2310 default_namespace.clone(),
2311 subject_id.clone(),
2312 predicate.clone(),
2313 object_id.clone(),
2314 via_flow_id,
2315 );
2316
2317 let relation_id = relation.id().clone();
2318 graph.add_relation_type(relation).map_err(|e| {
2319 ParseError::GrammarError(format!("Failed to add relation '{}': {}", name, e))
2320 })?;
2321 relation_map.insert(name.clone(), relation_id);
2322 }
2323 }
2324
2325 for node in &ast.declarations {
2327 let node = unwrap_export(node);
2328 if let AstNode::Instance {
2329 name,
2330 entity_type,
2331 fields,
2332 } = node
2333 {
2334 let namespace = default_namespace.clone();
2335 let mut instance = crate::primitives::Instance::new_with_namespace(
2336 name.clone(),
2337 entity_type.clone(),
2338 namespace,
2339 );
2340
2341 for (field_name, field_expr) in fields {
2343 let value = expression_to_json(field_expr)?;
2344 instance.set_field(field_name.clone(), value);
2345 }
2346
2347 graph.add_entity_instance(instance).map_err(|e| {
2348 ParseError::GrammarError(format!("Failed to add entity instance '{}': {}", name, e))
2349 })?;
2350 }
2351 }
2352
2353 for node in &ast.declarations {
2355 let node = unwrap_export(node);
2356 if let AstNode::Policy {
2357 name,
2358 version,
2359 metadata,
2360 expression,
2361 } = node
2362 {
2363 let namespace = ast
2364 .metadata
2365 .namespace
2366 .as_ref()
2367 .cloned()
2368 .or_else(|| options.default_namespace.clone())
2369 .unwrap_or_else(|| "default".to_string());
2370
2371 let kind = metadata.kind.as_ref().map(|kind| match kind {
2372 PolicyKind::Constraint => CorePolicyKind::Constraint,
2373 PolicyKind::Derivation => CorePolicyKind::Derivation,
2374 PolicyKind::Obligation => CorePolicyKind::Obligation,
2375 });
2376
2377 let modality = metadata.modality.as_ref().map(|modality| match modality {
2378 PolicyModality::Obligation => CorePolicyModality::Obligation,
2379 PolicyModality::Prohibition => CorePolicyModality::Prohibition,
2380 PolicyModality::Permission => CorePolicyModality::Permission,
2381 });
2382
2383 let mut policy =
2384 Policy::new_with_namespace(name.clone(), namespace, expression.clone())
2385 .with_metadata(
2386 kind,
2387 modality,
2388 metadata.priority,
2389 metadata.rationale.clone(),
2390 metadata.tags.clone(),
2391 );
2392
2393 let version_to_apply = version
2394 .as_ref()
2395 .cloned()
2396 .or_else(|| ast.metadata.version.clone());
2397
2398 if let Some(version_str) = version_to_apply {
2399 let semantic_version = SemanticVersion::parse(&version_str).map_err(|err| {
2400 ParseError::GrammarError(format!(
2401 "Invalid policy version '{}': {}",
2402 version_str, err
2403 ))
2404 })?;
2405 policy = policy.with_version(semantic_version);
2406 }
2407
2408 graph.add_policy(policy).map_err(|e| {
2409 ParseError::GrammarError(format!("Failed to add policy '{}': {}", name, e))
2410 })?;
2411 }
2412 }
2413
2414 for node in &ast.declarations {
2416 let node = unwrap_export(node);
2417 if let AstNode::Metric {
2418 name,
2419 expression,
2420 metadata,
2421 } = node
2422 {
2423 let namespace = ast
2424 .metadata
2425 .namespace
2426 .as_ref()
2427 .cloned()
2428 .or_else(|| options.default_namespace.clone())
2429 .unwrap_or_else(|| "default".to_string());
2430
2431 let mut metric =
2432 crate::primitives::Metric::new(name.clone(), namespace, expression.clone());
2433
2434 if let Some(duration) = metadata.refresh_interval {
2435 metric = metric.with_refresh_interval(duration);
2436 }
2437
2438 if let Some(unit) = &metadata.unit {
2439 metric = metric.with_unit(unit.clone());
2440 }
2441
2442 if let Some(threshold) = metadata.threshold {
2443 metric = metric.with_threshold(threshold);
2444 }
2445
2446 if let Some(severity) = metadata.severity.clone() {
2447 metric = metric.with_severity(severity);
2448 }
2449
2450 if let Some(target) = metadata.target {
2451 metric = metric.with_target(target);
2452 }
2453
2454 if let Some(duration) = metadata.window {
2455 metric = metric.with_window(duration);
2456 }
2457
2458 graph.add_metric(metric).map_err(|e| {
2459 ParseError::GrammarError(format!("Failed to add metric '{}': {}", name, e))
2460 })?;
2461 }
2462 }
2463
2464 for node in &ast.declarations {
2466 let node = unwrap_export(node);
2467 if let AstNode::MappingDecl {
2468 name,
2469 target,
2470 rules,
2471 } = node
2472 {
2473 let namespace = ast
2474 .metadata
2475 .namespace
2476 .clone()
2477 .or_else(|| options.default_namespace.clone())
2478 .unwrap_or_else(|| "default".to_string());
2479 let mapping = crate::primitives::MappingContract::new(
2480 crate::ConceptId::from_concept(&namespace, name),
2481 name.clone(),
2482 namespace,
2483 target.clone(),
2484 rules.clone(),
2485 );
2486 graph
2487 .add_mapping(mapping)
2488 .map_err(|e| ParseError::GrammarError(format!("Failed to add mapping: {}", e)))?;
2489 }
2490 }
2491
2492 for node in &ast.declarations {
2494 let node = unwrap_export(node);
2495 if let AstNode::ProjectionDecl {
2496 name,
2497 target,
2498 overrides,
2499 } = node
2500 {
2501 let namespace = ast
2502 .metadata
2503 .namespace
2504 .clone()
2505 .or_else(|| options.default_namespace.clone())
2506 .unwrap_or_else(|| "default".to_string());
2507 let projection = crate::primitives::ProjectionContract::new(
2508 crate::ConceptId::from_concept(&namespace, name),
2509 name.clone(),
2510 namespace,
2511 target.clone(),
2512 overrides.clone(),
2513 );
2514 graph.add_projection(projection).map_err(|e| {
2515 ParseError::GrammarError(format!("Failed to add projection: {}", e))
2516 })?;
2517 }
2518 }
2519
2520 Ok(graph)
2521}
2522
2523fn parse_metric(pair: Pair<Rule>) -> ParseResult<AstNode> {
2525 let mut inner = pair.into_inner();
2526
2527 let name = parse_name(
2528 inner
2529 .next()
2530 .ok_or_else(|| ParseError::GrammarError("Expected metric name".to_string()))?,
2531 )?;
2532
2533 let mut metadata = MetricMetadata {
2534 refresh_interval: None,
2535 unit: None,
2536 threshold: None,
2537 severity: None,
2538 target: None,
2539 window: None,
2540 };
2541
2542 let mut expression_pair = None;
2543
2544 for part in inner {
2545 match part.as_rule() {
2546 Rule::metric_annotation => {
2547 let mut annotation_inner = part.into_inner();
2548 let key_pair = annotation_inner.next().ok_or_else(|| {
2549 ParseError::GrammarError("Expected annotation key".to_string())
2550 })?;
2551
2552 match key_pair.as_rule() {
2553 Rule::ma_refresh_interval => {
2554 let value_pair = annotation_inner.next().ok_or_else(|| {
2555 ParseError::GrammarError("Expected refresh interval value".to_string())
2556 })?;
2557 let value = parse_number_i64(value_pair)?;
2558 let unit_pair = annotation_inner.next().ok_or_else(|| {
2559 ParseError::GrammarError("Expected refresh interval unit".to_string())
2560 })?;
2561 let unit = parse_string_literal(unit_pair.clone())?;
2562 let duration = parse_duration_with_unit(value, &unit, unit_pair.as_span())?;
2563 metadata.refresh_interval = Some(duration);
2564 }
2565 Rule::ma_unit => {
2566 let unit_pair = annotation_inner
2567 .next()
2568 .ok_or_else(|| ParseError::GrammarError("Expected unit".to_string()))?;
2569 metadata.unit = Some(parse_string_literal(unit_pair)?);
2570 }
2571 Rule::ma_threshold => {
2572 let value_pair = annotation_inner.next().ok_or_else(|| {
2573 ParseError::GrammarError("Expected threshold value".to_string())
2574 })?;
2575 metadata.threshold = Some(parse_decimal(value_pair)?);
2576 }
2577 Rule::ma_severity => {
2578 let severity_pair = annotation_inner.next().ok_or_else(|| {
2579 ParseError::GrammarError("Expected severity".to_string())
2580 })?;
2581 let severity_str = parse_string_literal(severity_pair.clone())?;
2582 let severity =
2583 parse_severity_value(&severity_str, severity_pair.as_span())?;
2584 metadata.severity = Some(severity);
2585 }
2586 Rule::ma_target => {
2587 let value_pair = annotation_inner.next().ok_or_else(|| {
2588 ParseError::GrammarError("Expected target value".to_string())
2589 })?;
2590 metadata.target = Some(parse_decimal(value_pair)?);
2591 }
2592 Rule::ma_window => {
2593 let value_pair = annotation_inner.next().ok_or_else(|| {
2594 ParseError::GrammarError("Expected window value".to_string())
2595 })?;
2596 let value = parse_number_i64(value_pair)?;
2597 let unit_pair = annotation_inner.next().ok_or_else(|| {
2598 ParseError::GrammarError("Expected window unit".to_string())
2599 })?;
2600 let unit = parse_string_literal(unit_pair.clone())?;
2601 let duration = parse_duration_with_unit(value, &unit, unit_pair.as_span())?;
2602 metadata.window = Some(duration);
2603 }
2604 _ => {
2605 let (line, column) = key_pair.as_span().start_pos().line_col();
2606 return Err(ParseError::GrammarError(format!(
2607 "Unknown metric annotation '{}' at {}:{}",
2608 key_pair.as_str(),
2609 line,
2610 column
2611 )));
2612 }
2613 }
2614 }
2615 Rule::expression => {
2616 expression_pair = Some(part);
2617 }
2618 _ => {}
2619 }
2620 }
2621
2622 let expression = parse_expression(
2623 expression_pair
2624 .ok_or_else(|| ParseError::GrammarError("Expected metric expression".to_string()))?,
2625 )?;
2626
2627 Ok(AstNode::Metric {
2628 name,
2629 expression,
2630 metadata,
2631 })
2632}
2633
2634fn parse_duration_with_unit(value: i64, unit: &str, span: Span<'_>) -> ParseResult<Duration> {
2635 let normalized_unit = unit.to_ascii_lowercase();
2636 let multiplier = match normalized_unit.as_str() {
2637 "second" => Some(1),
2638 "seconds" | "s" => Some(1),
2639 "minute" => Some(60),
2640 "minutes" | "m" => Some(60),
2641 "hour" => Some(60 * 60),
2642 "hours" | "h" => Some(60 * 60),
2643 "day" => Some(60 * 60 * 24),
2644 "days" | "d" => Some(60 * 60 * 24),
2645 _ => None,
2646 }
2647 .ok_or_else(|| {
2648 let (line, column) = span.start_pos().line_col();
2649 ParseError::GrammarError(format!(
2650 "Invalid duration unit '{}' at {}:{} (allowed: second(s)/s, minute(s)/m, hour(s)/h, day(s)/d)",
2651 unit, line, column
2652 ))
2653 })?;
2654
2655 let total_seconds = value.checked_mul(multiplier).ok_or_else(|| {
2656 let (line, column) = span.start_pos().line_col();
2657 ParseError::GrammarError(format!(
2658 "Duration overflow for value {} {} at {}:{}",
2659 value, unit, line, column
2660 ))
2661 })?;
2662
2663 Ok(Duration::seconds(total_seconds))
2664}
2665
2666fn parse_severity_value(value: &str, span: Span<'_>) -> ParseResult<Severity> {
2667 let normalized = value.to_ascii_lowercase();
2668 match normalized.as_str() {
2669 "info" => Ok(Severity::Info),
2670 "warning" => Ok(Severity::Warning),
2671 "error" => Ok(Severity::Error),
2672 "critical" => Ok(Severity::Critical),
2673 _ => {
2674 let (line, column) = span.start_pos().line_col();
2675 Err(ParseError::GrammarError(format!(
2676 "Unknown severity '{}' at {}:{} (expected one of: info, warning, error, critical)",
2677 value, line, column
2678 )))
2679 }
2680 }
2681}
2682
2683fn parse_number_i64(pair: Pair<Rule>) -> ParseResult<i64> {
2684 let s = pair.as_str();
2685 s.parse::<i64>()
2686 .map_err(|_| ParseError::GrammarError(format!("Invalid integer: {}", s)))
2687}