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 ("Promise", [_inner]) => {
244 let promise_id =
245 json_to_rex(heap, json, &Type::builtin(BuiltinTypeId::Uuid), ts, opts)?;
246 heap.alloc_adt(sym("Promise"), vec![promise_id])
247 }
248
249 ("Result", [err_t, ok_t]) => match json {
251 Value::Object(obj) if obj.len() == 1 => {
252 if let Some(v) = obj.get("Ok") {
253 let p = json_to_rex(heap, v, ok_t, ts, opts)?;
254 heap.alloc_adt(sym("Ok"), vec![p])
255 } else if let Some(v) = obj.get("Err") {
256 let p = json_to_rex(heap, v, err_t, ts, opts)?;
257 heap.alloc_adt(sym("Err"), vec![p])
258 } else {
259 Err(error(format!(
260 "expected {{Ok:..}} or {{Err:..}}, got {}",
261 json
262 )))
263 }
264 }
265 _ => Err(error(format!("expected result object JSON, got {}", json))),
266 },
267
268 ("Array", [elem_t]) => match json {
270 Value::Array(items) => {
271 let mut out = Vec::with_capacity(items.len());
272 for item in items {
273 out.push(json_to_rex(heap, item, elem_t, ts, opts)?);
274 }
275 heap.alloc_array(out)
276 }
277 _ => Err(error(format!(
278 "expected array JSON for Array, got {}",
279 json
280 ))),
281 },
282
283 ("List", [elem_t]) => match json {
284 Value::Array(items) => {
285 let mut out = Vec::with_capacity(items.len());
286 for item in items {
287 out.push(json_to_rex(heap, item, elem_t, ts, opts)?);
288 }
289 let mut list = heap.alloc_adt(sym("Empty"), vec![])?;
290 for p in out.into_iter().rev() {
291 list = heap.alloc_adt(sym("Cons"), vec![p, list])?;
292 }
293 Ok(list)
294 }
295 _ => Err(error(format!("expected array JSON for List, got {}", json))),
296 },
297
298 ("Dict", [elem_t]) => match json {
299 Value::Object(obj) => {
300 let mut out = BTreeMap::new();
301 for (k, v) in obj {
302 out.insert(sym(k), json_to_rex(heap, v, elem_t, ts, opts)?);
303 }
304 heap.alloc_dict(out)
305 }
306 _ => Err(error(format!(
307 "expected object JSON for Dict, got {}",
308 json
309 ))),
310 },
311
312 _ => json_to_pointer_for_adt(heap, json, con_name, con_args, ts, opts),
313 }
314}
315
316fn pointer_to_json_for_con(
317 heap: &Heap,
318 pointer: &Pointer,
319 con_name: &Symbol,
320 con_args: &[Type],
321 ts: &TypeSystem,
322 opts: &JsonOptions,
323) -> Result<Value, EngineError> {
324 match (con_name.as_ref(), con_args) {
325 ("bool", []) => Ok(Value::Bool(heap.pointer_as_bool(pointer)?)),
326 ("u8", []) => Ok(Value::Number(
327 u64::from(heap.pointer_as_u8(pointer)?).into(),
328 )),
329 ("u16", []) => Ok(Value::Number(
330 u64::from(heap.pointer_as_u16(pointer)?).into(),
331 )),
332 ("u32", []) => Ok(Value::Number(
333 u64::from(heap.pointer_as_u32(pointer)?).into(),
334 )),
335 ("u64", []) => Ok(Value::Number(heap.pointer_as_u64(pointer)?.into())),
336 ("i8", []) => Ok(Value::Number(
337 i64::from(heap.pointer_as_i8(pointer)?).into(),
338 )),
339 ("i16", []) => Ok(Value::Number(
340 i64::from(heap.pointer_as_i16(pointer)?).into(),
341 )),
342 ("i32", []) => Ok(Value::Number(
343 i64::from(heap.pointer_as_i32(pointer)?).into(),
344 )),
345 ("i64", []) => Ok(Value::Number(heap.pointer_as_i64(pointer)?.into())),
346 ("f32", []) => Number::from_f64(f64::from(heap.pointer_as_f32(pointer)?))
347 .map(Value::Number)
348 .ok_or_else(|| error("invalid f32 value for JSON".to_string())),
349 ("f64", []) => Number::from_f64(heap.pointer_as_f64(pointer)?)
350 .map(Value::Number)
351 .ok_or_else(|| error("invalid f64 value for JSON".to_string())),
352 ("string", []) => Ok(Value::String(heap.pointer_as_string(pointer)?)),
353 ("uuid", []) => serde_json::to_value(heap.pointer_as_uuid(pointer)?)
354 .map_err(|e| error(format!("failed to serialize uuid: {e}"))),
355 ("datetime", []) => serde_json::to_value(heap.pointer_as_datetime(pointer)?)
356 .map_err(|e| error(format!("failed to serialize datetime: {e}"))),
357
358 ("Option", [inner_t]) => {
359 let (tag, args) = heap.pointer_as_adt(pointer)?;
360 match (tag.as_ref(), args.as_slice()) {
361 ("None", []) => Ok(Value::Null),
362 ("Some", [x]) => rex_to_json(heap, x, inner_t, ts, opts),
363 _ => Err(type_mismatch_pointer(
364 heap,
365 pointer,
366 &Type::app(Type::builtin(BuiltinTypeId::Option), inner_t.clone()),
367 )),
368 }
369 }
370
371 ("Promise", [inner_t]) => {
372 let (tag, args) = heap.pointer_as_adt(pointer)?;
373 match (tag.as_ref(), args.as_slice()) {
374 ("Promise", [promise_id]) => rex_to_json(
375 heap,
376 promise_id,
377 &Type::builtin(BuiltinTypeId::Uuid),
378 ts,
379 opts,
380 ),
381 _ => Err(type_mismatch_pointer(
382 heap,
383 pointer,
384 &Type::app(Type::builtin(BuiltinTypeId::Promise), inner_t.clone()),
385 )),
386 }
387 }
388
389 ("Result", [err_t, ok_t]) => {
391 let (tag, args) = heap.pointer_as_adt(pointer)?;
392 match (tag.as_ref(), args.as_slice()) {
393 ("Ok", [x]) => {
394 let mut out = Map::new();
395 out.insert("Ok".to_string(), rex_to_json(heap, x, ok_t, ts, opts)?);
396 Ok(Value::Object(out))
397 }
398 ("Err", [x]) => {
399 let mut out = Map::new();
400 out.insert("Err".to_string(), rex_to_json(heap, x, err_t, ts, opts)?);
401 Ok(Value::Object(out))
402 }
403 _ => Err(type_mismatch_pointer(
404 heap,
405 pointer,
406 &Type::app(
407 Type::app(Type::builtin(BuiltinTypeId::Result), err_t.clone()),
408 ok_t.clone(),
409 ),
410 )),
411 }
412 }
413
414 ("Array", [elem_t]) => {
415 let items = heap.pointer_as_array(pointer)?;
416 let mut out = Vec::with_capacity(items.len());
417 for item in &items {
418 out.push(rex_to_json(heap, item, elem_t, ts, opts)?);
419 }
420 Ok(Value::Array(out))
421 }
422
423 ("List", [elem_t]) => {
424 let items = list_to_vec(heap, pointer)?;
425 let mut out = Vec::with_capacity(items.len());
426 for item in &items {
427 out.push(rex_to_json(heap, item, elem_t, ts, opts)?);
428 }
429 Ok(Value::Array(out))
430 }
431
432 ("Dict", [elem_t]) => {
433 let entries = heap.pointer_as_dict(pointer)?;
434 let mut out = Map::new();
435 for (k, v) in &entries {
436 out.insert(k.to_string(), rex_to_json(heap, v, elem_t, ts, opts)?);
437 }
438 Ok(Value::Object(out))
439 }
440
441 _ => pointer_to_json_for_adt(heap, pointer, con_name, con_args, ts, opts),
442 }
443}
444
445fn json_to_pointer_for_adt(
446 heap: &Heap,
447 json: &Value,
448 adt_name: &Symbol,
449 type_args: &[Type],
450 ts: &TypeSystem,
451 opts: &JsonOptions,
452) -> Result<Pointer, EngineError> {
453 let adt = ts
454 .adts
455 .get(adt_name)
456 .ok_or_else(|| error(format!("unknown ADT `{}`", adt_name)))?;
457 let subst = adt_subst(adt, type_args)?;
458
459 if adt.variants.len() == 1 {
460 let v = &adt.variants[0];
461 let arg_types = instantiate_types(&v.args, &subst);
462 return decode_direct_variant(heap, json, &v.name, &arg_types, ts, opts);
463 }
464
465 let enum_name = adt.name.to_string();
466 let enum_like = adt.variants.iter().all(|v| v.args.is_empty());
467 if enum_like {
468 if opts.int_enums.contains_key(&enum_name) {
469 if let Value::Number(n) = json
470 && let Some(i) = n.as_i64()
471 {
472 for (idx, v) in adt.variants.iter().enumerate() {
473 if variant_discriminant(&enum_name, &v.name, idx, opts) == Some(i) {
474 return heap.alloc_adt(v.name.clone(), vec![]);
475 }
476 }
477 }
478 return Err(error(format!(
479 "expected integer enum JSON for `{}`, got {}",
480 enum_name, json
481 )));
482 }
483 if let Value::String(tag) = json {
484 if let Some(v) = adt.variants.iter().find(|v| v.name.as_ref() == tag) {
485 return heap.alloc_adt(v.name.clone(), vec![]);
486 }
487 return Err(error(format!(
488 "unknown enum tag `{}` for `{}`",
489 tag, enum_name
490 )));
491 }
492 return Err(error(format!(
493 "expected enum string JSON for `{}`, got {}",
494 enum_name, json
495 )));
496 }
497
498 if let Value::String(tag) = json
499 && let Some(v) = adt
500 .variants
501 .iter()
502 .find(|v| v.args.is_empty() && v.name.as_ref() == tag)
503 {
504 return heap.alloc_adt(v.name.clone(), vec![]);
505 }
506
507 if let Value::Object(obj) = json
508 && obj.len() == 1
509 {
510 let Some((tag, payload)) = obj.iter().next() else {
511 return Err(error(format!(
512 "expected ADT JSON representation for `{}`; got {}",
513 adt_name, json
514 )));
515 };
516 if let Some(v) = adt.variants.iter().find(|v| v.name.as_ref() == tag) {
517 let arg_types = instantiate_types(&v.args, &subst);
518 return decode_wrapped_variant(heap, payload, &v.name, &arg_types, ts, opts);
519 }
520 }
521
522 Err(error(format!(
523 "expected ADT JSON representation for `{}`; got {}",
524 adt_name, json
525 )))
526}
527
528fn pointer_to_json_for_adt(
529 heap: &Heap,
530 pointer: &Pointer,
531 adt_name: &Symbol,
532 type_args: &[Type],
533 ts: &TypeSystem,
534 opts: &JsonOptions,
535) -> Result<Value, EngineError> {
536 let adt = ts
537 .adts
538 .get(adt_name)
539 .ok_or_else(|| error(format!("unknown ADT `{}`", adt_name)))?;
540 let subst = adt_subst(adt, type_args)?;
541
542 let (tag, args) = heap.pointer_as_adt(pointer)?;
543 let v = adt.variants.iter().find(|v| v.name == tag).ok_or_else(|| {
544 error(format!(
545 "constructor `{}` is not in ADT `{}`",
546 tag, adt_name
547 ))
548 })?;
549 let arg_types = instantiate_types(&v.args, &subst);
550 if args.len() != arg_types.len() {
551 return Err(error(format!(
552 "constructor `{}` expected {} args, got {}",
553 tag,
554 arg_types.len(),
555 args.len()
556 )));
557 }
558
559 if adt.variants.len() == 1 {
560 return encode_direct_variant(heap, &tag, &args, &arg_types, ts, opts);
561 }
562
563 let enum_name = adt.name.to_string();
564 let enum_like = adt.variants.iter().all(|v| v.args.is_empty());
565 if enum_like && args.is_empty() {
566 if opts.int_enums.contains_key(&enum_name) {
567 let idx = adt
568 .variants
569 .iter()
570 .position(|v| v.name == tag)
571 .ok_or_else(|| error(format!("missing enum variant `{}`", tag)))?;
572 let d = variant_discriminant(&enum_name, &tag, idx, opts).ok_or_else(|| {
573 error(format!(
574 "missing integer discriminant for enum `{}` variant `{}`",
575 enum_name, tag
576 ))
577 })?;
578 return Ok(Value::Number(d.into()));
579 }
580 return Ok(Value::String(tag.to_string()));
581 }
582
583 if args.is_empty() {
584 return Ok(Value::String(tag.to_string()));
585 }
586
587 let payload = encode_wrapped_variant(heap, &args, &arg_types, ts, opts)?;
588 let mut out = Map::new();
589 out.insert(tag.to_string(), payload);
590 Ok(Value::Object(out))
591}
592
593fn decode_direct_variant(
594 heap: &Heap,
595 json: &Value,
596 ctor: &Symbol,
597 arg_types: &[Type],
598 ts: &TypeSystem,
599 opts: &JsonOptions,
600) -> Result<Pointer, EngineError> {
601 match arg_types {
602 [] => match json {
603 Value::Null => heap.alloc_adt(ctor.clone(), vec![]),
604 Value::String(tag) if tag == ctor.as_ref() => heap.alloc_adt(ctor.clone(), vec![]),
605 _ => Err(error(format!(
606 "expected null or `{}` for unit constructor, got {}",
607 ctor, json
608 ))),
609 },
610 [t0] => {
611 let p = json_to_rex(heap, json, t0, ts, opts)?;
612 heap.alloc_adt(ctor.clone(), vec![p])
613 }
614 _ => match json {
615 Value::Array(items) if items.len() == arg_types.len() => {
616 let mut args = Vec::with_capacity(items.len());
617 for (item, t) in items.iter().zip(arg_types.iter()) {
618 args.push(json_to_rex(heap, item, t, ts, opts)?);
619 }
620 heap.alloc_adt(ctor.clone(), args)
621 }
622 _ => Err(error(format!(
623 "expected array payload for constructor `{}`, got {}",
624 ctor, json
625 ))),
626 },
627 }
628}
629
630fn decode_wrapped_variant(
631 heap: &Heap,
632 payload: &Value,
633 ctor: &Symbol,
634 arg_types: &[Type],
635 ts: &TypeSystem,
636 opts: &JsonOptions,
637) -> Result<Pointer, EngineError> {
638 match arg_types {
639 [] => heap.alloc_adt(ctor.clone(), vec![]),
640 [t0] => {
641 let p = json_to_rex(heap, payload, t0, ts, opts)?;
642 heap.alloc_adt(ctor.clone(), vec![p])
643 }
644 _ => match payload {
645 Value::Array(items) if items.len() == arg_types.len() => {
646 let mut args = Vec::with_capacity(items.len());
647 for (item, t) in items.iter().zip(arg_types.iter()) {
648 args.push(json_to_rex(heap, item, t, ts, opts)?);
649 }
650 heap.alloc_adt(ctor.clone(), args)
651 }
652 _ => Err(error(format!(
653 "expected array payload for constructor `{}`, got {}",
654 ctor, payload
655 ))),
656 },
657 }
658}
659
660fn encode_direct_variant(
661 heap: &Heap,
662 ctor: &Symbol,
663 args: &[Pointer],
664 arg_types: &[Type],
665 ts: &TypeSystem,
666 opts: &JsonOptions,
667) -> Result<Value, EngineError> {
668 match arg_types {
669 [] => Ok(Value::String(ctor.to_string())),
670 [t0] => rex_to_json(heap, &args[0], t0, ts, opts),
671 _ => {
672 let mut out = Vec::with_capacity(args.len());
673 for (arg, t) in args.iter().zip(arg_types.iter()) {
674 out.push(rex_to_json(heap, arg, t, ts, opts)?);
675 }
676 Ok(Value::Array(out))
677 }
678 }
679}
680
681fn encode_wrapped_variant(
682 heap: &Heap,
683 args: &[Pointer],
684 arg_types: &[Type],
685 ts: &TypeSystem,
686 opts: &JsonOptions,
687) -> Result<Value, EngineError> {
688 match arg_types {
689 [] => Ok(Value::Null),
690 [t0] => rex_to_json(heap, &args[0], t0, ts, opts),
691 _ => {
692 let mut out = Vec::with_capacity(args.len());
693 for (arg, t) in args.iter().zip(arg_types.iter()) {
694 out.push(rex_to_json(heap, arg, t, ts, opts)?);
695 }
696 Ok(Value::Array(out))
697 }
698 }
699}
700
701fn decompose_type_app(typ: &Type) -> (Type, Vec<Type>) {
702 let mut args = Vec::new();
703 let mut cur = typ.clone();
704 while let TypeKind::App(f, a) = cur.as_ref() {
705 args.push(a.clone());
706 cur = f.clone();
707 }
708 args.reverse();
709 (cur, args)
710}
711
712fn adt_subst(adt: &AdtDecl, type_args: &[Type]) -> Result<BTreeMap<usize, Type>, EngineError> {
713 if adt.params.len() != type_args.len() {
714 return Err(error(format!(
715 "ADT `{}` expects {} type args, got {}",
716 adt.name,
717 adt.params.len(),
718 type_args.len()
719 )));
720 }
721 let mut subst = BTreeMap::new();
722 for (param, arg) in adt.params.iter().zip(type_args.iter()) {
723 subst.insert(param.var.id, arg.clone());
724 }
725 Ok(subst)
726}
727
728fn instantiate_types(ts: &[Type], subst: &BTreeMap<usize, Type>) -> Vec<Type> {
729 ts.iter().map(|t| instantiate_type(t, subst)).collect()
730}
731
732fn instantiate_type(t: &Type, subst: &BTreeMap<usize, Type>) -> Type {
733 match t.as_ref() {
734 TypeKind::Var(tv) => subst.get(&tv.id).cloned().unwrap_or_else(|| t.clone()),
735 TypeKind::Con(_) => t.clone(),
736 TypeKind::App(f, a) => Type::app(instantiate_type(f, subst), instantiate_type(a, subst)),
737 TypeKind::Fun(a, b) => Type::fun(instantiate_type(a, subst), instantiate_type(b, subst)),
738 TypeKind::Tuple(xs) => Type::tuple(xs.iter().map(|x| instantiate_type(x, subst)).collect()),
739 TypeKind::Record(fields) => Type::record(
740 fields
741 .iter()
742 .map(|(k, v)| (k.clone(), instantiate_type(v, subst)))
743 .collect(),
744 ),
745 }
746}
747
748fn variant_discriminant(
749 enum_type_name: &str,
750 variant_name: &Symbol,
751 idx: usize,
752 opts: &JsonOptions,
753) -> Option<i64> {
754 let patches = opts.int_enums.get(enum_type_name)?;
755 for p in patches {
756 if p.enum_name == variant_name.as_ref() {
757 return Some(p.discriminant);
758 }
759 }
760 Some(idx as i64)
761}
762
763fn list_to_vec(heap: &Heap, pointer: &Pointer) -> Result<Vec<Pointer>, EngineError> {
764 let mut out = Vec::new();
765 let mut cur = *pointer;
766 loop {
767 let (tag, args) = heap.pointer_as_adt(&cur)?;
768 if tag.as_ref() == "Empty" && args.is_empty() {
769 return Ok(out);
770 }
771 if tag.as_ref() == "Cons" && args.len() == 2 {
772 out.push(args[0]);
773 cur = args[1];
774 continue;
775 }
776 return Err(error(format!(
777 "expected list ADT chain (Cons/Empty), found constructor `{}`",
778 tag
779 )));
780 }
781}
782
783fn json_u64(json: &Value) -> Result<u64, EngineError> {
784 match json {
785 Value::Number(n) => n
786 .as_u64()
787 .ok_or_else(|| error(format!("expected unsigned integer JSON, got {}", json))),
788 _ => Err(error(format!(
789 "expected unsigned integer JSON, got {}",
790 json
791 ))),
792 }
793}
794
795fn json_i64(json: &Value) -> Result<i64, EngineError> {
796 match json {
797 Value::Number(n) => n
798 .as_i64()
799 .ok_or_else(|| error(format!("expected signed integer JSON, got {}", json))),
800 _ => Err(error(format!("expected signed integer JSON, got {}", json))),
801 }
802}
803
804fn json_f64(json: &Value) -> Result<f64, EngineError> {
805 match json {
806 Value::Number(n) => n
807 .as_f64()
808 .ok_or_else(|| error(format!("expected floating-point JSON, got {}", json))),
809 _ => Err(error(format!("expected floating-point JSON, got {}", json))),
810 }
811}
812
813fn error(msg: String) -> EngineError {
814 EngineError::Custom(msg)
815}
816
817fn type_mismatch_json(json: &Value, want: &Type) -> EngineError {
818 error(format!(
819 "JSON value {} does not match Rex type {}",
820 json, want
821 ))
822}
823
824fn type_mismatch_pointer(heap: &Heap, pointer: &Pointer, want: &Type) -> EngineError {
825 match heap.type_name(pointer) {
826 Ok(got) => error(format!(
827 "Rex value of runtime kind `{}` does not match Rex type {}",
828 got, want
829 )),
830 Err(e) => e,
831 }
832}