1use crate::{EngineError, Heap, Pointer};
2use rexlang_ast::expr::{Symbol, sym};
3use rexlang_typesystem::{AdtDecl, BuiltinTypeId, Type, TypeKind, TypeSystem};
4use serde_json::{Map, Number, Value};
5use std::collections::BTreeMap;
6
7#[derive(Clone, Debug)]
8pub struct EnumPatch {
9 pub enum_name: String,
11 pub discriminant: i64,
12}
13
14#[derive(Clone, Default, Debug)]
25pub struct JsonOptions {
26 pub int_enums: BTreeMap<String, Vec<EnumPatch>>,
27}
28
29impl JsonOptions {
30 pub fn add_int_enum(&mut self, name: &str) {
34 self.int_enums.insert(name.to_string(), vec![]);
35 }
36
37 pub fn add_int_enum_with_patches(&mut self, name: &str, patches: Vec<EnumPatch>) {
41 self.int_enums.insert(name.to_string(), patches);
42 }
43}
44
45pub fn json_to_rex(
58 heap: &Heap,
59 json: &Value,
60 want: &Type,
61 ts: &TypeSystem,
62 opts: &JsonOptions,
63) -> Result<Pointer, EngineError> {
64 match want.as_ref() {
65 TypeKind::Var(tv) => Err(error(format!(
66 "cannot decode JSON into unresolved type variable t{}",
67 tv.id
68 ))),
69 TypeKind::Con(con) => json_to_pointer_for_con(heap, json, &con.name, &[], ts, opts),
70 TypeKind::App(_, _) => {
71 let (head, args) = decompose_type_app(want);
72 if let TypeKind::Con(con) = head.as_ref() {
73 json_to_pointer_for_con(heap, json, &con.name, &args, ts, opts)
74 } else {
75 Err(error(format!("unsupported applied type {}", want)))
76 }
77 }
78 TypeKind::Fun(_, _) => Err(error("cannot decode JSON into function type".to_string())),
79 TypeKind::Tuple(items) => match json {
80 Value::Array(values) if values.len() == items.len() => {
81 let mut out = Vec::with_capacity(values.len());
82 for (value, item_ty) in values.iter().zip(items.iter()) {
83 out.push(json_to_rex(heap, value, item_ty, ts, opts)?);
84 }
85 heap.alloc_tuple(out)
86 }
87 _ => Err(type_mismatch_json(json, want)),
88 },
89 TypeKind::Record(fields) => match json {
90 Value::Object(entries) => {
91 let mut out = BTreeMap::new();
92 for (k, t) in fields {
93 let j = entries.get(k.as_ref()).unwrap_or(&Value::Null);
94 out.insert(k.clone(), json_to_rex(heap, j, t, ts, opts)?);
95 }
96 heap.alloc_dict(out)
97 }
98 _ => Err(type_mismatch_json(json, want)),
99 },
100 }
101}
102
103pub fn rex_to_json(
108 heap: &Heap,
109 pointer: &Pointer,
110 want: &Type,
111 ts: &TypeSystem,
112 opts: &JsonOptions,
113) -> Result<Value, EngineError> {
114 match want.as_ref() {
115 TypeKind::Var(tv) => Err(error(format!(
116 "cannot encode unresolved type variable t{} to JSON",
117 tv.id
118 ))),
119 TypeKind::Con(con) => pointer_to_json_for_con(heap, pointer, &con.name, &[], ts, opts),
120 TypeKind::App(_, _) => {
121 let (head, args) = decompose_type_app(want);
122 if let TypeKind::Con(con) = head.as_ref() {
123 pointer_to_json_for_con(heap, pointer, &con.name, &args, ts, opts)
124 } else {
125 Err(error(format!("unsupported applied type {}", want)))
126 }
127 }
128 TypeKind::Fun(_, _) => Err(error("cannot encode function value to JSON".to_string())),
129 TypeKind::Tuple(item_types) => {
130 let values = heap.pointer_as_tuple(pointer)?;
131 if values.len() != item_types.len() {
132 return Err(type_mismatch_pointer(heap, pointer, want));
133 }
134 let mut out = Vec::with_capacity(values.len());
135 for (p, t) in values.iter().zip(item_types.iter()) {
136 out.push(rex_to_json(heap, p, t, ts, opts)?);
137 }
138 Ok(Value::Array(out))
139 }
140 TypeKind::Record(fields) => {
141 let entries = heap.pointer_as_dict(pointer)?;
142 if entries.len() != fields.len() {
143 return Err(type_mismatch_pointer(heap, pointer, want));
144 }
145 let mut out = Map::new();
146 for (k, t) in fields {
147 let p = entries
148 .get(k)
149 .ok_or_else(|| type_mismatch_pointer(heap, pointer, want))?;
150 out.insert(k.to_string(), rex_to_json(heap, p, t, ts, opts)?);
151 }
152 Ok(Value::Object(out))
153 }
154 }
155}
156
157fn json_to_pointer_for_con(
158 heap: &Heap,
159 json: &Value,
160 con_name: &Symbol,
161 con_args: &[Type],
162 ts: &TypeSystem,
163 opts: &JsonOptions,
164) -> Result<Pointer, EngineError> {
165 match (con_name.as_ref(), con_args) {
166 ("bool", []) => match json {
167 Value::Bool(v) => heap.alloc_bool(*v),
168 _ => Err(type_mismatch_json(
169 json,
170 &Type::builtin(BuiltinTypeId::Bool),
171 )),
172 },
173
174 ("u8", []) => {
175 let v = json_u64(json)?;
176 u8::try_from(v)
177 .map_err(|_| error(format!("value {} out of range for u8", v)))
178 .and_then(|x| heap.alloc_u8(x))
179 }
180 ("u16", []) => {
181 let v = json_u64(json)?;
182 u16::try_from(v)
183 .map_err(|_| error(format!("value {} out of range for u16", v)))
184 .and_then(|x| heap.alloc_u16(x))
185 }
186 ("u32", []) => {
187 let v = json_u64(json)?;
188 u32::try_from(v)
189 .map_err(|_| error(format!("value {} out of range for u32", v)))
190 .and_then(|x| heap.alloc_u32(x))
191 }
192 ("u64", []) => heap.alloc_u64(json_u64(json)?),
193
194 ("i8", []) => {
195 let v = json_i64(json)?;
196 i8::try_from(v)
197 .map_err(|_| error(format!("value {} out of range for i8", v)))
198 .and_then(|x| heap.alloc_i8(x))
199 }
200 ("i16", []) => {
201 let v = json_i64(json)?;
202 i16::try_from(v)
203 .map_err(|_| error(format!("value {} out of range for i16", v)))
204 .and_then(|x| heap.alloc_i16(x))
205 }
206 ("i32", []) => {
207 let v = json_i64(json)?;
208 i32::try_from(v)
209 .map_err(|_| error(format!("value {} out of range for i32", v)))
210 .and_then(|x| heap.alloc_i32(x))
211 }
212 ("i64", []) => heap.alloc_i64(json_i64(json)?),
213
214 ("f32", []) => heap.alloc_f32(json_f64(json)? as f32),
215 ("f64", []) => heap.alloc_f64(json_f64(json)?),
216
217 ("string", []) => match json {
218 Value::String(s) => heap.alloc_string(s.clone()),
219 _ => Err(type_mismatch_json(
220 json,
221 &Type::builtin(BuiltinTypeId::String),
222 )),
223 },
224 ("uuid", []) => {
225 let u = serde_json::from_value(json.clone())
226 .map_err(|e| error(format!("invalid uuid JSON: {e}")))?;
227 heap.alloc_uuid(u)
228 }
229 ("datetime", []) => {
230 let dt = serde_json::from_value(json.clone())
231 .map_err(|e| error(format!("invalid datetime JSON: {e}")))?;
232 heap.alloc_datetime(dt)
233 }
234
235 ("Option", [inner]) => match json {
236 Value::Null => heap.alloc_adt(sym("None"), vec![]),
237 _ => {
238 let inner_ptr = json_to_rex(heap, json, inner, ts, opts)?;
239 heap.alloc_adt(sym("Some"), vec![inner_ptr])
240 }
241 },
242
243 ("Result", [err_t, ok_t]) => match json {
245 Value::Object(obj) if obj.len() == 1 => {
246 if let Some(v) = obj.get("Ok") {
247 let p = json_to_rex(heap, v, ok_t, ts, opts)?;
248 heap.alloc_adt(sym("Ok"), vec![p])
249 } else if let Some(v) = obj.get("Err") {
250 let p = json_to_rex(heap, v, err_t, ts, opts)?;
251 heap.alloc_adt(sym("Err"), vec![p])
252 } else {
253 Err(error(format!(
254 "expected {{Ok:..}} or {{Err:..}}, got {}",
255 json
256 )))
257 }
258 }
259 _ => Err(error(format!("expected result object JSON, got {}", json))),
260 },
261
262 ("Array", [elem_t]) => match json {
264 Value::Array(items) => {
265 let mut out = Vec::with_capacity(items.len());
266 for item in items {
267 out.push(json_to_rex(heap, item, elem_t, ts, opts)?);
268 }
269 heap.alloc_array(out)
270 }
271 _ => Err(error(format!(
272 "expected array JSON for Array, got {}",
273 json
274 ))),
275 },
276
277 ("List", [elem_t]) => match json {
278 Value::Array(items) => {
279 let mut out = Vec::with_capacity(items.len());
280 for item in items {
281 out.push(json_to_rex(heap, item, elem_t, ts, opts)?);
282 }
283 let mut list = heap.alloc_adt(sym("Empty"), vec![])?;
284 for p in out.into_iter().rev() {
285 list = heap.alloc_adt(sym("Cons"), vec![p, list])?;
286 }
287 Ok(list)
288 }
289 _ => Err(error(format!("expected array JSON for List, got {}", json))),
290 },
291
292 ("Dict", [elem_t]) => match json {
293 Value::Object(obj) => {
294 let mut out = BTreeMap::new();
295 for (k, v) in obj {
296 out.insert(sym(k), json_to_rex(heap, v, elem_t, ts, opts)?);
297 }
298 heap.alloc_dict(out)
299 }
300 _ => Err(error(format!(
301 "expected object JSON for Dict, got {}",
302 json
303 ))),
304 },
305
306 _ => json_to_pointer_for_adt(heap, json, con_name, con_args, ts, opts),
307 }
308}
309
310fn pointer_to_json_for_con(
311 heap: &Heap,
312 pointer: &Pointer,
313 con_name: &Symbol,
314 con_args: &[Type],
315 ts: &TypeSystem,
316 opts: &JsonOptions,
317) -> Result<Value, EngineError> {
318 match (con_name.as_ref(), con_args) {
319 ("bool", []) => Ok(Value::Bool(heap.pointer_as_bool(pointer)?)),
320 ("u8", []) => Ok(Value::Number(
321 u64::from(heap.pointer_as_u8(pointer)?).into(),
322 )),
323 ("u16", []) => Ok(Value::Number(
324 u64::from(heap.pointer_as_u16(pointer)?).into(),
325 )),
326 ("u32", []) => Ok(Value::Number(
327 u64::from(heap.pointer_as_u32(pointer)?).into(),
328 )),
329 ("u64", []) => Ok(Value::Number(heap.pointer_as_u64(pointer)?.into())),
330 ("i8", []) => Ok(Value::Number(
331 i64::from(heap.pointer_as_i8(pointer)?).into(),
332 )),
333 ("i16", []) => Ok(Value::Number(
334 i64::from(heap.pointer_as_i16(pointer)?).into(),
335 )),
336 ("i32", []) => Ok(Value::Number(
337 i64::from(heap.pointer_as_i32(pointer)?).into(),
338 )),
339 ("i64", []) => Ok(Value::Number(heap.pointer_as_i64(pointer)?.into())),
340 ("f32", []) => Number::from_f64(f64::from(heap.pointer_as_f32(pointer)?))
341 .map(Value::Number)
342 .ok_or_else(|| error("invalid f32 value for JSON".to_string())),
343 ("f64", []) => Number::from_f64(heap.pointer_as_f64(pointer)?)
344 .map(Value::Number)
345 .ok_or_else(|| error("invalid f64 value for JSON".to_string())),
346 ("string", []) => Ok(Value::String(heap.pointer_as_string(pointer)?)),
347 ("uuid", []) => serde_json::to_value(heap.pointer_as_uuid(pointer)?)
348 .map_err(|e| error(format!("failed to serialize uuid: {e}"))),
349 ("datetime", []) => serde_json::to_value(heap.pointer_as_datetime(pointer)?)
350 .map_err(|e| error(format!("failed to serialize datetime: {e}"))),
351
352 ("Option", [inner_t]) => {
353 let (tag, args) = heap.pointer_as_adt(pointer)?;
354 match (tag.as_ref(), args.as_slice()) {
355 ("None", []) => Ok(Value::Null),
356 ("Some", [x]) => rex_to_json(heap, x, inner_t, ts, opts),
357 _ => Err(type_mismatch_pointer(
358 heap,
359 pointer,
360 &Type::app(Type::builtin(BuiltinTypeId::Option), inner_t.clone()),
361 )),
362 }
363 }
364
365 ("Result", [err_t, ok_t]) => {
367 let (tag, args) = heap.pointer_as_adt(pointer)?;
368 match (tag.as_ref(), args.as_slice()) {
369 ("Ok", [x]) => {
370 let mut out = Map::new();
371 out.insert("Ok".to_string(), rex_to_json(heap, x, ok_t, ts, opts)?);
372 Ok(Value::Object(out))
373 }
374 ("Err", [x]) => {
375 let mut out = Map::new();
376 out.insert("Err".to_string(), rex_to_json(heap, x, err_t, ts, opts)?);
377 Ok(Value::Object(out))
378 }
379 _ => Err(type_mismatch_pointer(
380 heap,
381 pointer,
382 &Type::app(
383 Type::app(Type::builtin(BuiltinTypeId::Result), err_t.clone()),
384 ok_t.clone(),
385 ),
386 )),
387 }
388 }
389
390 ("Array", [elem_t]) => {
391 let items = heap.pointer_as_array(pointer)?;
392 let mut out = Vec::with_capacity(items.len());
393 for item in &items {
394 out.push(rex_to_json(heap, item, elem_t, ts, opts)?);
395 }
396 Ok(Value::Array(out))
397 }
398
399 ("List", [elem_t]) => {
400 let items = list_to_vec(heap, pointer)?;
401 let mut out = Vec::with_capacity(items.len());
402 for item in &items {
403 out.push(rex_to_json(heap, item, elem_t, ts, opts)?);
404 }
405 Ok(Value::Array(out))
406 }
407
408 ("Dict", [elem_t]) => {
409 let entries = heap.pointer_as_dict(pointer)?;
410 let mut out = Map::new();
411 for (k, v) in &entries {
412 out.insert(k.to_string(), rex_to_json(heap, v, elem_t, ts, opts)?);
413 }
414 Ok(Value::Object(out))
415 }
416
417 _ => pointer_to_json_for_adt(heap, pointer, con_name, con_args, ts, opts),
418 }
419}
420
421fn json_to_pointer_for_adt(
422 heap: &Heap,
423 json: &Value,
424 adt_name: &Symbol,
425 type_args: &[Type],
426 ts: &TypeSystem,
427 opts: &JsonOptions,
428) -> Result<Pointer, EngineError> {
429 let adt = ts
430 .adts
431 .get(adt_name)
432 .ok_or_else(|| error(format!("unknown ADT `{}`", adt_name)))?;
433 let subst = adt_subst(adt, type_args)?;
434
435 if adt.variants.len() == 1 {
436 let v = &adt.variants[0];
437 let arg_types = instantiate_types(&v.args, &subst);
438 return decode_direct_variant(heap, json, &v.name, &arg_types, ts, opts);
439 }
440
441 let enum_name = adt.name.to_string();
442 let enum_like = adt.variants.iter().all(|v| v.args.is_empty());
443 if enum_like {
444 if opts.int_enums.contains_key(&enum_name) {
445 if let Value::Number(n) = json
446 && let Some(i) = n.as_i64()
447 {
448 for (idx, v) in adt.variants.iter().enumerate() {
449 if variant_discriminant(&enum_name, &v.name, idx, opts) == Some(i) {
450 return heap.alloc_adt(v.name.clone(), vec![]);
451 }
452 }
453 }
454 return Err(error(format!(
455 "expected integer enum JSON for `{}`, got {}",
456 enum_name, json
457 )));
458 }
459 if let Value::String(tag) = json {
460 if let Some(v) = adt.variants.iter().find(|v| v.name.as_ref() == tag) {
461 return heap.alloc_adt(v.name.clone(), vec![]);
462 }
463 return Err(error(format!(
464 "unknown enum tag `{}` for `{}`",
465 tag, enum_name
466 )));
467 }
468 return Err(error(format!(
469 "expected enum string JSON for `{}`, got {}",
470 enum_name, json
471 )));
472 }
473
474 if let Value::String(tag) = json
475 && let Some(v) = adt
476 .variants
477 .iter()
478 .find(|v| v.args.is_empty() && v.name.as_ref() == tag)
479 {
480 return heap.alloc_adt(v.name.clone(), vec![]);
481 }
482
483 if let Value::Object(obj) = json
484 && obj.len() == 1
485 {
486 let Some((tag, payload)) = obj.iter().next() else {
487 return Err(error(format!(
488 "expected ADT JSON representation for `{}`; got {}",
489 adt_name, json
490 )));
491 };
492 if let Some(v) = adt.variants.iter().find(|v| v.name.as_ref() == tag) {
493 let arg_types = instantiate_types(&v.args, &subst);
494 return decode_wrapped_variant(heap, payload, &v.name, &arg_types, ts, opts);
495 }
496 }
497
498 Err(error(format!(
499 "expected ADT JSON representation for `{}`; got {}",
500 adt_name, json
501 )))
502}
503
504fn pointer_to_json_for_adt(
505 heap: &Heap,
506 pointer: &Pointer,
507 adt_name: &Symbol,
508 type_args: &[Type],
509 ts: &TypeSystem,
510 opts: &JsonOptions,
511) -> Result<Value, EngineError> {
512 let adt = ts
513 .adts
514 .get(adt_name)
515 .ok_or_else(|| error(format!("unknown ADT `{}`", adt_name)))?;
516 let subst = adt_subst(adt, type_args)?;
517
518 let (tag, args) = heap.pointer_as_adt(pointer)?;
519 let v = adt.variants.iter().find(|v| v.name == tag).ok_or_else(|| {
520 error(format!(
521 "constructor `{}` is not in ADT `{}`",
522 tag, adt_name
523 ))
524 })?;
525 let arg_types = instantiate_types(&v.args, &subst);
526 if args.len() != arg_types.len() {
527 return Err(error(format!(
528 "constructor `{}` expected {} args, got {}",
529 tag,
530 arg_types.len(),
531 args.len()
532 )));
533 }
534
535 if adt.variants.len() == 1 {
536 return encode_direct_variant(heap, &tag, &args, &arg_types, ts, opts);
537 }
538
539 let enum_name = adt.name.to_string();
540 let enum_like = adt.variants.iter().all(|v| v.args.is_empty());
541 if enum_like && args.is_empty() {
542 if opts.int_enums.contains_key(&enum_name) {
543 let idx = adt
544 .variants
545 .iter()
546 .position(|v| v.name == tag)
547 .ok_or_else(|| error(format!("missing enum variant `{}`", tag)))?;
548 let d = variant_discriminant(&enum_name, &tag, idx, opts).ok_or_else(|| {
549 error(format!(
550 "missing integer discriminant for enum `{}` variant `{}`",
551 enum_name, tag
552 ))
553 })?;
554 return Ok(Value::Number(d.into()));
555 }
556 return Ok(Value::String(tag.to_string()));
557 }
558
559 if args.is_empty() {
560 return Ok(Value::String(tag.to_string()));
561 }
562
563 let payload = encode_wrapped_variant(heap, &args, &arg_types, ts, opts)?;
564 let mut out = Map::new();
565 out.insert(tag.to_string(), payload);
566 Ok(Value::Object(out))
567}
568
569fn decode_direct_variant(
570 heap: &Heap,
571 json: &Value,
572 ctor: &Symbol,
573 arg_types: &[Type],
574 ts: &TypeSystem,
575 opts: &JsonOptions,
576) -> Result<Pointer, EngineError> {
577 match arg_types {
578 [] => match json {
579 Value::Null => heap.alloc_adt(ctor.clone(), vec![]),
580 Value::String(tag) if tag == ctor.as_ref() => heap.alloc_adt(ctor.clone(), vec![]),
581 _ => Err(error(format!(
582 "expected null or `{}` for unit constructor, got {}",
583 ctor, json
584 ))),
585 },
586 [t0] => {
587 let p = json_to_rex(heap, json, t0, ts, opts)?;
588 heap.alloc_adt(ctor.clone(), vec![p])
589 }
590 _ => match json {
591 Value::Array(items) if items.len() == arg_types.len() => {
592 let mut args = Vec::with_capacity(items.len());
593 for (item, t) in items.iter().zip(arg_types.iter()) {
594 args.push(json_to_rex(heap, item, t, ts, opts)?);
595 }
596 heap.alloc_adt(ctor.clone(), args)
597 }
598 _ => Err(error(format!(
599 "expected array payload for constructor `{}`, got {}",
600 ctor, json
601 ))),
602 },
603 }
604}
605
606fn decode_wrapped_variant(
607 heap: &Heap,
608 payload: &Value,
609 ctor: &Symbol,
610 arg_types: &[Type],
611 ts: &TypeSystem,
612 opts: &JsonOptions,
613) -> Result<Pointer, EngineError> {
614 match arg_types {
615 [] => heap.alloc_adt(ctor.clone(), vec![]),
616 [t0] => {
617 let p = json_to_rex(heap, payload, t0, ts, opts)?;
618 heap.alloc_adt(ctor.clone(), vec![p])
619 }
620 _ => match payload {
621 Value::Array(items) if items.len() == arg_types.len() => {
622 let mut args = Vec::with_capacity(items.len());
623 for (item, t) in items.iter().zip(arg_types.iter()) {
624 args.push(json_to_rex(heap, item, t, ts, opts)?);
625 }
626 heap.alloc_adt(ctor.clone(), args)
627 }
628 _ => Err(error(format!(
629 "expected array payload for constructor `{}`, got {}",
630 ctor, payload
631 ))),
632 },
633 }
634}
635
636fn encode_direct_variant(
637 heap: &Heap,
638 ctor: &Symbol,
639 args: &[Pointer],
640 arg_types: &[Type],
641 ts: &TypeSystem,
642 opts: &JsonOptions,
643) -> Result<Value, EngineError> {
644 match arg_types {
645 [] => Ok(Value::String(ctor.to_string())),
646 [t0] => rex_to_json(heap, &args[0], t0, ts, opts),
647 _ => {
648 let mut out = Vec::with_capacity(args.len());
649 for (arg, t) in args.iter().zip(arg_types.iter()) {
650 out.push(rex_to_json(heap, arg, t, ts, opts)?);
651 }
652 Ok(Value::Array(out))
653 }
654 }
655}
656
657fn encode_wrapped_variant(
658 heap: &Heap,
659 args: &[Pointer],
660 arg_types: &[Type],
661 ts: &TypeSystem,
662 opts: &JsonOptions,
663) -> Result<Value, EngineError> {
664 match arg_types {
665 [] => Ok(Value::Null),
666 [t0] => rex_to_json(heap, &args[0], t0, ts, opts),
667 _ => {
668 let mut out = Vec::with_capacity(args.len());
669 for (arg, t) in args.iter().zip(arg_types.iter()) {
670 out.push(rex_to_json(heap, arg, t, ts, opts)?);
671 }
672 Ok(Value::Array(out))
673 }
674 }
675}
676
677fn decompose_type_app(typ: &Type) -> (Type, Vec<Type>) {
678 let mut args = Vec::new();
679 let mut cur = typ.clone();
680 while let TypeKind::App(f, a) = cur.as_ref() {
681 args.push(a.clone());
682 cur = f.clone();
683 }
684 args.reverse();
685 (cur, args)
686}
687
688fn adt_subst(adt: &AdtDecl, type_args: &[Type]) -> Result<BTreeMap<usize, Type>, EngineError> {
689 if adt.params.len() != type_args.len() {
690 return Err(error(format!(
691 "ADT `{}` expects {} type args, got {}",
692 adt.name,
693 adt.params.len(),
694 type_args.len()
695 )));
696 }
697 let mut subst = BTreeMap::new();
698 for (param, arg) in adt.params.iter().zip(type_args.iter()) {
699 subst.insert(param.var.id, arg.clone());
700 }
701 Ok(subst)
702}
703
704fn instantiate_types(ts: &[Type], subst: &BTreeMap<usize, Type>) -> Vec<Type> {
705 ts.iter().map(|t| instantiate_type(t, subst)).collect()
706}
707
708fn instantiate_type(t: &Type, subst: &BTreeMap<usize, Type>) -> Type {
709 match t.as_ref() {
710 TypeKind::Var(tv) => subst.get(&tv.id).cloned().unwrap_or_else(|| t.clone()),
711 TypeKind::Con(_) => t.clone(),
712 TypeKind::App(f, a) => Type::app(instantiate_type(f, subst), instantiate_type(a, subst)),
713 TypeKind::Fun(a, b) => Type::fun(instantiate_type(a, subst), instantiate_type(b, subst)),
714 TypeKind::Tuple(xs) => Type::tuple(xs.iter().map(|x| instantiate_type(x, subst)).collect()),
715 TypeKind::Record(fields) => Type::record(
716 fields
717 .iter()
718 .map(|(k, v)| (k.clone(), instantiate_type(v, subst)))
719 .collect(),
720 ),
721 }
722}
723
724fn variant_discriminant(
725 enum_type_name: &str,
726 variant_name: &Symbol,
727 idx: usize,
728 opts: &JsonOptions,
729) -> Option<i64> {
730 let patches = opts.int_enums.get(enum_type_name)?;
731 for p in patches {
732 if p.enum_name == variant_name.as_ref() {
733 return Some(p.discriminant);
734 }
735 }
736 Some(idx as i64)
737}
738
739fn list_to_vec(heap: &Heap, pointer: &Pointer) -> Result<Vec<Pointer>, EngineError> {
740 let mut out = Vec::new();
741 let mut cur = *pointer;
742 loop {
743 let (tag, args) = heap.pointer_as_adt(&cur)?;
744 if tag.as_ref() == "Empty" && args.is_empty() {
745 return Ok(out);
746 }
747 if tag.as_ref() == "Cons" && args.len() == 2 {
748 out.push(args[0]);
749 cur = args[1];
750 continue;
751 }
752 return Err(error(format!(
753 "expected list ADT chain (Cons/Empty), found constructor `{}`",
754 tag
755 )));
756 }
757}
758
759fn json_u64(json: &Value) -> Result<u64, EngineError> {
760 match json {
761 Value::Number(n) => n
762 .as_u64()
763 .ok_or_else(|| error(format!("expected unsigned integer JSON, got {}", json))),
764 _ => Err(error(format!(
765 "expected unsigned integer JSON, got {}",
766 json
767 ))),
768 }
769}
770
771fn json_i64(json: &Value) -> Result<i64, EngineError> {
772 match json {
773 Value::Number(n) => n
774 .as_i64()
775 .ok_or_else(|| error(format!("expected signed integer JSON, got {}", json))),
776 _ => Err(error(format!("expected signed integer JSON, got {}", json))),
777 }
778}
779
780fn json_f64(json: &Value) -> Result<f64, EngineError> {
781 match json {
782 Value::Number(n) => n
783 .as_f64()
784 .ok_or_else(|| error(format!("expected floating-point JSON, got {}", json))),
785 _ => Err(error(format!("expected floating-point JSON, got {}", json))),
786 }
787}
788
789fn error(msg: String) -> EngineError {
790 EngineError::Custom(msg)
791}
792
793fn type_mismatch_json(json: &Value, want: &Type) -> EngineError {
794 error(format!(
795 "JSON value {} does not match Rex type {}",
796 json, want
797 ))
798}
799
800fn type_mismatch_pointer(heap: &Heap, pointer: &Pointer, want: &Type) -> EngineError {
801 match heap.type_name(pointer) {
802 Ok(got) => error(format!(
803 "Rex value of runtime kind `{}` does not match Rex type {}",
804 got, want
805 )),
806 Err(e) => e,
807 }
808}