1use indexmap::IndexMap;
25use serde::de::Deserializer;
26use serde::ser::{SerializeMap, Serializer};
27use serde::{Deserialize, Serialize};
28
29use super::attributes::ValueAttributes;
30use super::literal::Literal;
31use super::pattern::Pattern;
32use super::types::{Incompleteness, Type};
33use crate::naming::{FQName, Name};
34
35#[derive(Debug, Clone, PartialEq)]
51pub enum Value {
52 Literal(ValueAttributes, Literal),
57
58 Constructor(ValueAttributes, FQName),
62
63 Tuple(ValueAttributes, Vec<Value>),
67
68 List(ValueAttributes, Vec<Value>),
72
73 Record(ValueAttributes, Vec<RecordFieldEntry>),
77
78 Variable(ValueAttributes, Name),
82
83 Reference(ValueAttributes, FQName),
87
88 Field(ValueAttributes, Box<Value>, Name),
92
93 FieldFunction(ValueAttributes, Name),
97
98 Apply(ValueAttributes, Box<Value>, Box<Value>),
102
103 Lambda(ValueAttributes, Pattern, Box<Value>),
107
108 LetDefinition(ValueAttributes, Name, Box<ValueDefinition>, Box<Value>),
112
113 LetRecursion(ValueAttributes, Vec<LetBinding>, Box<Value>),
117
118 Destructure(ValueAttributes, Pattern, Box<Value>, Box<Value>),
122
123 IfThenElse(ValueAttributes, Box<Value>, Box<Value>, Box<Value>),
127
128 PatternMatch(ValueAttributes, Box<Value>, Vec<PatternCase>),
132
133 UpdateRecord(ValueAttributes, Box<Value>, Vec<RecordFieldEntry>),
137
138 Unit(ValueAttributes),
142
143 Hole(ValueAttributes, HoleReason, Option<Box<Type>>),
156}
157
158#[derive(Debug, Clone, PartialEq)]
164pub enum HoleReason {
165 UnresolvedReference { target: FQName },
167 DeletedDuringRefactor {
169 tx_id: String,
171 },
172 TypeMismatch {
174 expected: String,
176 found: String,
178 },
179}
180
181#[derive(Debug, Clone, PartialEq)]
183pub enum NativeHint {
184 Arithmetic,
185 Comparison,
186 StringOp,
187 CollectionOp,
188 PlatformSpecific {
189 platform: String,
191 },
192}
193
194#[derive(Debug, Clone, PartialEq, Serialize)]
199pub struct NativeInfo {
200 pub hint: NativeHint,
201 #[serde(skip_serializing_if = "Option::is_none")]
202 pub description: Option<String>,
203}
204
205impl<'de> Deserialize<'de> for NativeInfo {
206 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
207 where
208 D: Deserializer<'de>,
209 {
210 super::serde_document::deserialize_with(
211 deserializer,
212 super::serde_document::decode_native_info,
213 )
214 }
215}
216
217#[derive(Debug, Clone, PartialEq)]
222pub struct InputType(pub Name, pub Type);
223
224#[derive(Debug, Clone, PartialEq)]
228pub struct RecordFieldEntry(pub Name, pub Value);
229
230#[derive(Debug, Clone, PartialEq)]
232pub struct PatternCase(pub Pattern, pub Value);
233
234#[derive(Debug, Clone, PartialEq)]
236pub struct LetBinding(pub Name, pub ValueDefinition);
237
238#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
243#[serde(rename_all = "camelCase")]
244pub struct ExternalBinding {
245 pub target_platform: String,
246 pub external_name: String,
247}
248
249#[derive(Debug, Clone, PartialEq)]
256#[allow(clippy::large_enum_variant)]
257pub enum ValueBody {
258 Expression(Value),
260
261 Native { native_info: NativeInfo },
263
264 External {
266 externals: Vec<ExternalBinding>,
267 fallback: Option<Box<Value>>,
268 },
269
270 Incomplete {
277 incompleteness: Incompleteness,
278 partial_body: Option<Box<Value>>,
279 },
280}
281
282impl Value {
283 pub fn attributes(&self) -> &ValueAttributes {
285 match self {
286 Value::Literal(a, _) => a,
287 Value::Constructor(a, _) => a,
288 Value::Tuple(a, _) => a,
289 Value::List(a, _) => a,
290 Value::Record(a, _) => a,
291 Value::Variable(a, _) => a,
292 Value::Reference(a, _) => a,
293 Value::Field(a, _, _) => a,
294 Value::FieldFunction(a, _) => a,
295 Value::Apply(a, _, _) => a,
296 Value::Lambda(a, _, _) => a,
297 Value::LetDefinition(a, _, _, _) => a,
298 Value::LetRecursion(a, _, _) => a,
299 Value::Destructure(a, _, _, _) => a,
300 Value::IfThenElse(a, _, _, _) => a,
301 Value::PatternMatch(a, _, _) => a,
302 Value::UpdateRecord(a, _, _) => a,
303 Value::Unit(a) => a,
304 Value::Hole(a, _, _) => a,
305 }
306 }
307
308 pub fn literal(attrs: ValueAttributes, lit: Literal) -> Self {
310 Value::Literal(attrs, lit)
311 }
312
313 pub fn variable(attrs: ValueAttributes, name: Name) -> Self {
315 Value::Variable(attrs, name)
316 }
317
318 pub fn constructor(attrs: ValueAttributes, name: FQName) -> Self {
320 Value::Constructor(attrs, name)
321 }
322
323 pub fn tuple(attrs: ValueAttributes, elements: Vec<Value>) -> Self {
325 Value::Tuple(attrs, elements)
326 }
327
328 pub fn list(attrs: ValueAttributes, elements: Vec<Value>) -> Self {
330 Value::List(attrs, elements)
331 }
332
333 pub fn record(attrs: ValueAttributes, fields: Vec<RecordFieldEntry>) -> Self {
335 Value::Record(attrs, fields)
336 }
337
338 pub fn apply(attrs: ValueAttributes, function: Value, argument: Value) -> Self {
340 Value::Apply(attrs, Box::new(function), Box::new(argument))
341 }
342
343 pub fn lambda(attrs: ValueAttributes, pattern: Pattern, body: Value) -> Self {
345 Value::Lambda(attrs, pattern, Box::new(body))
346 }
347
348 pub fn if_then_else(
350 attrs: ValueAttributes,
351 condition: Value,
352 then_branch: Value,
353 else_branch: Value,
354 ) -> Self {
355 Value::IfThenElse(
356 attrs,
357 Box::new(condition),
358 Box::new(then_branch),
359 Box::new(else_branch),
360 )
361 }
362
363 pub fn unit(attrs: ValueAttributes) -> Self {
365 Value::Unit(attrs)
366 }
367}
368
369impl InputType {
371 pub fn new(name: Name, tpe: Type) -> Self {
373 InputType(name, tpe)
374 }
375
376 pub fn name(&self) -> &Name {
378 &self.0
379 }
380
381 pub fn tpe(&self) -> &Type {
383 &self.1
384 }
385}
386
387impl RecordFieldEntry {
388 pub fn new(name: Name, value: Value) -> Self {
390 RecordFieldEntry(name, value)
391 }
392
393 pub fn name(&self) -> &Name {
395 &self.0
396 }
397
398 pub fn value(&self) -> &Value {
400 &self.1
401 }
402}
403
404impl PatternCase {
405 pub fn new(pattern: Pattern, body: Value) -> Self {
407 PatternCase(pattern, body)
408 }
409
410 pub fn pattern(&self) -> &Pattern {
412 &self.0
413 }
414
415 pub fn body(&self) -> &Value {
417 &self.1
418 }
419}
420
421impl LetBinding {
422 pub fn new(name: Name, definition: ValueDefinition) -> Self {
424 LetBinding(name, definition)
425 }
426
427 pub fn name(&self) -> &Name {
429 &self.0
430 }
431
432 pub fn definition(&self) -> &ValueDefinition {
434 &self.1
435 }
436}
437
438impl NativeInfo {
439 pub fn new(hint: NativeHint, description: Option<String>) -> Self {
441 NativeInfo { hint, description }
442 }
443}
444
445#[derive(Debug, Clone, PartialEq)]
456pub struct ValueSpecification {
457 pub annotations: super::annotation::Annotations,
460 pub inputs: IndexMap<String, Type>,
461 pub output: Type,
462}
463
464impl Serialize for ValueSpecification {
465 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
466 where
467 S: Serializer,
468 {
469 let mut map = serializer.serialize_map(None)?;
470 if !self.annotations.is_empty() {
471 map.serialize_entry("annotations", &self.annotations)?;
472 }
473 if !self.inputs.is_empty() {
475 map.serialize_entry("inputs", &self.inputs)?;
476 }
477 map.serialize_entry("output", &self.output)?;
478 map.end()
479 }
480}
481
482impl<'de> Deserialize<'de> for ValueSpecification {
483 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
484 where
485 D: Deserializer<'de>,
486 {
487 super::serde_document::deserialize_standalone_with(
488 deserializer,
489 super::serde_document::decode_value_specification,
490 )
491 }
492}
493
494#[derive(Debug, Clone, PartialEq)]
502pub struct ValueDefinition {
503 pub input_types: IndexMap<String, Type>,
504 pub output_type: Option<Type>,
505 pub body: ValueBody,
506}
507
508#[derive(Serialize)]
509#[serde(rename_all = "camelCase")]
510struct ExpressionDefinitionContent<'a> {
511 input_types: &'a IndexMap<String, Type>,
512 output_type: &'a Type,
513 body: &'a Value,
514}
515
516#[derive(Serialize)]
517#[serde(rename_all = "camelCase")]
518struct NativeDefinitionContent<'a> {
519 input_types: &'a IndexMap<String, Type>,
520 output_type: &'a Type,
521 native_info: &'a NativeInfo,
522}
523
524#[derive(Serialize)]
525#[serde(rename_all = "camelCase")]
526struct ExternalDefinitionContent<'a> {
527 input_types: &'a IndexMap<String, Type>,
528 output_type: &'a Type,
529 externals: &'a [ExternalBinding],
530 #[serde(skip_serializing_if = "Option::is_none")]
531 body: Option<&'a Value>,
532}
533
534#[derive(Serialize)]
535#[serde(rename_all = "camelCase")]
536struct IncompleteDefinitionContent<'a> {
537 input_types: &'a IndexMap<String, Type>,
538 #[serde(skip_serializing_if = "Option::is_none")]
539 output_type: Option<&'a Type>,
540 incompleteness: &'a Incompleteness,
541 #[serde(rename = "partialBody", skip_serializing_if = "Option::is_none")]
542 partial_body: Option<&'a Value>,
543}
544
545impl Serialize for ValueDefinition {
546 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
547 where
548 S: Serializer,
549 {
550 let mut map = serializer.serialize_map(Some(1))?;
551 match &self.body {
552 ValueBody::Expression(body) => map.serialize_entry(
553 "ExpressionBody",
554 &ExpressionDefinitionContent {
555 input_types: &self.input_types,
556 output_type: self.output_type.as_ref().ok_or_else(|| {
557 serde::ser::Error::custom("ExpressionBody requires outputType")
558 })?,
559 body,
560 },
561 )?,
562 ValueBody::Native { native_info } => map.serialize_entry(
563 "NativeBody",
564 &NativeDefinitionContent {
565 input_types: &self.input_types,
566 output_type: self.output_type.as_ref().ok_or_else(|| {
567 serde::ser::Error::custom("NativeBody requires outputType")
568 })?,
569 native_info,
570 },
571 )?,
572 ValueBody::External {
573 externals,
574 fallback,
575 } => map.serialize_entry(
576 "ExternalBody",
577 &ExternalDefinitionContent {
578 input_types: &self.input_types,
579 output_type: self.output_type.as_ref().ok_or_else(|| {
580 serde::ser::Error::custom("ExternalBody requires outputType")
581 })?,
582 externals,
583 body: fallback.as_deref(),
584 },
585 )?,
586 ValueBody::Incomplete {
587 incompleteness,
588 partial_body,
589 } => map.serialize_entry(
590 "IncompleteBody",
591 &IncompleteDefinitionContent {
592 input_types: &self.input_types,
593 output_type: self.output_type.as_ref(),
594 incompleteness,
595 partial_body: partial_body.as_deref(),
596 },
597 )?,
598 }
599 map.end()
600 }
601}
602
603impl<'de> Deserialize<'de> for ValueDefinition {
604 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
605 where
606 D: Deserializer<'de>,
607 {
608 super::serde_document::deserialize_standalone_with(
609 deserializer,
610 super::serde_document::decode_value_definition,
611 )
612 }
613}
614impl ValueDefinition {
615 pub fn new(input_types: Vec<InputType>, output_type: Type, body: Value) -> Self {
617 let inputs = input_types
618 .into_iter()
619 .map(|InputType(name, tpe)| (name.to_string(), tpe))
620 .collect();
621
622 ValueDefinition {
623 input_types: inputs,
624 output_type: Some(output_type),
625 body: ValueBody::Expression(body),
626 }
627 }
628
629 pub fn native(input_types: Vec<InputType>, output_type: Type, info: NativeInfo) -> Self {
631 let inputs = input_types
632 .into_iter()
633 .map(|InputType(name, tpe)| (name.to_string(), tpe))
634 .collect();
635
636 ValueDefinition {
637 input_types: inputs,
638 output_type: Some(output_type),
639 body: ValueBody::Native { native_info: info },
640 }
641 }
642}
643
644impl Serialize for ValueBody {
649 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
650 where
651 S: Serializer,
652 {
653 let mut map = serializer.serialize_map(Some(1))?;
654 match self {
655 ValueBody::Expression(body) => {
656 map.serialize_entry("ExpressionBody", &ExpressionBodySerContent { body })?;
657 }
658 ValueBody::Native { native_info } => {
659 map.serialize_entry("NativeBody", &NativeBodySerContent { native_info })?;
660 }
661 ValueBody::External {
662 externals,
663 fallback,
664 } => {
665 map.serialize_entry(
666 "ExternalBody",
667 &ExternalBodySerContent {
668 externals,
669 body: fallback.as_deref(),
670 },
671 )?;
672 }
673 ValueBody::Incomplete {
674 incompleteness,
675 partial_body,
676 } => {
677 map.serialize_entry(
678 "IncompleteBody",
679 &IncompleteBodySerContent {
680 incompleteness,
681 partial_body: partial_body.as_deref(),
682 },
683 )?;
684 }
685 }
686 map.end()
687 }
688}
689
690#[derive(Serialize)]
691#[serde(rename_all = "camelCase")]
692struct ExpressionBodySerContent<'a> {
693 body: &'a Value,
694}
695
696#[derive(Serialize)]
697#[serde(rename_all = "camelCase")]
698struct NativeBodySerContent<'a> {
699 native_info: &'a NativeInfo,
700}
701
702#[derive(Serialize)]
703#[serde(rename_all = "camelCase")]
704struct ExternalBodySerContent<'a> {
705 externals: &'a [ExternalBinding],
706 #[serde(skip_serializing_if = "Option::is_none")]
707 body: Option<&'a Value>,
708}
709
710#[derive(Serialize)]
711#[serde(rename_all = "camelCase")]
712struct IncompleteBodySerContent<'a> {
713 incompleteness: &'a Incompleteness,
714 #[serde(rename = "partialBody", skip_serializing_if = "Option::is_none")]
715 partial_body: Option<&'a Value>,
716}
717
718impl<'de> Deserialize<'de> for ValueBody {
719 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
720 where
721 D: Deserializer<'de>,
722 {
723 super::serde_document::deserialize_standalone_with(
724 deserializer,
725 super::serde_document::decode_value_body,
726 )
727 }
728}
729impl Serialize for NativeHint {
734 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
735 where
736 S: Serializer,
737 {
738 let mut map = serializer.serialize_map(Some(1))?;
739 match self {
740 NativeHint::Arithmetic => map.serialize_entry("Arithmetic", &serde_json::json!({}))?,
741 NativeHint::Comparison => map.serialize_entry("Comparison", &serde_json::json!({}))?,
742 NativeHint::StringOp => map.serialize_entry("StringOp", &serde_json::json!({}))?,
743 NativeHint::CollectionOp => {
744 map.serialize_entry("CollectionOp", &serde_json::json!({}))?
745 }
746 NativeHint::PlatformSpecific { platform } => map.serialize_entry(
747 "PlatformSpecific",
748 &serde_json::json!({ "platform": platform }),
749 )?,
750 }
751 map.end()
752 }
753}
754
755impl<'de> Deserialize<'de> for NativeHint {
756 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
757 where
758 D: Deserializer<'de>,
759 {
760 super::serde_document::deserialize_with(
761 deserializer,
762 super::serde_document::decode_native_hint,
763 )
764 }
765}
766
767impl Serialize for HoleReason {
772 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
773 where
774 S: Serializer,
775 {
776 let mut map = serializer.serialize_map(Some(1))?;
777 match self {
778 HoleReason::TypeMismatch { expected, found } => map.serialize_entry(
779 "TypeMismatch",
780 &serde_json::json!({ "expected": expected, "found": found }),
781 )?,
782 HoleReason::DeletedDuringRefactor { tx_id } => map.serialize_entry(
783 "DeletedDuringRefactor",
784 &serde_json::json!({ "tx-id": tx_id }),
785 )?,
786 HoleReason::UnresolvedReference { target } => map.serialize_entry(
787 "UnresolvedReference",
788 &serde_json::json!({ "target": target.to_canonical_string() }),
789 )?,
790 }
791 map.end()
792 }
793}
794
795impl<'de> Deserialize<'de> for HoleReason {
796 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
797 where
798 D: Deserializer<'de>,
799 {
800 super::serde_document::deserialize_with(
801 deserializer,
802 super::serde_document::decode_hole_reason,
803 )
804 }
805}
806
807#[cfg(test)]
812mod tests {
813 use super::super::attributes::TypeAttributes;
814 use super::*;
815
816 #[test]
818 fn test_literal_value() {
819 let val: Value = Value::literal(ValueAttributes::default(), Literal::Integer(42.into()));
820 assert!(matches!(
821 val,
822 Value::Literal(_, Literal::Integer(n)) if n == num_bigint::BigInt::from(42)
823 ));
824 }
825
826 #[test]
827 fn test_variable_value() {
828 let val: Value = Value::variable(ValueAttributes::default(), Name::from("x"));
829 assert!(matches!(val, Value::Variable(_, _)));
830 }
831
832 #[test]
833 fn test_unit_value() {
834 let val: Value = Value::unit(ValueAttributes::default());
835 assert!(matches!(val, Value::Unit(_)));
836 }
837
838 #[test]
839 fn test_tuple_value() {
840 let val: Value = Value::tuple(
841 ValueAttributes::default(),
842 vec![
843 Value::unit(ValueAttributes::default()),
844 Value::unit(ValueAttributes::default()),
845 ],
846 );
847 assert!(matches!(val, Value::Tuple(_, elements) if elements.len() == 2));
848 }
849
850 #[test]
851 fn test_lambda_value() {
852 let val: Value = Value::lambda(
853 ValueAttributes::default(),
854 Pattern::wildcard(ValueAttributes::default()),
855 Value::unit(ValueAttributes::default()),
856 );
857 assert!(matches!(val, Value::Lambda(_, _, _)));
858 }
859
860 #[test]
861 fn test_value_definition() {
862 let def: ValueDefinition = ValueDefinition::new(
863 vec![],
864 Type::unit(TypeAttributes::default()),
865 Value::unit(ValueAttributes::default()),
866 );
867 assert!(matches!(def.body, ValueBody::Expression(_)));
868 }
869
870 #[test]
871 fn test_hole_value() {
872 let val: Value = Value::Hole(
873 ValueAttributes::default(),
874 HoleReason::TypeMismatch {
875 expected: "Int".to_string(),
876 found: "String".to_string(),
877 },
878 None,
879 );
880 assert!(matches!(
881 val,
882 Value::Hole(_, HoleReason::TypeMismatch { .. }, None)
883 ));
884 }
885
886 #[test]
887 fn test_native_value_definition() {
888 let def: ValueDefinition = ValueDefinition::native(
889 vec![],
890 Type::unit(TypeAttributes::default()),
891 NativeInfo::new(NativeHint::Arithmetic, Some("add operation".to_string())),
892 );
893 assert!(matches!(def.body, ValueBody::Native { .. }));
894 }
895
896 #[test]
898 fn test_native_hint_wrapper_format() {
899 let hint = NativeHint::Arithmetic;
900 let json = serde_json::to_string(&hint).unwrap();
901 assert!(json.contains("\"Arithmetic\""));
902 assert!(json.contains("{}"));
903 }
904
905 #[test]
906 fn test_hole_reason_with_target() {
907 let reason = HoleReason::UnresolvedReference {
908 target: FQName::from_canonical_string("my/pkg:mod#func").unwrap(),
909 };
910 let json = serde_json::to_string(&reason).unwrap();
911 assert!(json.contains("\"UnresolvedReference\""));
912 assert!(json.contains("\"target\""));
913 assert!(json.contains("my/pkg:mod#func"));
915 }
916
917 #[test]
918 fn test_value_body_expression_wrapper() {
919 let body = ValueBody::Expression(Value::Unit(ValueAttributes::default()));
920 let json = serde_json::to_string(&body).unwrap();
921 assert!(json.contains("\"ExpressionBody\""));
922 assert!(json.contains("\"body\""));
923 }
924}