1fn metadata_value(form: &Form) -> Result<MetadataValue, String> {
2 match form {
3 Form::Nil => Ok(MetadataValue::Nil),
4 Form::Bool(value) => Ok(MetadataValue::Boolean(*value)),
5 Form::Number(value) => Ok(MetadataValue::Number(*value)),
6 Form::Float(value) => Ok(MetadataValue::Float(crate::numeric::finite_float(*value)?)),
7 Form::BigInteger(value) => Ok(MetadataValue::BigInteger(value.clone())),
8 Form::Character(value) => Ok(MetadataValue::Character(*value)),
9 Form::Regex(value) => Ok(MetadataValue::Regex(value.clone())),
10 Form::Tagged(tag, value) => Ok(MetadataValue::Tagged(
11 tag.clone(),
12 Box::new(metadata_value(value)?),
13 )),
14 Form::Metadata(_, value) => metadata_value(value),
15 Form::Symbol(value) => Ok(MetadataValue::Symbol(Symbol::from(value.clone()))),
16 Form::Keyword(value) => Ok(MetadataValue::Keyword(Keyword::from(value.clone()))),
17 Form::String(value) => Ok(MetadataValue::String(value.clone())),
18 Form::Vector(values) => Ok(MetadataValue::Vector(
19 values
20 .iter()
21 .map(metadata_value)
22 .collect::<Result<_, _>>()?,
23 )),
24 Form::List(values) => Ok(MetadataValue::List(
25 values
26 .iter()
27 .map(metadata_value)
28 .collect::<Result<_, _>>()?,
29 )),
30 Form::Set(values) => Ok(MetadataValue::Set(
31 values
32 .iter()
33 .map(metadata_value)
34 .collect::<Result<_, _>>()?,
35 )),
36 Form::Map(values) => Ok(MetadataValue::Map(
37 values
38 .iter()
39 .map(|(key, value)| Ok((metadata_value(key)?, metadata_value(value)?)))
40 .collect::<Result<_, String>>()?,
41 )),
42 }
43}
44
45pub(crate) fn metadata_from_form(form: &Form) -> Result<Rc<Metadata>, String> {
46 let MetadataValue::Map(entries) = metadata_value(form)? else {
47 return Err("reader metadata must be a map".into());
48 };
49 Ok(Metadata::new(entries))
50}
51
52fn merge_metadata(
53 existing: Option<Rc<Metadata>>,
54 overlay: Option<Rc<Metadata>>,
55) -> Option<Rc<Metadata>> {
56 match (existing, overlay) {
57 (None, None) => None,
58 (Some(metadata), None) | (None, Some(metadata)) => Some(metadata),
59 (Some(existing), Some(overlay)) => {
60 let mut entries = existing.entries().to_vec();
61 for (key, value) in overlay.entries() {
62 entries.retain(|(candidate, _)| candidate != key);
63 entries.push((key.clone(), value.clone()));
64 }
65 Some(Metadata::new(entries))
66 }
67 }
68}
69
70fn assoc_metadata(
71 metadata: Option<Rc<Metadata>>,
72 key: &str,
73 value: MetadataValue,
74) -> Option<Rc<Metadata>> {
75 merge_metadata(
76 metadata,
77 Some(Metadata::new(vec![(
78 MetadataValue::Keyword(Keyword::from(key)),
79 value,
80 )])),
81 )
82}
83
84pub(crate) fn definition_metadata(
85 mut metadata: Option<Rc<Metadata>>,
86 forms: &[Form],
87 private: bool,
88 macro_form: bool,
89) -> Result<(Option<Rc<Metadata>>, &[Form]), String> {
90 let mut rest = forms;
91 if let Some(Form::String(doc)) = rest.first().map(form_without_metadata) {
92 metadata = assoc_metadata(metadata, "doc", MetadataValue::String(doc.clone()));
93 rest = &rest[1..];
94 }
95 if let Some(Form::Map(_)) = rest.first().map(form_without_metadata) {
96 metadata = merge_metadata(
97 metadata,
98 Some(metadata_from_form(form_without_metadata(&rest[0]))?),
99 );
100 rest = &rest[1..];
101 }
102 if rest.is_empty() {
103 return Ok((metadata, rest));
104 }
105 let arglists = if matches!(
106 rest.first().map(form_without_metadata),
107 Some(Form::Vector(_))
108 ) {
109 vec![metadata_value(form_without_metadata(&rest[0]))?]
110 } else {
111 rest.iter()
112 .map(|clause| match form_without_metadata(clause) {
113 Form::List(parts) if !parts.is_empty() => {
114 metadata_value(form_without_metadata(&parts[0]))
115 }
116 _ => Err(format!(
117 "function arity must be a list beginning with parameters: {clause:?}"
118 )),
119 })
120 .collect::<Result<Vec<_>, String>>()?
121 };
122 metadata = assoc_metadata(metadata, "arglists", MetadataValue::Vector(arglists));
123 if metadata.as_ref().is_some_and(|value| value.flag("inline")) {
124 if let Some(target) = inline_forward_target(rest) {
129 metadata = assoc_metadata(
130 metadata,
131 "inline-target",
132 MetadataValue::Symbol(Symbol::from(target)),
133 );
134 }
135 }
136 if private {
137 metadata = assoc_metadata(metadata, "private", MetadataValue::Boolean(true));
138 }
139 if macro_form {
140 metadata = assoc_metadata(metadata, "macro", MetadataValue::Boolean(true));
141 }
142 Ok((metadata, rest))
143}
144
145fn inline_forward_target(forms: &[Form]) -> Option<String> {
146 fn clause_target(params: &Form, body: &[Form]) -> Option<String> {
147 if body.len() != 1 {
148 return None;
149 }
150 let Form::Vector(params) = form_without_metadata(params) else {
151 return None;
152 };
153 let Form::List(call) = form_without_metadata(&body[0]) else {
154 return None;
155 };
156 let parameter_names = params
157 .iter()
158 .map(form_without_metadata)
159 .map(|form| match form {
160 Form::Symbol(name) => Some(name.as_str()),
161 _ => None,
162 })
163 .collect::<Option<Vec<_>>>()?;
164 if let [ampersand, rest] = parameter_names.as_slice() {
165 if *ampersand == "&" {
166 return match call.as_slice() {
167 [Form::Symbol(apply), Form::Symbol(target), Form::Symbol(argument)]
168 if apply == "apply" && argument == rest =>
169 {
170 Some(target.clone())
171 }
172 _ => None,
173 };
174 }
175 }
176 let Form::Symbol(target) = call.first()? else {
177 return None;
178 };
179 let arguments = call[1..]
180 .iter()
181 .map(form_without_metadata)
182 .map(|form| match form {
183 Form::Symbol(name) => Some(name.as_str()),
184 _ => None,
185 })
186 .collect::<Option<Vec<_>>>()?;
187 (arguments == parameter_names).then(|| target.clone())
188 }
189
190 if matches!(
191 forms.first().map(form_without_metadata),
192 Some(Form::Vector(_))
193 ) {
194 return clause_target(forms.first()?, &forms[1..]);
195 }
196 let mut target = None;
197 for clause in forms {
198 let Form::List(parts) = form_without_metadata(clause) else {
199 return None;
200 };
201 let candidate = clause_target(parts.first()?, &parts[1..])?;
202 if target.as_ref().is_some_and(|value| value != &candidate) {
203 return None;
204 }
205 target = Some(candidate);
206 }
207 target
208}
209
210pub(crate) fn schema_var_reference(metadata: Option<&Metadata>) -> Option<&Symbol> {
211 let MetadataValue::List(reference) = metadata?.get_keyword("schema")? else {
212 return None;
213 };
214 match reference.as_slice() {
215 [MetadataValue::Symbol(operator), MetadataValue::Symbol(target)]
216 if operator.get_namespace().is_none() && operator.get_name() == "var" =>
217 {
218 Some(target)
219 }
220 _ => None,
221 }
222}
223
224fn attach_optional_metadata(value: Value, metadata: Option<Rc<Metadata>>) -> Result<Value, String> {
225 Ok(match value {
226 Value::Symbol(value) => Value::Symbol(value.with_meta(metadata.clone())),
227 Value::Pointer(value) => Value::Pointer(value.with_meta(metadata.clone())),
228 Value::Tuple(value) => Value::Tuple(Box::new(value.with_meta(metadata.clone()))),
229 Value::Vector(value) => Value::Vector(value.with_meta(metadata.clone())),
230 Value::MapEntry(value) => Value::MapEntry(Box::new(value.with_meta(metadata.clone()))),
231 Value::List(value) => Value::List(value.with_meta(metadata.clone())),
232 Value::Cons(value) => Value::Cons(Box::new(value.with_meta(metadata.clone()))),
233 Value::Queue(value) => Value::Queue(Box::new(value.with_meta(metadata.clone()))),
234 Value::Deque(value) => Value::Deque(Box::new(value.with_meta(metadata.clone()))),
235 Value::Map(value) => Value::Map(value.with_meta(metadata.clone())),
236 Value::OrderedMap(value) => Value::OrderedMap(Box::new(value.with_meta(metadata.clone()))),
237 Value::SortedMap(value) => Value::SortedMap(Box::new(value.with_meta(metadata.clone()))),
238 Value::Trie(value) => Value::Trie(Box::new(value.with_meta(metadata.clone()))),
239 Value::PriorityMap(value) => {
240 Value::PriorityMap(Box::new(value.with_meta(metadata.clone())))
241 }
242 Value::Set(value) => Value::Set(value.with_meta(metadata.clone())),
243 Value::OrderedSet(value) => Value::OrderedSet(Box::new(value.with_meta(metadata.clone()))),
244 Value::SortedSet(value) => Value::SortedSet(Box::new(value.with_meta(metadata.clone()))),
245 Value::Seq(value) => Value::Seq(Box::new(value.with_meta(metadata.clone()))),
246 Value::Var(value) => {
247 value.set_hara_metadata(metadata);
248 Value::Var(value)
249 }
250 Value::Function(value) => Value::Function(Rc::new(Function {
251 metadata,
252 ..value.as_ref().clone()
253 })),
254 Value::Struct(value) => Value::Struct(Rc::new(StructValue {
255 ty: value.ty.clone(),
256 values: value.values.clone(),
257 metadata,
258 })),
259 Value::Mutable(value) => Value::Mutable(Rc::new(MutableValue {
260 ty: value.ty.clone(),
261 values: value.values.clone(),
262 metadata,
263 })),
264 Value::NativeType(value) => Value::NativeType(Rc::new(NativeType {
265 name: value.name.clone(),
266 methods: value.methods.clone(),
267 availability: value.availability,
268 capability: value.capability.clone(),
269 metadata,
270 })),
271 Value::Keyword(value) => Value::Keyword(value),
272 _ => return Err("metadata can only be applied to object values".into()),
273 })
274}
275
276fn attach_metadata(value: Value, metadata: Rc<Metadata>) -> Result<Value, String> {
277 attach_optional_metadata(value, Some(metadata))
278}
279
280fn collection_constructor_values(name: &str, values: Vec<Value>) -> Result<Value, String> {
281 match name {
282 "hash-map" | "ordered-map" | "priority-map" | "sorted-map" | "trie" => {
283 if values.len() % 2 != 0 {
284 return Err(format!(
285 "{name} expects an even number of key/value arguments"
286 ));
287 }
288 let entries = values
289 .chunks_exact(2)
290 .map(|pair| (pair[0].clone(), pair[1].clone()));
291 Ok(match name {
292 "hash-map" => Value::Map(PMap::from_iter(entries)),
293 "ordered-map" => Value::OrderedMap(Box::new(POrderedMap::from_iter(entries))),
294 "priority-map" => Value::PriorityMap(Box::new(PPriorityMap::from_iter(entries))),
295 "sorted-map" => Value::SortedMap(Box::new(PSortedMap::from_iter(entries))),
296 "trie" => {
297 let mut trie = PTrie::new();
298 for (key, value) in entries {
299 let Value::String(key) = key else {
300 return Err("trie expects string keys".into());
301 };
302 trie = trie.assoc_value(key, value);
303 }
304 Value::Trie(Box::new(trie))
305 }
306 _ => unreachable!("guarded map constructor"),
307 })
308 }
309 "hash-set" => Ok(Value::Set(values.into_iter().collect())),
310 "ordered-set" => Ok(Value::OrderedSet(Box::new(values.into_iter().collect()))),
311 "sorted-set" => Ok(Value::SortedSet(Box::new(values.into_iter().collect()))),
312 "deque" => Ok(Value::Deque(Box::new(values.into_iter().collect()))),
313 "queue" => Ok(Value::Queue(Box::new(values.into_iter().collect()))),
314 _ => unreachable!("guarded collection constructor"),
315 }
316}
317
318fn vector_literal(values: Vec<Value>) -> Result<Value, String> {
319 if values.len() <= 8 {
320 Ok(Value::Tuple(Box::new(PTuple::from_values(values)?)))
321 } else {
322 Ok(Value::Vector(values.into()))
323 }
324}
325
326pub(crate) fn vm_build_vector(values: Vec<Value>) -> Result<Value, String> {
327 vector_literal(values)
328}
329
330pub(crate) fn vm_build_map(values: Vec<Value>) -> Result<Value, String> {
331 if values.len() % 2 != 0 {
332 return Err("map construction requires key/value pairs".into());
333 }
334 Ok(Value::Map(PMap::from_iter(
335 values
336 .chunks_exact(2)
337 .map(|pair| (pair[0].clone(), pair[1].clone())),
338 )))
339}
340
341pub(crate) fn vm_build_set(values: Vec<Value>) -> Result<Value, String> {
342 Ok(Value::OrderedSet(Box::new(POrderedSet::from_iter(values))))
343}
344
345pub(crate) fn vm_build_list(values: Vec<Value>) -> Value {
346 Value::List(values.into())
347}
348
349pub(crate) fn vm_concat_list(values: Vec<Value>) -> Result<Value, String> {
350 let mut output = Vec::new();
351 for value in values {
352 output.extend(iterator_values(value)?);
353 }
354 Ok(Value::List(output.into()))
355}
356
357pub(crate) fn vm_to_vector(value: Value) -> Result<Value, String> {
358 vector_literal(iterator_values(value)?)
359}
360
361fn literal_value(form: &Form) -> Result<Value, String> {
362 match form {
363 Form::Nil => Ok(Value::Nil),
364 Form::Bool(value) => Ok(Value::Bool(*value)),
365 Form::Character(value) => Ok(Value::Character(*value)),
366 Form::Float(value) => Ok(Value::Float(crate::numeric::finite_float(*value)?)),
367 Form::BigInteger(value) => Ok(crate::numeric::compact_integer(value.clone())),
368 Form::Regex(value) => Ok(Value::Regex(value.clone())),
369 Form::Tagged(tag, value) if tag == "ptr" => pointer_from_descriptor(literal_value(value)?),
370 Form::Tagged(tag, value) if tag == "uuid" => {
371 crate::core::uuid_tag_value(literal_value(value)?)
372 }
373 Form::Tagged(tag, value) if tag == "ex" => exception_literal_value(value),
374 Form::Tagged(tag, value) if tag == "result" => result_literal_value(value),
375 Form::Tagged(tag, value) if tag == "arr" => {
376 let Form::Vector(values) = value.as_ref() else {
377 return Err("#arr expects a vector literal".into());
378 };
379 Ok(Value::Array(Rc::new(RefCell::new(
380 values
381 .iter()
382 .map(literal_value)
383 .collect::<Result<Vec<_>, _>>()?,
384 ))))
385 }
386 Form::Tagged(tag, value) if tag == "obj" => {
387 let Form::Map(entries) = value.as_ref() else {
388 return Err("#obj expects a map literal".into());
389 };
390 Ok(Value::Object(Rc::new(RefCell::new(
391 entries
392 .iter()
393 .map(|(key, value)| {
394 Ok((
395 marker_key(&literal_value(key)?, "#obj")?,
396 literal_value(value)?,
397 ))
398 })
399 .collect::<Result<Vec<_>, String>>()?,
400 ))))
401 }
402 Form::Tagged(tag, value) => Ok(Value::Tagged(Box::new(PTaggedLiteral::new(
403 Symbol::parse(tag),
404 literal_value(value)?,
405 )))),
406 Form::Metadata(metadata, value) => {
407 attach_metadata(literal_value(value)?, metadata_from_form(metadata)?)
408 }
409 Form::Number(v) => Ok(Value::Number(*v)),
410 Form::String(v) => Ok(Value::String(v.clone())),
411 Form::Keyword(v) => Ok(Value::Keyword(v.clone().into())),
412 Form::Symbol(v) => Ok(Value::Symbol(v.clone().into())),
413 Form::Vector(values) => {
414 vector_literal(values.iter().map(literal_value).collect::<Result<_, _>>()?)
415 }
416 Form::Set(values) => Ok(Value::OrderedSet(Box::new(
417 unique_values(values.iter().map(literal_value).collect::<Result<_, _>>()?)
418 .into_iter()
419 .collect(),
420 ))),
421 Form::List(values) => Ok(Value::List(
422 values.iter().map(literal_value).collect::<Result<_, _>>()?,
423 )),
424 Form::Map(values) => Ok(Value::Map(
425 values
426 .iter()
427 .map(|(k, v)| Ok((literal_value(k)?, literal_value(v)?)))
428 .collect::<Result<_, String>>()?,
429 )),
430 }
431}
432
433fn exception_literal_value(form: &Form) -> Result<Value, String> {
434 let Form::Vector(values) = form else {
435 return Err("#ex expects a [message data] vector".into());
436 };
437 let [message, data] = values.as_slice() else {
438 return Err("#ex expects exactly a message and data value".into());
439 };
440 let Value::String(message) = literal_value(message)? else {
441 return Err("#ex message must be a string".into());
442 };
443 let data = literal_value(data)?;
444 let cause = map_entries(&data)
445 .and_then(|entries| {
446 entries.into_iter().find_map(|(key, value)| {
447 matches!(key, Value::Keyword(name) if name.as_str() == "ex/cause")
448 .then_some(value)
449 })
450 });
451 let cause = match cause {
452 Some(Value::ExceptionInfo(value)) => Some(Box::new(Value::ExceptionInfo(value))),
453 Some(_) => return Err("#ex :ex/cause must be an Exception".into()),
454 None => None,
455 };
456 Ok(Value::ExceptionInfo(Rc::new(ExceptionInfo {
457 message,
458 data: Box::new(data),
459 cause,
460 provenance: Rc::new(RefCell::new(ExceptionProvenance::default())),
461 })))
462}
463
464fn result_literal_value(form: &Form) -> Result<Value, String> {
465 let Form::Vector(values) = form else {
466 return Err("#result expects a [status data error context] vector".into());
467 };
468 let [status, data, error, context] = values.as_slice() else {
469 return Err("#result expects exactly status, data, error, and context".into());
470 };
471 let Value::Keyword(status) = literal_value(status)? else {
472 return Err("#result status must be :success or :error".into());
473 };
474 let data = literal_value(data)?;
475 let error = literal_value(error)?;
476 let context = literal_value(context)?;
477 match status.as_str() {
478 "success" => {
479 if !matches!(error, Value::Nil) {
480 return Err("#result success must have nil error".into());
481 }
482 Ok(Value::Result(Rc::new(ResultValue::success(data, context)?)))
483 }
484 "error" => {
485 if !matches!(data, Value::Nil) {
486 return Err("#result error must have nil data".into());
487 }
488 if !matches!(error, Value::ExceptionInfo(_)) {
489 return Err("#result error must be an Exception".into());
490 }
491 Ok(Value::Result(Rc::new(ResultValue::error(error, context)?)))
492 }
493 _ => Err("#result status must be :success or :error".into()),
494 }
495}
496
497#[cfg(test)]
498mod literal_tests {
499 use super::*;
500
501 #[test]
502 fn short_exception_and_result_literals_round_trip_without_ex_info() {
503 let exception = literal_value(&Form::Tagged(
504 "ex".into(),
505 Box::new(Form::Vector(vec![
506 Form::String("boom".into()),
507 Form::Map(vec![(
508 Form::Keyword("kind".into()),
509 Form::Keyword("fixture".into()),
510 )]),
511 ])),
512 ))
513 .expect("#ex literal");
514 assert_eq!(exception.display(), "#ex[\"boom\" {:kind :fixture}]");
515 let forms = crate::kernel::parse_forms(&exception.display()).expect("printed #ex parses");
516 let Value::ExceptionInfo(round_trip) = literal_value(&forms[0]).expect("printed #ex reads") else {
517 panic!("#ex must read as an Exception");
518 };
519 assert_eq!(round_trip.message, "boom");
520 assert_eq!(round_trip.data.display(), "{:kind :fixture}");
521 assert!(
522 !exception_function_values()
523 .iter()
524 .any(|(name, _)| *name == "ex-info"),
525 "ex-info must not enter the Foundation prelude"
526 );
527
528 let result = Value::Result(Rc::new(
529 ResultValue::success(
530 Value::Number(42),
531 Value::Map(PMap::from_iter([(
532 Value::Keyword("trace".into()),
533 Value::Number(8),
534 )])),
535 )
536 .expect("Result value"),
537 ));
538 assert_eq!(result.display(), "#result[:success 42 nil {:trace 8}]");
539 let forms = crate::kernel::parse_forms(&result.display()).expect("printed #result parses");
540 assert_eq!(literal_value(&forms[0]).expect("printed #result reads"), result);
541 }
542}
543
544fn function_parts(
545 form: &Form,
546) -> Result<(Vec<String>, Option<String>, Vec<Form>, Option<Form>), String> {
547 let list = match form_without_metadata(form) {
548 Form::Vector(values) => values,
549 _ => return Err("function parameters must be a vector".into()),
550 };
551 let mut params = Vec::new();
552 let mut variadic = None;
553 let mut patterns = Vec::new();
554 let mut variadic_pattern = None;
555 let mut index = 0;
556 while index < list.len() {
557 match form_without_metadata(&list[index]) {
558 Form::Symbol(name) if name == "&" => {
559 if variadic.is_some() || index + 1 >= list.len() || index + 2 != list.len() {
560 return Err("variadic marker must precede the final parameter".into());
561 }
562 let pattern = form_without_metadata(&list[index + 1]).clone();
563 variadic = Some(match &pattern {
564 Form::Symbol(name) => name.clone(),
565 _ => format!("__rest_{}", params.len()),
566 });
567 variadic_pattern = Some(pattern);
568 index += 2;
569 }
570 pattern @ (Form::Symbol(_) | Form::Vector(_) | Form::Map(_)) => {
571 params.push(match pattern {
572 Form::Symbol(name) => name.clone(),
573 _ => format!("__arg_{}", params.len()),
574 });
575 patterns.push(pattern.clone());
576 index += 1;
577 }
578 _ => return Err("function parameters must be binding patterns".into()),
579 }
580 }
581 Ok((params, variadic, patterns, variadic_pattern))
582}
583
584fn collect_capture_names(form: &Form, names: &mut std::collections::HashSet<String>) {
585 match form {
586 Form::Symbol(name) => {
587 names.insert(name.clone());
588 }
589 Form::List(values) | Form::Vector(values) | Form::Set(values) => {
590 for value in values {
591 collect_capture_names(value, names);
592 }
593 }
594 Form::Map(entries) => {
595 for (key, value) in entries {
596 collect_capture_names(key, names);
597 collect_capture_names(value, names);
598 }
599 }
600 Form::Metadata(metadata, value) => {
601 collect_capture_names(metadata, names);
602 collect_capture_names(value, names);
603 }
604 Form::Tagged(_, value) => collect_capture_names(value, names),
605 Form::Nil
606 | Form::Bool(_)
607 | Form::Number(_)
608 | Form::Float(_)
609 | Form::BigInteger(_)
610 | Form::Character(_)
611 | Form::Regex(_)
612 | Form::String(_)
613 | Form::Keyword(_) => {}
614 }
615}
616
617fn capture_environment(forms: &[Form], env: &HashMap<String, Value>) -> HashMap<String, Value> {
618 let mut names = std::collections::HashSet::new();
619 for form in forms {
620 collect_capture_names(form, &mut names);
621 }
622 names
623 .into_iter()
624 .filter_map(|name| env.get(&name).cloned().map(|value| (name, value)))
625 .collect()
626}
627
628fn destructuring_default<'a>(defaults: Option<&'a Form>, name: &str) -> Option<&'a Form> {
629 let Form::Map(entries) = defaults? else {
630 return None;
631 };
632 entries.iter().find_map(|(key, value)| {
633 matches!(key, Form::Symbol(candidate) if candidate == name).then_some(value)
634 })
635}
636
637pub(crate) fn bind_pattern(
638 pattern: &Form,
639 value: Value,
640 env: &mut HashMap<String, Value>,
641 bound: &mut Vec<String>,
642 defaults: Option<&Form>,
643) -> Result<(), String> {
644 match pattern {
645 Form::Symbol(name) => {
646 if name == "_" {
647 return Ok(());
648 }
649 if name.contains('/') || bound.iter().any(|candidate| candidate == name) {
650 return Err(format!("invalid or duplicate binding: {name}"));
651 }
652 let value = if matches!(value, Value::Nil) {
653 match destructuring_default(defaults, name) {
654 Some(default) => eval(default, env)?,
655 None => value,
656 }
657 } else {
658 value
659 };
660 env.insert(name.clone(), value);
661 bound.push(name.clone());
662 Ok(())
663 }
664 Form::Vector(patterns) => {
665 let original = value.clone();
666 let values = if matches!(value, Value::Nil) {
667 Vec::new()
668 } else {
669 iterator_values(value)
670 .map_err(|_| "cannot destructure non-sequential value".to_owned())?
671 };
672 let mut index = 0;
673 let mut position = 0;
674 while index < patterns.len() {
675 match &patterns[index] {
676 Form::Symbol(marker) if marker == "&" => {
677 if index + 1 >= patterns.len() {
678 return Err("& in a destructuring vector requires a binding".into());
679 }
680 bind_pattern(
681 &patterns[index + 1],
682 Value::Vector(values.iter().skip(position).cloned().collect()),
683 env,
684 bound,
685 defaults,
686 )?;
687 index += 2;
688 }
689 Form::Keyword(marker) if marker.as_str() == "as" => {
690 if index + 2 != patterns.len() {
691 return Err(
692 ":as in a destructuring vector must precede its final binding"
693 .into(),
694 );
695 }
696 bind_pattern(&patterns[index + 1], original, env, bound, defaults)?;
697 return Ok(());
698 }
699 nested => {
700 bind_pattern(
701 nested,
702 values.get(position).cloned().unwrap_or(Value::Nil),
703 env,
704 bound,
705 defaults,
706 )?;
707 position += 1;
708 index += 1;
709 }
710 }
711 }
712 Ok(())
713 }
714 Form::Map(entries) => {
715 if !matches!(value, Value::Nil | Value::Struct(_)) && map_entries(&value).is_none() {
716 return Err("cannot destructure non-map value".into());
717 }
718 let defaults = entries.iter().find_map(|(key, value)| {
719 matches!(key, Form::Keyword(keyword) if keyword.as_str() == "or").then_some(value)
720 });
721 for (binding, key) in entries {
722 match binding {
723 Form::Keyword(keyword) if keyword.as_str() == "or" => {}
724 Form::Keyword(keyword) if keyword.as_str() == "as" => {
725 bind_pattern(key, value.clone(), env, bound, defaults)?;
726 }
727 Form::Keyword(keyword)
728 if ["keys", "strs", "syms"].contains(&keyword.as_str()) =>
729 {
730 let Form::Vector(names) = key else {
731 return Err(format!(
732 ":{} destructuring expects a vector of symbols",
733 keyword.as_str()
734 ));
735 };
736 for name in names {
737 let Form::Symbol(name) = name else {
738 return Err(format!(
739 ":{} destructuring expects symbols",
740 keyword.as_str()
741 ));
742 };
743 let lookup = match keyword.as_str() {
744 "keys" => Value::Keyword(name.clone().into()),
745 "strs" => Value::String(name.clone()),
746 "syms" => Value::Symbol(name.clone().into()),
747 _ => unreachable!(),
748 };
749 bind_pattern(
750 &Form::Symbol(name.clone()),
751 collection_get(&value, &lookup, Value::Nil)?,
752 env,
753 bound,
754 defaults,
755 )?;
756 }
757 }
758 binding => {
759 let lookup = literal_value(key)?;
760 bind_pattern(
761 binding,
762 collection_get(&value, &lookup, Value::Nil)?,
763 env,
764 bound,
765 defaults,
766 )?;
767 }
768 }
769 }
770 Ok(())
771 }
772 _ => Err("unsupported binding pattern".into()),
773 }
774}
775
776fn select_clause(functions: &[Rc<Function>], argument_count: usize) -> Option<Rc<Function>> {
777 functions
778 .iter()
779 .find(|function| function.variadic.is_none() && function.params.len() == argument_count)
780 .or_else(|| {
781 functions
782 .iter()
783 .filter(|function| {
784 function.variadic.is_some() && argument_count >= function.params.len()
785 })
786 .max_by_key(|function| function.params.len())
787 })
788 .cloned()
789}
790
791fn multi_arity_function(
792 name: &str,
793 clauses: &[Form],
794 captured: &HashMap<String, Value>,
795 is_macro: bool,
796) -> Result<Value, String> {
797 let mut functions = Vec::with_capacity(clauses.len());
798 for clause in clauses {
799 let parts = match form_without_metadata(clause) {
800 Form::List(parts) if parts.len() >= 2 => parts,
801 _ => return Err("defn arity must contain parameters and a body".into()),
802 };
803 let (params, variadic, patterns, variadic_pattern) = function_parts(&parts[0])?;
804 functions.push(Rc::new(Function {
805 params,
806 variadic,
807 patterns,
808 variadic_pattern,
809 body: parts[1..].to_vec(),
810 captured: Rc::new(RefCell::new(capture_environment(&parts[1..], captured))),
811 name: Some(name.into()),
812 namespace: function_definition_namespace(),
813 native: None,
814 fiber_native: None,
815 clauses: Vec::new(),
816 metadata: None,
817 is_macro,
818 }));
819 }
820 if functions.is_empty() {
821 return Err("defn expects at least one arity".into());
822 }
823 Ok(arity_dispatcher(name, functions, is_macro))
824}
825
826pub(crate) fn arity_dispatcher(name: &str, functions: Vec<Rc<Function>>, is_macro: bool) -> Value {
830 let dispatch_name = name.to_owned();
831 let clauses = functions.clone();
832 #[cfg(all(feature = "direct-native", not(target_arch = "wasm32")))]
833 let fiber_functions = functions.clone();
834 #[cfg(all(feature = "direct-native", not(target_arch = "wasm32")))]
835 let fiber_dispatch_name = dispatch_name.clone();
836 Value::Function(Rc::new(Function {
837 params: Vec::new(),
838 variadic: Some("arguments".into()),
839 patterns: Vec::new(),
840 variadic_pattern: None,
841 body: Vec::new(),
842 captured: Rc::new(RefCell::new(HashMap::new())),
843 name: Some(dispatch_name.clone()),
844 namespace: function_definition_namespace(),
845 clauses,
846 native: Some(Rc::new(move |arguments| {
847 let function = select_clause(&functions, arguments.len()).ok_or_else(|| {
848 format!(
849 "{dispatch_name} has no arity accepting {} arguments",
850 arguments.len()
851 )
852 })?;
853 call_function(&function, arguments)
854 })),
855 #[cfg(all(feature = "direct-native", not(target_arch = "wasm32")))]
856 fiber_native: Some(Rc::new(move |arguments, continuation| {
857 let function = select_clause(&fiber_functions, arguments.len()).ok_or_else(|| {
858 format!(
859 "{fiber_dispatch_name} has no arity accepting {} arguments",
860 arguments.len()
861 )
862 });
863 match function {
864 Ok(function) => crate::core::call_direct_native_fiber(
865 Value::Function(function),
866 arguments,
867 continuation,
868 )
869 .unwrap_or_else(|error| Step::Done(Err(error))),
870 Err(error) => Step::Done(Err(error)),
871 }
872 })),
873 #[cfg(not(all(feature = "direct-native", not(target_arch = "wasm32"))))]
874 fiber_native: None,
875 metadata: None,
876 is_macro,
877 }))
878}
879
880fn deref_binding_value(name: &str, value: Value) -> Value {
881 match value {
882 Value::Var(var)
883 if name.starts_with("std.native.")
884 || name.starts_with("std.protocol.")
885 || var.symbol().get_name() == Symbol::parse(name).get_name() =>
886 {
887 var.deref_value()
888 }
889 value => value,
890 }
891}
892
893fn binding_value(env: &HashMap<String, Value>, name: &str) -> Option<Value> {
894 env.get(name)
895 .cloned()
896 .map(|value| deref_binding_value(name, value))
897 .or_else(|| {
898 let registry = namespace_registry().ok()?;
899 registry
900 .resolve(&crate::lang::data::Symbol::parse(name))
901 .or_else(|| {
902 crate::core::canonical_intrinsic_symbol(name).and_then(|canonical| {
903 registry.resolve(&crate::lang::data::Symbol::parse(&canonical))
904 })
905 })
906 .map(|var| var.deref_value())
907 })
908 .or_else(|| {
909 let registry = namespace_registry().ok()?;
910 let local = crate::lang::data::Symbol::parse(name);
911 if name.contains('/') || !registry.current().foundation_visible(&local) {
912 return None;
913 }
914 registry
915 .find("std.foundation")
916 .and_then(|foundation| foundation.resolve(&local))
917 .map(|var| var.deref_value())
918 })
919 .or_else(|| {
920 let (qualifier, local) = name.rsplit_once('/')?;
921 let registry = namespace_registry().ok()?;
922 (registry.current().name().as_str() == qualifier)
923 .then(|| {
924 env.get(local)
925 .cloned()
926 .map(|value| deref_binding_value(local, value))
927 })
928 .flatten()
929 })
930}
931
932fn foundation_fallback_omitted(env: &HashMap<String, Value>, name: &str) -> bool {
933 const INTRINSIC_FORMS: &[&str] = &[
936 "ns-alias-state",
937 "ns-loaded?",
938 "ns-state",
939 "resolve",
940 ];
941 if name.contains('/')
942 || env.contains_key(name)
943 || syntax_symbol(name)
944 || INTRINSIC_FORMS.contains(&name)
945 {
946 return false;
947 }
948 let Ok(registry) = namespace_registry() else {
949 return false;
950 };
951 let local = crate::lang::data::Symbol::parse(name);
952 registry.resolve(&local).is_none()
953 && registry
954 .find("std.foundation")
955 .and_then(|foundation| foundation.resolve(&local))
956 .is_some()
957}
958
959fn binding_var(env: &mut HashMap<String, Value>, name: &str) -> Option<KernelVar<Value>> {
960 match env.get(name) {
961 Some(Value::Var(var)) => Some(var.clone()),
962 Some(value) => {
963 let var = KernelVar::new(name, value.clone());
964 env.insert(name.to_string(), Value::Var(var.clone()));
965 Some(var)
966 }
967 None => {
968 if let Some(local) = name.strip_prefix("-/") {
969 if let Some(Value::Var(var)) = env.get(local) {
970 return Some(var.clone());
971 }
972 }
973 namespace_registry()
974 .ok()?
975 .resolve(&crate::lang::data::Symbol::parse(name))
976 }
977 }
978}
979
980pub(crate) fn call_value(callable: Value, arguments: Vec<Value>) -> Result<Value, String> {
981 let lookup =
982 |target: &Value, key: &Value, fallback: Value| collection_get(target, key, fallback);
983 match callable {
984 Value::Function(function) => call_function(&function, arguments),
985 Value::Namespace(namespace) => namespace
986 .resolve(&crate::lang::data::Symbol::parse("run"))
987 .map(|var| var.deref_value())
988 .ok_or_else(|| format!("namespace is not callable: {}", namespace.name().as_str()))
989 .and_then(|function| call_value(function, arguments)),
990 Value::StructType(ty) => Ok(Value::Struct(Rc::new(StructValue::from_values(
991 ty, arguments, None,
992 )?))),
993 Value::MutableType(ty) => Ok(Value::Mutable(Rc::new(MutableValue::from_values(
994 ty, arguments, None,
995 )?))),
996 value @ (Value::Struct(_) | Value::Mutable(_)) => {
997 let mut protocol_arguments = Vec::with_capacity(arguments.len() + 1);
998 protocol_arguments.push(value);
999 protocol_arguments.extend(arguments);
1000 protocol_call("std.protocol.ifn.IFn", "invoke", &protocol_arguments)
1001 }
1002 Value::Pointer(pointer) => pointer_invoke(&pointer, pointer_default(&pointer)?, &arguments),
1003 Value::Keyword(keyword) => match arguments.as_slice() {
1004 [target] => lookup(target, &Value::Keyword(keyword), Value::Nil),
1005 [target, fallback] => lookup(target, &Value::Keyword(keyword), fallback.clone()),
1006 _ => Err("keyword invocation expects one or two arguments".into()),
1007 },
1008 value @ (Value::Map(_)
1009 | Value::OrderedMap(_)
1010 | Value::SortedMap(_)
1011 | Value::Trie(_)
1012 | Value::PriorityMap(_)) => match arguments.as_slice() {
1013 [key] => Ok(map_value(&value, key).cloned().unwrap_or(Value::Nil)),
1014 [key, fallback] => Ok(map_value(&value, key)
1015 .cloned()
1016 .unwrap_or_else(|| fallback.clone())),
1017 _ => Err("map invocation expects one or two arguments".into()),
1018 },
1019 value @ (Value::Set(_) | Value::OrderedSet(_) | Value::SortedSet(_)) => {
1020 match arguments.as_slice() {
1021 [key] => Ok(set_find(&value, key).unwrap_or(Value::Nil)),
1022 [key, fallback] => Ok(set_find(&value, key).unwrap_or_else(|| fallback.clone())),
1023 _ => Err("set invocation expects one or two arguments".into()),
1024 }
1025 }
1026 _ => Err("value is not callable".into()),
1027 }
1028}
1029
1030pub fn invoke_callable(callable: Value, arguments: Vec<Value>) -> Result<Value, String> {
1036 call_value(callable, arguments)
1037}
1038
1039#[cfg(all(feature = "direct-native", not(target_arch = "wasm32")))]
1047pub(crate) fn call_direct_native_value(
1048 callable: Value,
1049 arguments: Vec<Value>,
1050) -> Result<Value, String> {
1051 match &callable {
1052 Value::Function(function) if is_direct_native_function(function) => {
1053 call_function(function, arguments)
1054 }
1055 Value::Function(function) => Err(format!(
1056 "direct-native cannot call an evaluator-backed Hara function {}; compile the callee first",
1057 function
1058 .origin_symbol()
1059 .map(|symbol| symbol.as_str().to_owned())
1060 .unwrap_or_else(|| "<anonymous>".into())
1061 )),
1062 _ => call_value(callable, arguments),
1063 }
1064}
1065
1066#[cfg(all(feature = "direct-native", not(target_arch = "wasm32")))]
1067pub(crate) fn call_direct_native_fiber(
1068 callable: Value,
1069 arguments: Vec<Value>,
1070 continuation: Cont,
1071) -> Result<Step, String> {
1072 match callable {
1073 Value::Function(function) if is_direct_native_function(&function) => {
1074 if let Some(fiber_native) = &function.fiber_native {
1075 return Ok(fiber_native(arguments, continuation));
1076 }
1077 Ok(Step::Done(call_direct_native_value(
1078 Value::Function(function),
1079 arguments,
1080 )))
1081 }
1082 Value::Function(function) => Err(format!(
1083 "direct-native cannot call an evaluator-backed Hara function {}; compile the callee first",
1084 function
1085 .origin_symbol()
1086 .map(|symbol| symbol.as_str().to_owned())
1087 .unwrap_or_else(|| "<anonymous>".into())
1088 )),
1089 Value::Namespace(namespace) => {
1090 let run = namespace
1091 .resolve(&crate::lang::data::Symbol::parse("run"))
1092 .map(|var| var.deref_value())
1093 .ok_or_else(|| {
1094 format!("namespace is not callable: {}", namespace.name().as_str())
1095 })?;
1096 call_direct_native_fiber(run, arguments, continuation)
1097 }
1098 value => Ok(Step::Done(call_direct_native_value(value, arguments))),
1099 }
1100}
1101
1102#[cfg(all(feature = "direct-native", not(target_arch = "wasm32")))]
1103pub(crate) fn is_direct_native_function(function: &Function) -> bool {
1104 function.native.is_some()
1110}
1111
1112pub(crate) fn call_function(function: &Function, arguments: Vec<Value>) -> Result<Value, String> {
1113 #[cfg(all(feature = "direct-native", not(target_arch = "wasm32")))]
1114 if direct_native_execution() && !is_direct_native_function(function) {
1115 return Err(format!(
1116 "direct-native cannot call an evaluator- or fiber-backed Hara function {}; compile the callee first",
1117 function
1118 .origin_symbol()
1119 .map(|symbol| symbol.as_str().to_owned())
1120 .unwrap_or_else(|| "<anonymous>".into())
1121 ));
1122 }
1123 #[cfg(all(feature = "direct-native", not(target_arch = "wasm32")))]
1124 if let Some(symbol) = function.origin_symbol() {
1125 crate::direct_native::record_native_target(symbol.as_str());
1126 }
1127 #[cfg(feature = "evaluation-journal")]
1128 let operation = evaluation_journal_enter(function, &arguments);
1129 if let Some(native) = &function.native {
1130 if function.variadic.is_none() && function.params.len() != arguments.len() {
1131 #[cfg(feature = "evaluation-journal")]
1132 evaluation_journal_exit(operation, function, None);
1133 if function.name.as_deref() == Some("type") {
1134 return Err("type expects one value".into());
1135 }
1136 return Err(format!(
1137 "function expects {} arguments",
1138 function.params.len()
1139 ));
1140 }
1141 let result = native(arguments);
1142 #[cfg(feature = "evaluation-journal")]
1143 evaluation_journal_exit(operation, function, result.as_ref().ok());
1144 return result;
1145 }
1146 let tracing = tracing_enabled();
1147 if tracing {
1148 TRACE_STACK.with(|stack| {
1149 stack.borrow_mut().push(trace_frame(
1150 function
1151 .name
1152 .clone()
1153 .unwrap_or_else(|| "<anonymous>".into()),
1154 function.namespace.clone(),
1155 current_exception_site(),
1156 ))
1157 });
1158 }
1159 let caller_scoped_foundation = function.namespace.as_deref() == Some("std.foundation")
1160 && (function.is_macro
1161 || matches!(
1162 function.name.as_deref(),
1163 Some(
1164 "macroexpand"
1165 | "macroexpand-1"
1166 | "ns-current"
1167 | "ns-alias-state"
1168 | "eval"
1169 | "eval-in-ns"
1170 | "env-snapshot"
1171 | "ns-vars"
1172 | "ns-list"
1173 | "ns-info"
1174 | "env-module"
1175 )
1176 ));
1177 let namespace_scope = namespace_registry().ok().and_then(|registry| {
1178 (!caller_scoped_foundation)
1179 .then_some(())
1180 .and_then(|_| function.namespace.as_ref())
1181 .map(|namespace| {
1182 let previous = registry.current().name().as_str().to_owned();
1183 registry.set_current(namespace);
1184 (registry, previous)
1185 })
1186 });
1187 let result = (|| {
1188 if function.variadic.is_none() && function.params.len() != arguments.len() {
1189 if function.namespace.as_deref() == Some("std.foundation")
1190 && function.name.as_deref() == Some("type")
1191 {
1192 return Err("type expects one value".into());
1193 }
1194 return Err(format!(
1195 "function expects {} arguments",
1196 function.params.len()
1197 ));
1198 }
1199 if arguments.len() < function.params.len() {
1200 return Err(format!(
1201 "function expects at least {} arguments",
1202 function.params.len()
1203 ));
1204 }
1205 let mut env = function.captured.borrow().clone();
1206 for (name, value) in function
1207 .params
1208 .iter()
1209 .zip(arguments.iter().take(function.params.len()))
1210 {
1211 env.insert(name.clone(), value.clone());
1212 }
1213 let mut bound = Vec::new();
1214 for (pattern, value) in function
1215 .patterns
1216 .iter()
1217 .zip(arguments.iter().take(function.params.len()))
1218 {
1219 bind_pattern(pattern, value.clone(), &mut env, &mut bound, None)?;
1220 }
1221 if let Some(name) = &function.variadic {
1222 let rest = Value::List(arguments.into_iter().skip(function.params.len()).collect());
1223 env.insert(name.clone(), rest.clone());
1224 if let Some(pattern) = &function.variadic_pattern {
1225 bind_pattern(pattern, rest, &mut env, &mut bound, None)?;
1226 }
1227 }
1228 let mut result = Value::Nil;
1229 for form in &function.body {
1230 result = eval(form, &mut env)?;
1231 if matches!(result, Value::Recur(_)) {
1232 return Err("recur must be inside loop".into());
1233 }
1234 }
1235 Ok(result)
1236 })();
1237 if let Some((registry, previous)) = namespace_scope {
1238 registry.set_current(previous);
1239 }
1240 let result = result.map_err(append_trace);
1241 #[cfg(feature = "evaluation-journal")]
1242 evaluation_journal_exit(operation, function, result.as_ref().ok());
1243 if tracing {
1244 TRACE_STACK.with(|stack| {
1245 stack.borrow_mut().pop();
1246 });
1247 }
1248 result
1249}
1250
1251#[cfg(feature = "evaluation-journal")]
1254pub fn with_evaluation_journal<T>(
1255 journal_id: crate::journal::JournalId,
1256 limits: crate::journal::JournalLimits,
1257 evaluate: impl FnOnce() -> Result<T, String>,
1258 preview: impl FnOnce(&T, &crate::journal::JournalCollector) -> crate::journal::ValuePreview,
1259) -> (Result<T, String>, crate::journal::Journal) {
1260 EVALUATION_JOURNAL_STACK.with(|stack| stack.borrow_mut().clear());
1261 let previous = EVALUATION_JOURNAL.with(|active| {
1262 active.replace(Some(crate::journal::JournalCollector::new(
1263 journal_id, limits,
1264 )))
1265 });
1266 assert!(
1267 previous.is_none(),
1268 "nested evaluation journals are not supported yet"
1269 );
1270 EVALUATION_JOURNAL.with(|active| {
1271 active
1272 .borrow_mut()
1273 .as_mut()
1274 .expect("evaluation journal must be active")
1275 .record(crate::journal::JournalEvent::new(
1276 crate::journal::JournalEventKind::EvaluationStart,
1277 ));
1278 });
1279 let result = evaluate();
1280 let collector = EVALUATION_JOURNAL.with(|active| {
1281 active
1282 .replace(previous)
1283 .expect("evaluation journal must be active")
1284 });
1285 EVALUATION_JOURNAL_STACK.with(|stack| stack.borrow_mut().clear());
1286 let trace = match &result {
1287 Ok(value) => {
1288 let result = preview(value, &collector);
1289 collector.finish(result)
1290 }
1291 Err(error) => collector.fail(error.clone()),
1292 };
1293 (result, trace)
1294}
1295
1296pub(crate) fn binding_symbol(
1297 form: &Form,
1298 context: &str,
1299) -> Result<(String, Option<Rc<Metadata>>), String> {
1300 match form {
1301 Form::Symbol(name) => Ok((name.clone(), None)),
1302 Form::Metadata(metadata, value) => match value.as_ref() {
1303 Form::Symbol(name) => Ok((name.clone(), Some(metadata_from_form(metadata)?))),
1304 _ => Err(format!("{context} must be a symbol")),
1305 },
1306 _ => Err(format!("{context} must be a symbol")),
1307 }
1308}
1309
1310fn syntax_quote_collection(
1311 values: &[Form],
1312 vector: bool,
1313 env: &mut HashMap<String, Value>,
1314) -> Result<Value, String> {
1315 let mut output = Vec::new();
1316 for value in values {
1317 match value {
1318 Form::List(parts)
1319 if !parts.is_empty()
1320 && matches!(&parts[0], Form::Symbol(name) if name == "unquote") =>
1321 {
1322 if parts.len() != 2 {
1323 return Err("unquote expects one argument".into());
1324 }
1325 output.push(eval(&parts[1], env)?);
1326 }
1327 Form::List(parts)
1328 if !parts.is_empty()
1329 && matches!(&parts[0], Form::Symbol(name) if name == "unquote-splicing") =>
1330 {
1331 if parts.len() != 2 {
1332 return Err("unquote-splicing expects one argument".into());
1333 }
1334 output.extend(iterator_values(eval(&parts[1], env)?)?);
1335 }
1336 value => output.push(syntax_quote_value(value, env)?),
1337 }
1338 }
1339 if vector {
1340 vector_literal(output)
1341 } else {
1342 Ok(Value::List(output.into()))
1343 }
1344}
1345
1346fn syntax_quote_value(form: &Form, env: &mut HashMap<String, Value>) -> Result<Value, String> {
1347 match form {
1348 Form::Symbol(_) => literal_value(form),
1349 Form::List(values)
1350 if values.len() == 2
1351 && matches!(&values[0], Form::Symbol(name) if name == "unquote") =>
1352 {
1353 eval(&values[1], env)
1354 }
1355 Form::List(values) => syntax_quote_collection(values, false, env),
1356 Form::Vector(values) => syntax_quote_collection(values, true, env),
1357 Form::Map(values) => Ok(Value::Map(
1358 values
1359 .iter()
1360 .map(|(key, value)| {
1361 Ok((
1362 syntax_quote_value(key, env)?,
1363 syntax_quote_value(value, env)?,
1364 ))
1365 })
1366 .collect::<Result<Vec<_>, String>>()?
1367 .into_iter()
1368 .collect(),
1369 )),
1370 _ => literal_value(form),
1371 }
1372}