1pub mod ast;
17pub mod tokenizer;
18
19use crate::{Error, Result};
20use ast::*;
21use tokenizer::{Span, SpannedToken, Token, Tokenizer};
22
23pub fn parse(input: &str) -> Result<ContractNode> {
37 let mut tokenizer = Tokenizer::new(input);
38 let tokens = tokenizer.tokenize()?;
39 let mut parser = Parser::new(tokens);
40 parser.parse_contract_definition()
41}
42
43pub fn parse_contract(input: &str) -> Result<crate::Contract> {
51 let node = parse(input)?;
52 lower_contract(&node)
53}
54
55struct Parser {
58 tokens: Vec<SpannedToken>,
59 position: usize,
60}
61
62impl Parser {
63 fn new(tokens: Vec<SpannedToken>) -> Self {
64 Parser {
65 tokens,
66 position: 0,
67 }
68 }
69
70 fn current_span(&self) -> Span {
73 if self.position < self.tokens.len() {
74 self.tokens[self.position].span.clone()
75 } else {
76 Span {
77 line: 0,
78 column: 0,
79 offset: 0,
80 }
81 }
82 }
83
84 fn peek(&self) -> &Token {
85 &self.tokens[self.position].token
86 }
87
88 fn advance(&mut self) -> SpannedToken {
89 let token = self.tokens[self.position].clone();
90 if self.position < self.tokens.len() - 1 {
91 self.position += 1;
92 }
93 token
94 }
95
96 fn expect(&mut self, expected: Token) -> Result<SpannedToken> {
98 let current = self.tokens[self.position].clone();
99 if current.token == expected {
100 self.advance();
101 Ok(current)
102 } else {
103 Err(Error::ParseError(format!(
104 "Expected {:?}, found {:?} at {}",
105 expected, current.token, current.span
106 )))
107 }
108 }
109
110 fn expect_string_literal(&mut self) -> Result<SpannedValue<String>> {
112 let st = self.advance();
113 match st.token {
114 Token::StringLiteral(s) => Ok(SpannedValue::new(s, st.span)),
115 _ => Err(Error::ParseError(format!(
116 "Expected string literal, found {:?} at {}",
117 st.token, st.span
118 ))),
119 }
120 }
121
122 fn expect_integer_literal(&mut self) -> Result<SpannedValue<i64>> {
124 let st = self.advance();
125 match st.token {
126 Token::IntegerLiteral(n) => Ok(SpannedValue::new(n, st.span)),
127 _ => Err(Error::ParseError(format!(
128 "Expected integer literal, found {:?} at {}",
129 st.token, st.span
130 ))),
131 }
132 }
133
134 fn expect_float_literal(&mut self) -> Result<SpannedValue<f64>> {
136 let st = self.advance();
137 match st.token {
138 Token::FloatLiteral(f) => Ok(SpannedValue::new(f, st.span)),
139 _ => Err(Error::ParseError(format!(
140 "Expected float literal, found {:?} at {}",
141 st.token, st.span
142 ))),
143 }
144 }
145
146 fn expect_field(&mut self, name: &str) -> Result<Span> {
148 let st = self.advance();
149 match &st.token {
150 Token::Identifier(id) if id == name => {}
151 _ => {
152 return Err(Error::ParseError(format!(
153 "Expected field '{}', found {:?} at {}",
154 name, st.token, st.span
155 )));
156 }
157 }
158 self.expect(Token::Colon)?;
159 Ok(st.span)
160 }
161
162 fn optional_comma(&mut self) {
164 if matches!(self.peek(), Token::Comma) {
165 self.advance();
166 }
167 }
168
169 fn peek_identifier_name(&self) -> Result<String> {
171 match &self.tokens[self.position].token {
172 Token::Identifier(name) => Ok(name.clone()),
173 other => Err(Error::ParseError(format!(
174 "Expected field name identifier, found {:?} at {}",
175 other, self.tokens[self.position].span
176 ))),
177 }
178 }
179
180 fn parse_contract_definition(&mut self) -> Result<ContractNode> {
184 let span = self.current_span();
185 self.expect(Token::Contract)?;
186 self.expect(Token::LBrace)?;
187
188 let identity = self.parse_identity()?;
189 let purpose_statement = self.parse_purpose_statement()?;
190 let data_semantics = self.parse_data_semantics()?;
191 let behavioral_semantics = self.parse_behavioral_semantics()?;
192 let execution_constraints = self.parse_execution_constraints()?;
193 let human_machine_contract = self.parse_human_machine_contract()?;
194
195 self.expect(Token::RBrace)?;
196
197 let extensions = if matches!(self.peek(), Token::Extensions) {
199 Some(self.parse_extensions()?)
200 } else {
201 None
202 };
203
204 Ok(ContractNode {
205 identity,
206 purpose_statement,
207 data_semantics,
208 behavioral_semantics,
209 execution_constraints,
210 human_machine_contract,
211 extensions,
212 span,
213 })
214 }
215
216 fn parse_identity(&mut self) -> Result<IdentityNode> {
219 let span = self.current_span();
220 self.expect(Token::Identity)?;
221 self.expect(Token::LBrace)?;
222
223 let mut stable_id: Option<SpannedValue<String>> = None;
224 let mut version: Option<SpannedValue<i64>> = None;
225 let mut created_timestamp: Option<SpannedValue<String>> = None;
226 let mut owner: Option<SpannedValue<String>> = None;
227 let mut semantic_hash: Option<SpannedValue<String>> = None;
228
229 while !matches!(self.peek(), Token::RBrace) {
230 let field_name = self.peek_identifier_name()?;
231 match field_name.as_str() {
232 "stable_id" => {
233 self.expect_field("stable_id")?;
234 stable_id = Some(self.expect_string_literal()?);
235 }
236 "version" => {
237 self.expect_field("version")?;
238 version = Some(self.expect_integer_literal()?);
239 }
240 "created_timestamp" => {
241 self.expect_field("created_timestamp")?;
242 created_timestamp = Some(self.expect_string_literal()?);
243 }
244 "owner" => {
245 self.expect_field("owner")?;
246 owner = Some(self.expect_string_literal()?);
247 }
248 "semantic_hash" => {
249 self.expect_field("semantic_hash")?;
250 semantic_hash = Some(self.expect_string_literal()?);
251 }
252 other => {
253 return Err(Error::ParseError(format!(
254 "Unknown field '{}' in Identity at {}",
255 other,
256 self.current_span()
257 )));
258 }
259 }
260 self.optional_comma();
261 }
262
263 self.expect(Token::RBrace)?;
264
265 Ok(IdentityNode {
266 stable_id: stable_id.ok_or_else(|| {
267 Error::ParseError(format!(
268 "Missing required field 'stable_id' in Identity at {}",
269 span
270 ))
271 })?,
272 version: version.ok_or_else(|| {
273 Error::ParseError(format!(
274 "Missing required field 'version' in Identity at {}",
275 span
276 ))
277 })?,
278 created_timestamp: created_timestamp.ok_or_else(|| {
279 Error::ParseError(format!(
280 "Missing required field 'created_timestamp' in Identity at {}",
281 span
282 ))
283 })?,
284 owner: owner.ok_or_else(|| {
285 Error::ParseError(format!(
286 "Missing required field 'owner' in Identity at {}",
287 span
288 ))
289 })?,
290 semantic_hash: semantic_hash.ok_or_else(|| {
291 Error::ParseError(format!(
292 "Missing required field 'semantic_hash' in Identity at {}",
293 span
294 ))
295 })?,
296 span,
297 })
298 }
299
300 fn parse_purpose_statement(&mut self) -> Result<PurposeStatementNode> {
303 let span = self.current_span();
304 self.expect(Token::PurposeStatement)?;
305 self.expect(Token::LBrace)?;
306
307 let mut narrative: Option<SpannedValue<String>> = None;
308 let mut intent_source: Option<SpannedValue<String>> = None;
309 let mut confidence_level: Option<SpannedValue<f64>> = None;
310
311 while !matches!(self.peek(), Token::RBrace) {
312 let field_name = self.peek_identifier_name()?;
313 match field_name.as_str() {
314 "narrative" => {
315 self.expect_field("narrative")?;
316 narrative = Some(self.expect_string_literal()?);
317 }
318 "intent_source" => {
319 self.expect_field("intent_source")?;
320 intent_source = Some(self.expect_string_literal()?);
321 }
322 "confidence_level" => {
323 self.expect_field("confidence_level")?;
324 let cl = self.expect_float_literal()?;
325 if cl.value < 0.0 || cl.value > 1.0 {
326 return Err(Error::ValidationError(format!(
327 "confidence_level must be in [0.0, 1.0], found {} at {}",
328 cl.value, cl.span
329 )));
330 }
331 confidence_level = Some(cl);
332 }
333 other => {
334 return Err(Error::ParseError(format!(
335 "Unknown field '{}' in PurposeStatement at {}",
336 other,
337 self.current_span()
338 )));
339 }
340 }
341 self.optional_comma();
342 }
343
344 self.expect(Token::RBrace)?;
345
346 Ok(PurposeStatementNode {
347 narrative: narrative.ok_or_else(|| {
348 Error::ParseError(format!(
349 "Missing required field 'narrative' in PurposeStatement at {}",
350 span
351 ))
352 })?,
353 intent_source: intent_source.ok_or_else(|| {
354 Error::ParseError(format!(
355 "Missing required field 'intent_source' in PurposeStatement at {}",
356 span
357 ))
358 })?,
359 confidence_level: confidence_level.ok_or_else(|| {
360 Error::ParseError(format!(
361 "Missing required field 'confidence_level' in PurposeStatement at {}",
362 span
363 ))
364 })?,
365 span,
366 })
367 }
368
369 fn parse_data_semantics(&mut self) -> Result<DataSemanticsNode> {
372 let span = self.current_span();
373 self.expect(Token::DataSemantics)?;
374 self.expect(Token::LBrace)?;
375
376 let mut state: Option<Vec<StateFieldNode>> = None;
377 let mut invariants: Option<Vec<SpannedValue<String>>> = None;
378
379 while !matches!(self.peek(), Token::RBrace) {
380 let field_name = self.peek_identifier_name()?;
381 match field_name.as_str() {
382 "state" => {
383 self.expect_field("state")?;
384 self.expect(Token::LBrace)?;
385 state = Some(self.parse_state_fields()?);
386 self.expect(Token::RBrace)?;
387 }
388 "invariants" => {
389 self.expect_field("invariants")?;
390 invariants = Some(self.parse_string_list()?);
391 }
392 other => {
393 return Err(Error::ParseError(format!(
394 "Unknown field '{}' in DataSemantics at {}",
395 other,
396 self.current_span()
397 )));
398 }
399 }
400 self.optional_comma();
401 }
402
403 self.expect(Token::RBrace)?;
404
405 Ok(DataSemanticsNode {
406 state: state.ok_or_else(|| {
407 Error::ParseError(format!(
408 "Missing required field 'state' in DataSemantics at {}",
409 span
410 ))
411 })?,
412 invariants: invariants.ok_or_else(|| {
413 Error::ParseError(format!(
414 "Missing required field 'invariants' in DataSemantics at {}",
415 span
416 ))
417 })?,
418 span,
419 })
420 }
421
422 fn parse_state_fields(&mut self) -> Result<Vec<StateFieldNode>> {
424 let mut fields = Vec::new();
425 while !matches!(self.peek(), Token::RBrace) {
426 fields.push(self.parse_state_field()?);
427 self.optional_comma();
428 }
429 Ok(fields)
430 }
431
432 fn parse_state_field(&mut self) -> Result<StateFieldNode> {
434 let span = self.current_span();
435
436 let name_st = self.advance();
437 let name = match name_st.token {
438 Token::Identifier(s) => SpannedValue::new(s, name_st.span),
439 _ => {
440 return Err(Error::ParseError(format!(
441 "Expected field name, found {:?} at {}",
442 name_st.token, name_st.span
443 )));
444 }
445 };
446
447 self.expect(Token::Colon)?;
448 let type_expr = self.parse_type_expression()?;
449
450 let default_value = if matches!(self.peek(), Token::Equals) {
451 self.advance(); Some(self.parse_literal_value()?)
453 } else {
454 None
455 };
456
457 Ok(StateFieldNode {
458 name,
459 type_expr,
460 default_value,
461 span,
462 })
463 }
464
465 fn parse_type_expression(&mut self) -> Result<TypeExpression> {
468 let span = self.current_span();
469 match self.peek().clone() {
470 Token::IntegerType => {
471 self.advance();
472 Ok(TypeExpression::Primitive(PrimitiveType::Integer, span))
473 }
474 Token::FloatType => {
475 self.advance();
476 Ok(TypeExpression::Primitive(PrimitiveType::Float, span))
477 }
478 Token::StringType => {
479 self.advance();
480 Ok(TypeExpression::Primitive(PrimitiveType::String, span))
481 }
482 Token::BooleanType => {
483 self.advance();
484 Ok(TypeExpression::Primitive(PrimitiveType::Boolean, span))
485 }
486 Token::Iso8601Type => {
487 self.advance();
488 Ok(TypeExpression::Primitive(PrimitiveType::Iso8601, span))
489 }
490 Token::UuidType => {
491 self.advance();
492 Ok(TypeExpression::Primitive(PrimitiveType::Uuid, span))
493 }
494 Token::ArrayType => self.parse_array_type(span),
495 Token::MapType => self.parse_map_type(span),
496 Token::ObjectType => self.parse_object_type(span),
497 Token::EnumType => self.parse_enum_type(span),
498 _ => Err(Error::ParseError(format!(
499 "Expected type expression, found {:?} at {}",
500 self.peek(),
501 span
502 ))),
503 }
504 }
505
506 fn parse_array_type(&mut self, span: Span) -> Result<TypeExpression> {
507 self.advance(); self.expect(Token::LAngle)?;
509 let inner = self.parse_type_expression()?;
510 self.expect(Token::RAngle)?;
511 Ok(TypeExpression::Array(Box::new(inner), span))
512 }
513
514 fn parse_map_type(&mut self, span: Span) -> Result<TypeExpression> {
515 self.advance(); self.expect(Token::LAngle)?;
517 let key = self.parse_type_expression()?;
518 self.expect(Token::Comma)?;
519 let value = self.parse_type_expression()?;
520 self.expect(Token::RAngle)?;
521 Ok(TypeExpression::Map(Box::new(key), Box::new(value), span))
522 }
523
524 fn parse_object_type(&mut self, span: Span) -> Result<TypeExpression> {
525 self.advance(); self.expect(Token::LBrace)?;
527 let fields = self.parse_state_fields()?;
528 self.expect(Token::RBrace)?;
529 Ok(TypeExpression::Object(fields, span))
530 }
531
532 fn parse_enum_type(&mut self, span: Span) -> Result<TypeExpression> {
533 self.advance(); self.expect(Token::LBracket)?;
535
536 let mut variants = Vec::new();
537 if !matches!(self.peek(), Token::RBracket) {
538 variants.push(self.expect_string_literal()?);
539 while matches!(self.peek(), Token::Comma) {
540 self.advance(); if matches!(self.peek(), Token::RBracket) {
542 break; }
544 variants.push(self.expect_string_literal()?);
545 }
546 }
547
548 self.expect(Token::RBracket)?;
549 Ok(TypeExpression::Enum(variants, span))
550 }
551
552 fn parse_literal_value(&mut self) -> Result<LiteralValue> {
555 let span = self.current_span();
556 match self.peek().clone() {
557 Token::StringLiteral(_) => {
558 let st = self.advance();
559 if let Token::StringLiteral(s) = st.token {
560 Ok(LiteralValue::String(s, st.span))
561 } else {
562 unreachable!()
563 }
564 }
565 Token::IntegerLiteral(_) => {
566 let st = self.advance();
567 if let Token::IntegerLiteral(n) = st.token {
568 Ok(LiteralValue::Integer(n, st.span))
569 } else {
570 unreachable!()
571 }
572 }
573 Token::FloatLiteral(_) => {
574 let st = self.advance();
575 if let Token::FloatLiteral(f) = st.token {
576 Ok(LiteralValue::Float(f, st.span))
577 } else {
578 unreachable!()
579 }
580 }
581 Token::BooleanLiteral(_) => {
582 let st = self.advance();
583 if let Token::BooleanLiteral(b) = st.token {
584 Ok(LiteralValue::Boolean(b, st.span))
585 } else {
586 unreachable!()
587 }
588 }
589 Token::LBracket => {
590 self.advance(); let mut items = Vec::new();
592 if !matches!(self.peek(), Token::RBracket) {
593 items.push(self.parse_literal_value()?);
594 while matches!(self.peek(), Token::Comma) {
595 self.advance(); if matches!(self.peek(), Token::RBracket) {
597 break; }
599 items.push(self.parse_literal_value()?);
600 }
601 }
602 self.expect(Token::RBracket)?;
603 Ok(LiteralValue::Array(items, span))
604 }
605 _ => Err(Error::ParseError(format!(
606 "Expected literal value, found {:?} at {}",
607 self.peek(),
608 span
609 ))),
610 }
611 }
612
613 fn parse_behavioral_semantics(&mut self) -> Result<BehavioralSemanticsNode> {
616 let span = self.current_span();
617 self.expect(Token::BehavioralSemantics)?;
618 self.expect(Token::LBrace)?;
619
620 self.expect_field("operations")?;
621 self.expect(Token::LBracket)?;
622
623 let mut operations = Vec::new();
624 while !matches!(self.peek(), Token::RBracket) {
625 operations.push(self.parse_operation()?);
626 self.optional_comma();
627 }
628
629 self.expect(Token::RBracket)?;
630 self.optional_comma();
631
632 self.expect(Token::RBrace)?;
633
634 Ok(BehavioralSemanticsNode { operations, span })
635 }
636
637 fn parse_operation(&mut self) -> Result<OperationNode> {
638 let span = self.current_span();
639 self.expect(Token::LBrace)?;
640
641 let mut name: Option<SpannedValue<String>> = None;
642 let mut precondition: Option<SpannedValue<String>> = None;
643 let mut parameters: Option<Vec<StateFieldNode>> = None;
644 let mut postcondition: Option<SpannedValue<String>> = None;
645 let mut side_effects: Option<Vec<SpannedValue<String>>> = None;
646 let mut idempotence: Option<SpannedValue<String>> = None;
647
648 while !matches!(self.peek(), Token::RBrace) {
649 let field_name = self.peek_identifier_name()?;
650 match field_name.as_str() {
651 "name" => {
652 self.expect_field("name")?;
653 name = Some(self.expect_string_literal()?);
654 }
655 "precondition" => {
656 self.expect_field("precondition")?;
657 precondition = Some(self.expect_string_literal()?);
658 }
659 "parameters" => {
660 self.expect_field("parameters")?;
661 self.expect(Token::LBrace)?;
662 parameters = Some(self.parse_state_fields()?);
663 self.expect(Token::RBrace)?;
664 }
665 "postcondition" => {
666 self.expect_field("postcondition")?;
667 postcondition = Some(self.expect_string_literal()?);
668 }
669 "side_effects" => {
670 self.expect_field("side_effects")?;
671 side_effects = Some(self.parse_string_list()?);
672 }
673 "idempotence" => {
674 self.expect_field("idempotence")?;
675 idempotence = Some(self.expect_string_literal()?);
676 }
677 other => {
678 return Err(Error::ParseError(format!(
679 "Unknown field '{}' in operation at {}",
680 other,
681 self.current_span()
682 )));
683 }
684 }
685 self.optional_comma();
686 }
687
688 self.expect(Token::RBrace)?;
689
690 Ok(OperationNode {
691 name: name.ok_or_else(|| {
692 Error::ParseError(format!(
693 "Missing required field 'name' in operation at {}",
694 span
695 ))
696 })?,
697 precondition: precondition.ok_or_else(|| {
698 Error::ParseError(format!(
699 "Missing required field 'precondition' in operation at {}",
700 span
701 ))
702 })?,
703 parameters: parameters.ok_or_else(|| {
704 Error::ParseError(format!(
705 "Missing required field 'parameters' in operation at {}",
706 span
707 ))
708 })?,
709 postcondition: postcondition.ok_or_else(|| {
710 Error::ParseError(format!(
711 "Missing required field 'postcondition' in operation at {}",
712 span
713 ))
714 })?,
715 side_effects: side_effects.ok_or_else(|| {
716 Error::ParseError(format!(
717 "Missing required field 'side_effects' in operation at {}",
718 span
719 ))
720 })?,
721 idempotence: idempotence.ok_or_else(|| {
722 Error::ParseError(format!(
723 "Missing required field 'idempotence' in operation at {}",
724 span
725 ))
726 })?,
727 span,
728 })
729 }
730
731 fn parse_execution_constraints(&mut self) -> Result<ExecutionConstraintsNode> {
734 let span = self.current_span();
735 self.expect(Token::ExecutionConstraints)?;
736 self.expect(Token::LBrace)?;
737
738 let mut trigger_types: Option<Vec<SpannedValue<String>>> = None;
739 let mut resource_limits: Option<ResourceLimitsNode> = None;
740 let mut external_permissions: Option<Vec<SpannedValue<String>>> = None;
741 let mut sandbox_mode: Option<SpannedValue<String>> = None;
742
743 while !matches!(self.peek(), Token::RBrace) {
744 let field_name = self.peek_identifier_name()?;
745 match field_name.as_str() {
746 "trigger_types" => {
747 self.expect_field("trigger_types")?;
748 trigger_types = Some(self.parse_string_list()?);
749 }
750 "resource_limits" => {
751 self.expect_field("resource_limits")?;
752 resource_limits = Some(self.parse_resource_limits()?);
753 }
754 "external_permissions" => {
755 self.expect_field("external_permissions")?;
756 external_permissions = Some(self.parse_string_list()?);
757 }
758 "sandbox_mode" => {
759 self.expect_field("sandbox_mode")?;
760 sandbox_mode = Some(self.expect_string_literal()?);
761 }
762 other => {
763 return Err(Error::ParseError(format!(
764 "Unknown field '{}' in ExecutionConstraints at {}",
765 other,
766 self.current_span()
767 )));
768 }
769 }
770 self.optional_comma();
771 }
772
773 self.expect(Token::RBrace)?;
774
775 Ok(ExecutionConstraintsNode {
776 trigger_types: trigger_types.ok_or_else(|| {
777 Error::ParseError(format!(
778 "Missing required field 'trigger_types' in ExecutionConstraints at {}",
779 span
780 ))
781 })?,
782 resource_limits: resource_limits.ok_or_else(|| {
783 Error::ParseError(format!(
784 "Missing required field 'resource_limits' in ExecutionConstraints at {}",
785 span
786 ))
787 })?,
788 external_permissions: external_permissions.ok_or_else(|| {
789 Error::ParseError(format!(
790 "Missing required field 'external_permissions' in ExecutionConstraints at {}",
791 span
792 ))
793 })?,
794 sandbox_mode: sandbox_mode.ok_or_else(|| {
795 Error::ParseError(format!(
796 "Missing required field 'sandbox_mode' in ExecutionConstraints at {}",
797 span
798 ))
799 })?,
800 span,
801 })
802 }
803
804 fn parse_resource_limits(&mut self) -> Result<ResourceLimitsNode> {
805 let span = self.current_span();
806 self.expect(Token::LBrace)?;
807
808 let mut max_memory_bytes: Option<SpannedValue<i64>> = None;
809 let mut computation_timeout_ms: Option<SpannedValue<i64>> = None;
810 let mut max_state_size_bytes: Option<SpannedValue<i64>> = None;
811
812 while !matches!(self.peek(), Token::RBrace) {
813 let field_name = self.peek_identifier_name()?;
814 match field_name.as_str() {
815 "max_memory_bytes" => {
816 self.expect_field("max_memory_bytes")?;
817 max_memory_bytes = Some(self.expect_integer_literal()?);
818 }
819 "computation_timeout_ms" => {
820 self.expect_field("computation_timeout_ms")?;
821 computation_timeout_ms = Some(self.expect_integer_literal()?);
822 }
823 "max_state_size_bytes" => {
824 self.expect_field("max_state_size_bytes")?;
825 max_state_size_bytes = Some(self.expect_integer_literal()?);
826 }
827 other => {
828 return Err(Error::ParseError(format!(
829 "Unknown field '{}' in resource_limits at {}",
830 other,
831 self.current_span()
832 )));
833 }
834 }
835 self.optional_comma();
836 }
837
838 self.expect(Token::RBrace)?;
839
840 Ok(ResourceLimitsNode {
841 max_memory_bytes: max_memory_bytes.ok_or_else(|| {
842 Error::ParseError(format!(
843 "Missing required field 'max_memory_bytes' in resource_limits at {}",
844 span
845 ))
846 })?,
847 computation_timeout_ms: computation_timeout_ms.ok_or_else(|| {
848 Error::ParseError(format!(
849 "Missing required field 'computation_timeout_ms' in resource_limits at {}",
850 span
851 ))
852 })?,
853 max_state_size_bytes: max_state_size_bytes.ok_or_else(|| {
854 Error::ParseError(format!(
855 "Missing required field 'max_state_size_bytes' in resource_limits at {}",
856 span
857 ))
858 })?,
859 span,
860 })
861 }
862
863 fn parse_human_machine_contract(&mut self) -> Result<HumanMachineContractNode> {
866 let span = self.current_span();
867 self.expect(Token::HumanMachineContract)?;
868 self.expect(Token::LBrace)?;
869
870 let mut system_commitments: Option<Vec<SpannedValue<String>>> = None;
871 let mut system_refusals: Option<Vec<SpannedValue<String>>> = None;
872 let mut user_obligations: Option<Vec<SpannedValue<String>>> = None;
873
874 while !matches!(self.peek(), Token::RBrace) {
875 let field_name = self.peek_identifier_name()?;
876 match field_name.as_str() {
877 "system_commitments" => {
878 self.expect_field("system_commitments")?;
879 system_commitments = Some(self.parse_string_list()?);
880 }
881 "system_refusals" => {
882 self.expect_field("system_refusals")?;
883 system_refusals = Some(self.parse_string_list()?);
884 }
885 "user_obligations" => {
886 self.expect_field("user_obligations")?;
887 user_obligations = Some(self.parse_string_list()?);
888 }
889 other => {
890 return Err(Error::ParseError(format!(
891 "Unknown field '{}' in HumanMachineContract at {}",
892 other,
893 self.current_span()
894 )));
895 }
896 }
897 self.optional_comma();
898 }
899
900 self.expect(Token::RBrace)?;
901
902 Ok(HumanMachineContractNode {
903 system_commitments: system_commitments.ok_or_else(|| {
904 Error::ParseError(format!(
905 "Missing required field 'system_commitments' in HumanMachineContract at {}",
906 span
907 ))
908 })?,
909 system_refusals: system_refusals.ok_or_else(|| {
910 Error::ParseError(format!(
911 "Missing required field 'system_refusals' in HumanMachineContract at {}",
912 span
913 ))
914 })?,
915 user_obligations: user_obligations.ok_or_else(|| {
916 Error::ParseError(format!(
917 "Missing required field 'user_obligations' in HumanMachineContract at {}",
918 span
919 ))
920 })?,
921 span,
922 })
923 }
924
925 fn parse_extensions(&mut self) -> Result<ExtensionsNode> {
928 let span = self.current_span();
929 self.expect(Token::Extensions)?;
930 self.expect(Token::LBrace)?;
931
932 let mut systems = Vec::new();
933 while !matches!(self.peek(), Token::RBrace) {
934 systems.push(self.parse_system_extension()?);
935 }
936
937 self.expect(Token::RBrace)?;
938
939 Ok(ExtensionsNode { systems, span })
940 }
941
942 fn parse_system_extension(&mut self) -> Result<SystemExtensionNode> {
943 let span = self.current_span();
944
945 let name_st = self.advance();
946 let name = match name_st.token {
947 Token::Identifier(s) => SpannedValue::new(s, name_st.span),
948 _ => {
949 return Err(Error::ParseError(format!(
950 "Expected system extension name, found {:?} at {}",
951 name_st.token, name_st.span
952 )));
953 }
954 };
955
956 self.expect(Token::LBrace)?;
957
958 let mut fields = Vec::new();
959 while !matches!(self.peek(), Token::RBrace) {
960 fields.push(self.parse_custom_field()?);
961 self.optional_comma();
962 }
963
964 self.expect(Token::RBrace)?;
965
966 Ok(SystemExtensionNode { name, fields, span })
967 }
968
969 fn parse_custom_field(&mut self) -> Result<CustomFieldNode> {
970 let span = self.current_span();
971
972 let name_st = self.advance();
973 let name = match name_st.token {
974 Token::Identifier(s) => SpannedValue::new(s, name_st.span),
975 _ => {
976 return Err(Error::ParseError(format!(
977 "Expected field name, found {:?} at {}",
978 name_st.token, name_st.span
979 )));
980 }
981 };
982
983 self.expect(Token::Colon)?;
984 let value = self.parse_literal_value()?;
985
986 Ok(CustomFieldNode { name, value, span })
987 }
988
989 fn parse_string_list(&mut self) -> Result<Vec<SpannedValue<String>>> {
993 self.expect(Token::LBracket)?;
994
995 let mut items = Vec::new();
996 if !matches!(self.peek(), Token::RBracket) {
997 items.push(self.expect_string_literal()?);
998 while matches!(self.peek(), Token::Comma) {
999 self.advance(); if matches!(self.peek(), Token::RBracket) {
1001 break; }
1003 items.push(self.expect_string_literal()?);
1004 }
1005 }
1006
1007 self.expect(Token::RBracket)?;
1008 Ok(items)
1009 }
1010}
1011
1012pub fn lower_contract(node: &ContractNode) -> Result<crate::Contract> {
1017 Ok(crate::Contract {
1018 identity: crate::Identity {
1019 stable_id: node.identity.stable_id.value.clone(),
1020 version: node.identity.version.value as u32,
1021 created_timestamp: node.identity.created_timestamp.value.clone(),
1022 owner: node.identity.owner.value.clone(),
1023 semantic_hash: node.identity.semantic_hash.value.clone(),
1024 },
1025 purpose_statement: crate::PurposeStatement {
1026 narrative: node.purpose_statement.narrative.value.clone(),
1027 intent_source: node.purpose_statement.intent_source.value.clone(),
1028 confidence_level: node.purpose_statement.confidence_level.value,
1029 },
1030 data_semantics: lower_data_semantics(&node.data_semantics),
1031 behavioral_semantics: lower_behavioral_semantics(&node.behavioral_semantics),
1032 execution_constraints: crate::ExecutionConstraints {
1033 trigger_types: node
1034 .execution_constraints
1035 .trigger_types
1036 .iter()
1037 .map(|s| s.value.clone())
1038 .collect(),
1039 resource_limits: crate::ResourceLimits {
1040 max_memory_bytes: node
1041 .execution_constraints
1042 .resource_limits
1043 .max_memory_bytes
1044 .value as u64,
1045 computation_timeout_ms: node
1046 .execution_constraints
1047 .resource_limits
1048 .computation_timeout_ms
1049 .value as u64,
1050 max_state_size_bytes: node
1051 .execution_constraints
1052 .resource_limits
1053 .max_state_size_bytes
1054 .value as u64,
1055 },
1056 external_permissions: node
1057 .execution_constraints
1058 .external_permissions
1059 .iter()
1060 .map(|s| s.value.clone())
1061 .collect(),
1062 sandbox_mode: node.execution_constraints.sandbox_mode.value.clone(),
1063 },
1064 human_machine_contract: crate::HumanMachineContract {
1065 system_commitments: node
1066 .human_machine_contract
1067 .system_commitments
1068 .iter()
1069 .map(|s| s.value.clone())
1070 .collect(),
1071 system_refusals: node
1072 .human_machine_contract
1073 .system_refusals
1074 .iter()
1075 .map(|s| s.value.clone())
1076 .collect(),
1077 user_obligations: node
1078 .human_machine_contract
1079 .user_obligations
1080 .iter()
1081 .map(|s| s.value.clone())
1082 .collect(),
1083 },
1084 })
1085}
1086
1087fn lower_data_semantics(node: &DataSemanticsNode) -> crate::DataSemantics {
1088 let mut state = serde_json::Map::new();
1089 for field in &node.state {
1090 let type_str = field.type_expr.to_string();
1091 let value = if let Some(ref default) = field.default_value {
1092 let default_json = lower_literal(default);
1094 serde_json::json!({
1095 "type": type_str,
1096 "default": default_json
1097 })
1098 } else {
1099 serde_json::Value::String(type_str)
1100 };
1101 state.insert(field.name.value.clone(), value);
1102 }
1103 crate::DataSemantics {
1104 state: serde_json::Value::Object(state),
1105 invariants: node.invariants.iter().map(|s| s.value.clone()).collect(),
1106 }
1107}
1108
1109fn lower_literal(lit: &ast::LiteralValue) -> serde_json::Value {
1110 match lit {
1111 ast::LiteralValue::String(s, _) => serde_json::Value::String(s.clone()),
1112 ast::LiteralValue::Integer(i, _) => serde_json::json!(*i),
1113 ast::LiteralValue::Float(f, _) => serde_json::json!(*f),
1114 ast::LiteralValue::Boolean(b, _) => serde_json::Value::Bool(*b),
1115 ast::LiteralValue::Array(arr, _) => {
1116 serde_json::Value::Array(arr.iter().map(lower_literal).collect())
1117 }
1118 }
1119}
1120
1121fn lower_behavioral_semantics(node: &BehavioralSemanticsNode) -> crate::BehavioralSemantics {
1122 let operations = node
1123 .operations
1124 .iter()
1125 .map(|op| {
1126 let mut params = serde_json::Map::new();
1127 for p in &op.parameters {
1128 params.insert(
1129 p.name.value.clone(),
1130 serde_json::Value::String(p.type_expr.to_string()),
1131 );
1132 }
1133
1134 crate::Operation {
1135 name: op.name.value.clone(),
1136 precondition: op.precondition.value.clone(),
1137 parameters: serde_json::Value::Object(params),
1138 postcondition: op.postcondition.value.clone(),
1139 side_effects: op.side_effects.iter().map(|s| s.value.clone()).collect(),
1140 idempotence: op.idempotence.value.clone(),
1141 }
1142 })
1143 .collect();
1144
1145 crate::BehavioralSemantics { operations }
1146}
1147
1148#[cfg(test)]
1149mod tests {
1150 use super::*;
1151 use std::fs;
1152 use std::path::Path;
1153
1154 fn parse_valid(input: &str) -> ContractNode {
1157 parse(input).unwrap_or_else(|e| panic!("Expected successful parse, got: {}", e))
1158 }
1159
1160 fn parse_err(input: &str) -> String {
1161 parse(input).unwrap_err().to_string()
1162 }
1163
1164 const MINIMAL_CONTRACT: &str = r#"Contract {
1167 Identity {
1168 stable_id: "ic-test-001",
1169 version: 1,
1170 created_timestamp: 2026-02-01T00:00:00Z,
1171 owner: "test",
1172 semantic_hash: "0000000000000000"
1173 }
1174
1175 PurposeStatement {
1176 narrative: "Minimal test contract",
1177 intent_source: "test",
1178 confidence_level: 1.0
1179 }
1180
1181 DataSemantics {
1182 state: {
1183 value: String
1184 },
1185 invariants: []
1186 }
1187
1188 BehavioralSemantics {
1189 operations: []
1190 }
1191
1192 ExecutionConstraints {
1193 trigger_types: ["manual"],
1194 resource_limits: {
1195 max_memory_bytes: 1048576,
1196 computation_timeout_ms: 100,
1197 max_state_size_bytes: 1048576
1198 },
1199 external_permissions: [],
1200 sandbox_mode: "full_isolation"
1201 }
1202
1203 HumanMachineContract {
1204 system_commitments: [],
1205 system_refusals: [],
1206 user_obligations: []
1207 }
1208}"#;
1209
1210 #[test]
1211 fn test_parse_minimal_contract() {
1212 let ast = parse_valid(MINIMAL_CONTRACT);
1213 assert_eq!(ast.identity.stable_id.value, "ic-test-001");
1214 assert_eq!(ast.identity.version.value, 1);
1215 assert_eq!(ast.identity.owner.value, "test");
1216 assert_eq!(ast.purpose_statement.confidence_level.value, 1.0);
1217 assert_eq!(ast.data_semantics.state.len(), 1);
1218 assert_eq!(ast.data_semantics.state[0].name.value, "value");
1219 assert_eq!(ast.behavioral_semantics.operations.len(), 0);
1220 assert!(ast.extensions.is_none());
1221 }
1222
1223 #[test]
1224 fn test_parse_contract_lowers_correctly() {
1225 let contract = parse_contract(MINIMAL_CONTRACT).unwrap();
1226 assert_eq!(contract.identity.stable_id, "ic-test-001");
1227 assert_eq!(contract.identity.version, 1);
1228 assert_eq!(contract.purpose_statement.confidence_level, 1.0);
1229 assert_eq!(
1230 contract.execution_constraints.sandbox_mode,
1231 "full_isolation"
1232 );
1233 }
1234
1235 #[test]
1238 fn test_parse_all_primitive_types() {
1239 let input = r#"Contract {
1240 Identity {
1241 stable_id: "ic-types-001",
1242 version: 1,
1243 created_timestamp: 2026-02-01T00:00:00Z,
1244 owner: "test",
1245 semantic_hash: "1111111111111111"
1246 }
1247 PurposeStatement {
1248 narrative: "Primitive types test",
1249 intent_source: "test",
1250 confidence_level: 0.95
1251 }
1252 DataSemantics {
1253 state: {
1254 count: Integer = 0,
1255 ratio: Float = 1.0,
1256 label: String,
1257 active: Boolean,
1258 created_at: ISO8601,
1259 user_id: UUID
1260 },
1261 invariants: ["count >= 0"]
1262 }
1263 BehavioralSemantics {
1264 operations: []
1265 }
1266 ExecutionConstraints {
1267 trigger_types: ["manual"],
1268 resource_limits: {
1269 max_memory_bytes: 1048576,
1270 computation_timeout_ms: 100,
1271 max_state_size_bytes: 1048576
1272 },
1273 external_permissions: [],
1274 sandbox_mode: "full_isolation"
1275 }
1276 HumanMachineContract {
1277 system_commitments: [],
1278 system_refusals: [],
1279 user_obligations: []
1280 }
1281}"#;
1282 let ast = parse_valid(input);
1283 assert_eq!(ast.data_semantics.state.len(), 6);
1284
1285 let state = &ast.data_semantics.state;
1286 assert_eq!(state[0].name.value, "count");
1287 assert!(matches!(
1288 state[0].type_expr,
1289 TypeExpression::Primitive(PrimitiveType::Integer, _)
1290 ));
1291 assert!(state[0].default_value.is_some());
1292
1293 assert_eq!(state[3].name.value, "active");
1294 assert!(matches!(
1295 state[3].type_expr,
1296 TypeExpression::Primitive(PrimitiveType::Boolean, _)
1297 ));
1298
1299 assert_eq!(state[4].name.value, "created_at");
1300 assert!(matches!(
1301 state[4].type_expr,
1302 TypeExpression::Primitive(PrimitiveType::Iso8601, _)
1303 ));
1304
1305 assert_eq!(state[5].name.value, "user_id");
1306 assert!(matches!(
1307 state[5].type_expr,
1308 TypeExpression::Primitive(PrimitiveType::Uuid, _)
1309 ));
1310 }
1311
1312 #[test]
1313 fn test_parse_composite_types() {
1314 let input = r#"Contract {
1315 Identity {
1316 stable_id: "ic-composite-001",
1317 version: 1,
1318 created_timestamp: 2026-02-01T00:00:00Z,
1319 owner: "test",
1320 semantic_hash: "2222222222222222"
1321 }
1322 PurposeStatement {
1323 narrative: "Composite types",
1324 intent_source: "test",
1325 confidence_level: 1.0
1326 }
1327 DataSemantics {
1328 state: {
1329 status: Enum["pending", "active", "completed"],
1330 metadata: Object {
1331 key: String,
1332 value: String
1333 },
1334 tags: Array<String>,
1335 scores: Map<String, Integer>
1336 },
1337 invariants: ["status is valid enum value"]
1338 }
1339 BehavioralSemantics {
1340 operations: []
1341 }
1342 ExecutionConstraints {
1343 trigger_types: ["manual"],
1344 resource_limits: {
1345 max_memory_bytes: 1048576,
1346 computation_timeout_ms: 100,
1347 max_state_size_bytes: 1048576
1348 },
1349 external_permissions: [],
1350 sandbox_mode: "full_isolation"
1351 }
1352 HumanMachineContract {
1353 system_commitments: [],
1354 system_refusals: [],
1355 user_obligations: []
1356 }
1357}"#;
1358 let ast = parse_valid(input);
1359 let state = &ast.data_semantics.state;
1360 assert_eq!(state.len(), 4);
1361
1362 if let TypeExpression::Enum(variants, _) = &state[0].type_expr {
1364 assert_eq!(variants.len(), 3);
1365 assert_eq!(variants[0].value, "pending");
1366 assert_eq!(variants[2].value, "completed");
1367 } else {
1368 panic!("Expected Enum type");
1369 }
1370
1371 if let TypeExpression::Object(fields, _) = &state[1].type_expr {
1373 assert_eq!(fields.len(), 2);
1374 assert_eq!(fields[0].name.value, "key");
1375 } else {
1376 panic!("Expected Object type");
1377 }
1378
1379 assert!(matches!(&state[2].type_expr, TypeExpression::Array(_, _)));
1381
1382 assert!(matches!(&state[3].type_expr, TypeExpression::Map(_, _, _)));
1384 }
1385
1386 #[test]
1389 fn test_parse_multiple_operations() {
1390 let input = r#"Contract {
1391 Identity {
1392 stable_id: "ic-ops-001",
1393 version: 2,
1394 created_timestamp: 2026-02-01T00:00:00Z,
1395 owner: "test",
1396 semantic_hash: "4444444444444444"
1397 }
1398 PurposeStatement {
1399 narrative: "Multiple operations",
1400 intent_source: "test",
1401 confidence_level: 0.99
1402 }
1403 DataSemantics {
1404 state: {
1405 items: Array<String>,
1406 count: Integer = 0
1407 },
1408 invariants: ["count >= 0"]
1409 }
1410 BehavioralSemantics {
1411 operations: [
1412 {
1413 name: "add_item",
1414 precondition: "item_not_duplicate",
1415 parameters: {
1416 item: String
1417 },
1418 postcondition: "item_added",
1419 side_effects: ["log_addition"],
1420 idempotence: "not_idempotent"
1421 },
1422 {
1423 name: "clear_all",
1424 precondition: "items_not_empty",
1425 parameters: {},
1426 postcondition: "items_empty",
1427 side_effects: ["log_clear"],
1428 idempotence: "idempotent"
1429 }
1430 ]
1431 }
1432 ExecutionConstraints {
1433 trigger_types: ["manual", "event_based"],
1434 resource_limits: {
1435 max_memory_bytes: 2097152,
1436 computation_timeout_ms: 200,
1437 max_state_size_bytes: 1048576
1438 },
1439 external_permissions: [],
1440 sandbox_mode: "full_isolation"
1441 }
1442 HumanMachineContract {
1443 system_commitments: ["Items managed correctly"],
1444 system_refusals: ["No duplicate items"],
1445 user_obligations: ["May add or remove items"]
1446 }
1447}"#;
1448 let ast = parse_valid(input);
1449 assert_eq!(ast.behavioral_semantics.operations.len(), 2);
1450
1451 let op1 = &ast.behavioral_semantics.operations[0];
1452 assert_eq!(op1.name.value, "add_item");
1453 assert_eq!(op1.parameters.len(), 1);
1454 assert_eq!(op1.parameters[0].name.value, "item");
1455
1456 let op2 = &ast.behavioral_semantics.operations[1];
1457 assert_eq!(op2.name.value, "clear_all");
1458 assert_eq!(op2.parameters.len(), 0);
1459 }
1460
1461 #[test]
1464 fn test_parse_with_extensions() {
1465 let input = format!("{}\n\nExtensions {{\n custom_system {{\n priority: \"high\",\n tags: [\"experimental\", \"beta\"]\n }}\n}}", MINIMAL_CONTRACT);
1466 let ast = parse_valid(&input);
1467
1468 let ext = ast.extensions.as_ref().expect("Expected extensions");
1469 assert_eq!(ext.systems.len(), 1);
1470 assert_eq!(ext.systems[0].name.value, "custom_system");
1471 assert_eq!(ext.systems[0].fields.len(), 2);
1472 assert_eq!(ext.systems[0].fields[0].name.value, "priority");
1473
1474 if let LiteralValue::Array(items, _) = &ext.systems[0].fields[1].value {
1475 assert_eq!(items.len(), 2);
1476 } else {
1477 panic!("Expected array value for tags");
1478 }
1479 }
1480
1481 #[test]
1484 fn test_parse_missing_identity() {
1485 let input = r#"Contract {
1486 PurposeStatement {
1487 narrative: "No identity",
1488 intent_source: "test",
1489 confidence_level: 1.0
1490 }
1491}"#;
1492 let err = parse_err(input);
1493 assert!(err.contains("Expected Identity"), "Error: {}", err);
1494 }
1495
1496 #[test]
1497 fn test_parse_missing_closing_brace() {
1498 let input = r#"Contract {
1499 Identity {
1500 stable_id: "ic-test-001",
1501 version: 1,
1502 created_timestamp: 2026-02-01T00:00:00Z,
1503 owner: "test",
1504 semantic_hash: "0000000000000000"
1505 }
1506"#;
1507 let err = parse_err(input);
1508 assert!(
1510 err.contains("Expected") || err.contains("found"),
1511 "Error: {}",
1512 err
1513 );
1514 }
1515
1516 #[test]
1517 fn test_parse_wrong_version_type() {
1518 let input = r#"Contract {
1519 Identity {
1520 stable_id: "ic-test-001",
1521 version: "not_an_integer",
1522 created_timestamp: 2026-02-01T00:00:00Z,
1523 owner: "test",
1524 semantic_hash: "0000000000000000"
1525 }
1526}"#;
1527 let err = parse_err(input);
1528 assert!(err.contains("Expected integer literal"), "Error: {}", err);
1529 }
1530
1531 #[test]
1532 fn test_parse_confidence_out_of_range() {
1533 let input = r#"Contract {
1534 Identity {
1535 stable_id: "ic-test-001",
1536 version: 1,
1537 created_timestamp: 2026-02-01T00:00:00Z,
1538 owner: "test",
1539 semantic_hash: "0000000000000000"
1540 }
1541 PurposeStatement {
1542 narrative: "Invalid confidence",
1543 intent_source: "test",
1544 confidence_level: 2.5
1545 }
1546}"#;
1547 let err = parse_err(input);
1548 assert!(err.contains("confidence_level"), "Error: {}", err);
1549 }
1550
1551 #[test]
1552 fn test_parse_unknown_section() {
1553 let input = r#"Contract {
1554 Identity {
1555 stable_id: "ic-test-001",
1556 version: 1,
1557 created_timestamp: 2026-02-01T00:00:00Z,
1558 owner: "test",
1559 semantic_hash: "0000000000000000"
1560 }
1561 FakeSection {
1562 something: "invalid"
1563 }
1564}"#;
1565 let err = parse_err(input);
1566 assert!(
1568 err.contains("Expected") || err.contains("PurposeStatement"),
1569 "Error: {}",
1570 err
1571 );
1572 }
1573
1574 fn read_fixture(path: &str) -> String {
1577 let full = Path::new(env!("CARGO_MANIFEST_DIR"))
1578 .join("../../tests/fixtures")
1579 .join(path);
1580 fs::read_to_string(&full)
1581 .unwrap_or_else(|e| panic!("Failed to read {}: {}", full.display(), e))
1582 }
1583
1584 #[test]
1585 fn test_conformance_valid_minimal_contract() {
1586 let input = read_fixture("conformance/valid/minimal-contract.icl");
1587 let ast = parse_valid(&input);
1588 assert_eq!(ast.identity.stable_id.value, "ic-test-001");
1589 }
1590
1591 #[test]
1592 fn test_conformance_valid_all_primitive_types() {
1593 let input = read_fixture("conformance/valid/all-primitive-types.icl");
1594 let ast = parse_valid(&input);
1595 assert_eq!(ast.data_semantics.state.len(), 6);
1596 }
1597
1598 #[test]
1599 fn test_conformance_valid_composite_types() {
1600 let input = read_fixture("conformance/valid/composite-types.icl");
1601 let ast = parse_valid(&input);
1602 assert_eq!(ast.data_semantics.state.len(), 4);
1603 }
1604
1605 #[test]
1606 fn test_conformance_valid_multiple_operations() {
1607 let input = read_fixture("conformance/valid/multiple-operations.icl");
1608 let ast = parse_valid(&input);
1609 assert_eq!(ast.behavioral_semantics.operations.len(), 3);
1610 }
1611
1612 #[test]
1613 fn test_conformance_valid_with_extensions() {
1614 let input = read_fixture("conformance/valid/with-extensions.icl");
1615 let ast = parse_valid(&input);
1616 assert!(ast.extensions.is_some());
1617 }
1618
1619 #[test]
1620 fn test_conformance_invalid_missing_identity() {
1621 let input = read_fixture("conformance/invalid/missing-identity.icl");
1622 assert!(parse(&input).is_err());
1623 }
1624
1625 #[test]
1626 fn test_conformance_invalid_missing_closing_brace() {
1627 let input = read_fixture("conformance/invalid/missing-closing-brace.icl");
1628 assert!(parse(&input).is_err());
1629 }
1630
1631 #[test]
1632 fn test_conformance_invalid_wrong_version_type() {
1633 let input = read_fixture("conformance/invalid/wrong-version-type.icl");
1634 assert!(parse(&input).is_err());
1635 }
1636
1637 #[test]
1638 fn test_conformance_invalid_confidence_out_of_range() {
1639 let input = read_fixture("conformance/invalid/confidence-out-of-range.icl");
1640 assert!(parse(&input).is_err());
1641 }
1642
1643 #[test]
1644 fn test_conformance_invalid_unknown_section() {
1645 let input = read_fixture("conformance/invalid/unknown-section.icl");
1646 assert!(parse(&input).is_err());
1647 }
1648
1649 #[test]
1652 fn test_parse_determinism_100_iterations() {
1653 let first = parse(MINIMAL_CONTRACT).unwrap();
1654
1655 for i in 0..100 {
1656 let result = parse(MINIMAL_CONTRACT).unwrap();
1657 assert_eq!(first, result, "Determinism failure at iteration {}", i);
1658 }
1659 }
1660
1661 #[test]
1662 fn test_parse_determinism_complex_contract() {
1663 let input = read_fixture("conformance/valid/all-primitive-types.icl");
1664 let first = parse(&input).unwrap();
1665
1666 for i in 0..100 {
1667 let result = parse(&input).unwrap();
1668 assert_eq!(first, result, "Determinism failure at iteration {}", i);
1669 }
1670 }
1671
1672 #[test]
1675 fn test_parse_empty_input() {
1676 assert!(parse("").is_err());
1677 }
1678
1679 #[test]
1680 fn test_parse_just_contract_keyword() {
1681 assert!(parse("Contract").is_err());
1682 }
1683
1684 #[test]
1685 fn test_parse_empty_state() {
1686 let input = r#"Contract {
1688 Identity {
1689 stable_id: "ic-test-001",
1690 version: 1,
1691 created_timestamp: 2026-02-01T00:00:00Z,
1692 owner: "test",
1693 semantic_hash: "0000000000000000"
1694 }
1695 PurposeStatement {
1696 narrative: "Empty state",
1697 intent_source: "test",
1698 confidence_level: 0.5
1699 }
1700 DataSemantics {
1701 state: {},
1702 invariants: []
1703 }
1704 BehavioralSemantics {
1705 operations: []
1706 }
1707 ExecutionConstraints {
1708 trigger_types: ["manual"],
1709 resource_limits: {
1710 max_memory_bytes: 1048576,
1711 computation_timeout_ms: 100,
1712 max_state_size_bytes: 1048576
1713 },
1714 external_permissions: [],
1715 sandbox_mode: "full_isolation"
1716 }
1717 HumanMachineContract {
1718 system_commitments: [],
1719 system_refusals: [],
1720 user_obligations: []
1721 }
1722}"#;
1723 let ast = parse_valid(input);
1724 assert_eq!(ast.data_semantics.state.len(), 0);
1725 }
1726}