1use crate::ast::Type;
2use crate::jit;
3use crate::number::{
4 float_from_int, float_is_nan, float_to_hash_bits, int_from_float, int_from_usize, LustFloat,
5 LustInt,
6};
7use crate::vm::{pop_vm_ptr, push_vm_ptr, VM};
8use alloc::{
9 borrow::ToOwned,
10 format,
11 rc::{Rc, Weak},
12 string::{String, ToString},
13 vec,
14 vec::Vec,
15};
16use core::cell::RefCell;
17use core::fmt;
18use core::hash::{Hash, Hasher};
19use core::{ptr, slice, str};
20use hashbrown::HashMap;
21#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
22pub struct TaskHandle(pub u64);
23impl TaskHandle {
24 pub fn id(&self) -> u64 {
25 self.0
26 }
27}
28
29#[derive(Clone, Debug)]
30pub enum ValueKey {
31 Int(LustInt),
32 Float(LustFloat),
33 String(Rc<String>),
34 Bool(bool),
35}
36
37impl ValueKey {
38 pub fn from_value(value: &Value) -> Option<Self> {
39 match value {
40 Value::Int(i) => Some(ValueKey::Int(*i)),
41 Value::Float(f) => Some(ValueKey::Float(*f)),
42 Value::String(s) => Some(ValueKey::String(s.clone())),
43 Value::Bool(b) => Some(ValueKey::Bool(*b)),
44 _ => None,
45 }
46 }
47
48 pub fn string<S>(value: S) -> Self
49 where
50 S: Into<String>,
51 {
52 ValueKey::String(Rc::new(value.into()))
53 }
54
55 pub fn to_value(&self) -> Value {
56 match self {
57 ValueKey::Int(i) => Value::Int(*i),
58 ValueKey::Float(f) => Value::Float(*f),
59 ValueKey::String(s) => Value::String(s.clone()),
60 ValueKey::Bool(b) => Value::Bool(*b),
61 }
62 }
63}
64
65impl PartialEq for ValueKey {
66 fn eq(&self, other: &Self) -> bool {
67 match (self, other) {
68 (ValueKey::Int(a), ValueKey::Int(b)) => a == b,
69 (ValueKey::Float(a), ValueKey::Float(b)) => {
70 if float_is_nan(*a) && float_is_nan(*b) {
71 true
72 } else {
73 a == b
74 }
75 }
76
77 (ValueKey::String(a), ValueKey::String(b)) => a == b,
78 (ValueKey::Bool(a), ValueKey::Bool(b)) => a == b,
79 _ => false,
80 }
81 }
82}
83
84impl Eq for ValueKey {}
85impl Hash for ValueKey {
86 fn hash<H: Hasher>(&self, state: &mut H) {
87 match self {
88 ValueKey::Int(i) => {
89 0u8.hash(state);
90 i.hash(state);
91 }
92
93 ValueKey::Float(f) => {
94 1u8.hash(state);
95 if float_is_nan(*f) {
96 u64::MAX.hash(state);
97 } else {
98 float_to_hash_bits(*f).hash(state);
99 }
100 }
101
102 ValueKey::String(s) => {
103 2u8.hash(state);
104 s.hash(state);
105 }
106
107 ValueKey::Bool(b) => {
108 3u8.hash(state);
109 b.hash(state);
110 }
111 }
112 }
113}
114
115impl fmt::Display for ValueKey {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 match self {
118 ValueKey::Int(i) => write!(f, "{}", i),
119 ValueKey::Float(fl) => write!(f, "{}", fl),
120 ValueKey::String(s) => write!(f, "{}", s),
121 ValueKey::Bool(b) => write!(f, "{}", b),
122 }
123 }
124}
125
126impl From<LustInt> for ValueKey {
127 fn from(value: LustInt) -> Self {
128 ValueKey::Int(value)
129 }
130}
131
132impl From<LustFloat> for ValueKey {
133 fn from(value: LustFloat) -> Self {
134 ValueKey::Float(value)
135 }
136}
137
138impl From<bool> for ValueKey {
139 fn from(value: bool) -> Self {
140 ValueKey::Bool(value)
141 }
142}
143
144impl From<String> for ValueKey {
145 fn from(value: String) -> Self {
146 ValueKey::String(Rc::new(value))
147 }
148}
149
150impl From<&str> for ValueKey {
151 fn from(value: &str) -> Self {
152 ValueKey::String(Rc::new(value.to_owned()))
153 }
154}
155
156impl From<Rc<String>> for ValueKey {
157 fn from(value: Rc<String>) -> Self {
158 ValueKey::String(value)
159 }
160}
161
162#[repr(u8)]
163#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164pub enum ValueTag {
165 Nil,
166 Bool,
167 Int,
168 Float,
169 String,
170 Array,
171 Tuple,
172 Map,
173 Struct,
174 Enum,
175 Function,
176 NativeFunction,
177 Closure,
178 Iterator,
179 Task,
180}
181
182impl ValueTag {
183 #[inline]
184 pub const fn as_u8(self) -> u8 {
185 self as u8
186 }
187}
188
189#[derive(Debug, Clone, Copy, PartialEq, Eq)]
190pub enum FieldStorage {
191 Strong,
192 Weak,
193}
194
195#[derive(Debug)]
196pub struct StructLayout {
197 name: String,
198 field_names: Vec<Rc<String>>,
199 field_lookup_ptr: HashMap<usize, usize>,
200 field_lookup_str: HashMap<String, usize>,
201 field_storage: Vec<FieldStorage>,
202 field_types: Vec<Type>,
203 weak_targets: Vec<Option<Type>>,
204}
205
206impl StructLayout {
207 pub fn new(
208 name: String,
209 field_names: Vec<Rc<String>>,
210 field_storage: Vec<FieldStorage>,
211 field_types: Vec<Type>,
212 weak_targets: Vec<Option<Type>>,
213 ) -> Self {
214 debug_assert_eq!(
215 field_names.len(),
216 field_storage.len(),
217 "StructLayout::new expects field names and storage metadata to align"
218 );
219 debug_assert_eq!(
220 field_names.len(),
221 field_types.len(),
222 "StructLayout::new expects field names and type metadata to align"
223 );
224 debug_assert_eq!(
225 field_names.len(),
226 weak_targets.len(),
227 "StructLayout::new expects field names and weak target metadata to align"
228 );
229 let mut field_lookup_ptr = HashMap::with_capacity(field_names.len());
230 let mut field_lookup_str = HashMap::with_capacity(field_names.len());
231 for (index, field_name_rc) in field_names.iter().enumerate() {
232 let ptr = Rc::as_ptr(field_name_rc) as usize;
233 field_lookup_ptr.insert(ptr, index);
234 field_lookup_str.insert((**field_name_rc).clone(), index);
235 }
236
237 Self {
238 name,
239 field_names,
240 field_lookup_ptr,
241 field_lookup_str,
242 field_storage,
243 field_types,
244 weak_targets,
245 }
246 }
247
248 #[inline]
249 pub fn name(&self) -> &str {
250 &self.name
251 }
252
253 #[inline]
254 pub fn field_names(&self) -> &[Rc<String>] {
255 &self.field_names
256 }
257
258 #[inline]
259 pub fn index_of_rc(&self, key: &Rc<String>) -> Option<usize> {
260 let ptr = Rc::as_ptr(key) as usize;
261 self.field_lookup_ptr
262 .get(&ptr)
263 .copied()
264 .or_else(|| self.field_lookup_str.get(key.as_str()).copied())
265 }
266
267 #[inline]
268 pub fn index_of_str(&self, key: &str) -> Option<usize> {
269 self.field_lookup_str.get(key).copied()
270 }
271
272 #[inline]
273 pub fn field_storage(&self, index: usize) -> FieldStorage {
274 self.field_storage[index]
275 }
276
277 #[inline]
278 pub fn field_type(&self, index: usize) -> &Type {
279 &self.field_types[index]
280 }
281
282 #[inline]
283 pub fn weak_target(&self, index: usize) -> Option<&Type> {
284 self.weak_targets[index].as_ref()
285 }
286
287 #[inline]
288 pub fn is_weak(&self, index: usize) -> bool {
289 matches!(self.field_storage(index), FieldStorage::Weak)
290 }
291
292 pub fn canonicalize_field_value(&self, index: usize, value: Value) -> Result<Value, String> {
293 match self.field_storage(index) {
294 FieldStorage::Strong => Ok(value),
295 FieldStorage::Weak => self.canonicalize_weak_field(index, value),
296 }
297 }
298
299 pub fn materialize_field_value(&self, index: usize, value: Value) -> Value {
300 match self.field_storage(index) {
301 FieldStorage::Strong => value,
302 FieldStorage::Weak => self.materialize_weak_field(value),
303 }
304 }
305
306 fn canonicalize_weak_field(&self, index: usize, value: Value) -> Result<Value, String> {
307 let field_name = self.field_names[index].as_str();
308 match value {
309 Value::Enum {
310 enum_name,
311 variant,
312 values,
313 } if enum_name == "Option" => {
314 if variant == "Some" {
315 if let Some(inner_values) = values {
316 if let Some(inner) = inner_values.get(0) {
317 let coerced = self.to_weak_struct(field_name, inner.clone())?;
318 Ok(Value::enum_variant("Option", "Some", vec![coerced]))
319 } else {
320 Ok(Value::enum_unit("Option", "None"))
321 }
322 } else {
323 Ok(Value::enum_unit("Option", "None"))
324 }
325 } else if variant == "None" {
326 Ok(Value::enum_unit("Option", "None"))
327 } else {
328 Err(format!(
329 "Struct '{}' field '{}' uses 'ref' and must store Option values; received variant '{}'",
330 self.name, field_name, variant
331 ))
332 }
333 }
334
335 Value::Nil => Ok(Value::enum_unit("Option", "None")),
336 other => {
337 let coerced = self.to_weak_struct(field_name, other)?;
338 Ok(Value::enum_variant("Option", "Some", vec![coerced]))
339 }
340 }
341 }
342
343 fn materialize_weak_field(&self, value: Value) -> Value {
344 match value {
345 Value::Enum {
346 enum_name,
347 variant,
348 values,
349 } if enum_name == "Option" => {
350 if variant == "Some" {
351 if let Some(inner_values) = values {
352 if let Some(inner) = inner_values.get(0) {
353 match inner {
354 Value::WeakStruct(ref weak) => {
355 if let Some(upgraded) = weak.upgrade() {
356 Value::enum_variant("Option", "Some", vec![upgraded])
357 } else {
358 Value::enum_unit("Option", "None")
359 }
360 }
361
362 _ => Value::enum_variant("Option", "Some", vec![inner.clone()]),
363 }
364 } else {
365 Value::enum_unit("Option", "None")
366 }
367 } else {
368 Value::enum_unit("Option", "None")
369 }
370 } else {
371 Value::enum_unit("Option", "None")
372 }
373 }
374
375 Value::Nil => Value::enum_unit("Option", "None"),
376 other => Value::enum_variant("Option", "Some", vec![other]),
377 }
378 }
379
380 fn to_weak_struct(&self, field_name: &str, value: Value) -> Result<Value, String> {
381 match value {
382 Value::Struct {
383 name,
384 layout,
385 fields,
386 } => Ok(Value::WeakStruct(WeakStructRef::new(name, layout, &fields))),
387 Value::WeakStruct(_) => Ok(value),
388 other => {
389 let ty = other.type_of();
390 Err(format!(
391 "Struct '{}' field '{}' expects a struct reference but received value of type '{:?}'",
392 self.name, field_name, ty
393 ))
394 }
395 }
396 }
397}
398
399#[repr(C, u8)]
400#[derive(Clone)]
401pub enum Value {
402 Nil,
403 Bool(bool),
404 Int(LustInt),
405 Float(LustFloat),
406 String(Rc<String>),
407 Array(Rc<RefCell<Vec<Value>>>),
408 Tuple(Rc<Vec<Value>>),
409 Map(Rc<RefCell<HashMap<ValueKey, Value>>>),
410 Struct {
411 name: String,
412 layout: Rc<StructLayout>,
413 fields: Rc<RefCell<Vec<Value>>>,
414 },
415 WeakStruct(WeakStructRef),
416 Enum {
417 enum_name: String,
418 variant: String,
419 values: Option<Rc<Vec<Value>>>,
420 },
421 Function(usize),
422 NativeFunction(NativeFn),
423 Closure {
424 function_idx: usize,
425 upvalues: Rc<Vec<Upvalue>>,
426 },
427 Iterator(Rc<RefCell<IteratorState>>),
428 Task(TaskHandle),
429}
430
431#[derive(Debug, Clone)]
432pub struct WeakStructRef {
433 name: String,
434 layout: Rc<StructLayout>,
435 fields: Weak<RefCell<Vec<Value>>>,
436}
437
438impl WeakStructRef {
439 pub fn new(name: String, layout: Rc<StructLayout>, fields: &Rc<RefCell<Vec<Value>>>) -> Self {
440 Self {
441 name,
442 layout,
443 fields: Rc::downgrade(fields),
444 }
445 }
446
447 pub fn upgrade(&self) -> Option<Value> {
448 self.fields.upgrade().map(|fields| Value::Struct {
449 name: self.name.clone(),
450 layout: self.layout.clone(),
451 fields,
452 })
453 }
454
455 pub fn struct_name(&self) -> &str {
456 &self.name
457 }
458}
459
460#[derive(Clone)]
461pub enum IteratorState {
462 Array {
463 items: Vec<Value>,
464 index: usize,
465 },
466 MapPairs {
467 items: Vec<(ValueKey, Value)>,
468 index: usize,
469 },
470}
471
472#[derive(Clone)]
473pub struct Upvalue {
474 value: Rc<RefCell<Value>>,
475}
476
477impl Upvalue {
478 pub fn new(value: Value) -> Self {
479 Self {
480 value: Rc::new(RefCell::new(value)),
481 }
482 }
483
484 pub fn get(&self) -> Value {
485 self.value.borrow().clone()
486 }
487
488 pub fn set(&self, value: Value) {
489 *self.value.borrow_mut() = value;
490 }
491}
492
493impl fmt::Debug for Upvalue {
494 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
495 write!(f, "Upvalue({:?})", self.value.borrow())
496 }
497}
498
499#[derive(Debug, Clone)]
500pub enum NativeCallResult {
501 Return(Value),
502 Yield(Value),
503 Stop(Value),
504}
505
506impl From<Value> for NativeCallResult {
507 fn from(value: Value) -> Self {
508 NativeCallResult::Return(value)
509 }
510}
511
512pub type NativeFn = Rc<dyn Fn(&[Value]) -> Result<NativeCallResult, String>>;
513#[derive(Debug, Clone, Copy, PartialEq, Eq)]
514pub enum ValueType {
515 Nil,
516 Bool,
517 Int,
518 Float,
519 String,
520 Array,
521 Tuple,
522 Map,
523 Struct,
524 Enum,
525 Function,
526 NativeFunction,
527 Closure,
528 Iterator,
529 Task,
530}
531
532impl Value {
533 #[inline]
534 pub fn tag(&self) -> ValueTag {
535 match self {
536 Value::Nil => ValueTag::Nil,
537 Value::Bool(_) => ValueTag::Bool,
538 Value::Int(_) => ValueTag::Int,
539 Value::Float(_) => ValueTag::Float,
540 Value::String(_) => ValueTag::String,
541 Value::Array(_) => ValueTag::Array,
542 Value::Tuple(_) => ValueTag::Tuple,
543 Value::Map(_) => ValueTag::Map,
544 Value::Struct { .. } | Value::WeakStruct(_) => ValueTag::Struct,
545 Value::Enum { .. } => ValueTag::Enum,
546 Value::Function(_) => ValueTag::Function,
547 Value::NativeFunction(_) => ValueTag::NativeFunction,
548 Value::Closure { .. } => ValueTag::Closure,
549 Value::Iterator(_) => ValueTag::Iterator,
550 Value::Task(_) => ValueTag::Task,
551 }
552 }
553
554 pub fn type_of(&self) -> ValueType {
555 match self {
556 Value::Nil => ValueType::Nil,
557 Value::Bool(_) => ValueType::Bool,
558 Value::Int(_) => ValueType::Int,
559 Value::Float(_) => ValueType::Float,
560 Value::String(_) => ValueType::String,
561 Value::Array(_) => ValueType::Array,
562 Value::Tuple(_) => ValueType::Tuple,
563 Value::Map(_) => ValueType::Map,
564 Value::Struct { .. } | Value::WeakStruct(_) => ValueType::Struct,
565 Value::Enum { .. } => ValueType::Enum,
566 Value::Function(_) => ValueType::Function,
567 Value::NativeFunction(_) => ValueType::NativeFunction,
568 Value::Closure { .. } => ValueType::Closure,
569 Value::Iterator(_) => ValueType::Iterator,
570 Value::Task(_) => ValueType::Task,
571 }
572 }
573
574 pub fn is_truthy(&self) -> bool {
575 match self {
576 Value::Nil => false,
577 Value::Bool(false) => false,
578 Value::Enum {
579 enum_name, variant, ..
580 } if enum_name == "Option" && variant == "None" => false,
581 _ => true,
582 }
583 }
584
585 pub fn to_bool(&self) -> bool {
586 self.is_truthy()
587 }
588
589 pub fn as_int(&self) -> Option<LustInt> {
590 match self {
591 Value::Int(i) => Some(*i),
592 Value::Float(f) => Some(int_from_float(*f)),
593 _ => None,
594 }
595 }
596
597 pub fn as_float(&self) -> Option<LustFloat> {
598 match self {
599 Value::Float(f) => Some(*f),
600 Value::Int(i) => Some(float_from_int(*i)),
601 _ => None,
602 }
603 }
604
605 pub fn as_string(&self) -> Option<&str> {
606 match self {
607 Value::String(s) => Some(s.as_str()),
608 _ => None,
609 }
610 }
611
612 pub fn as_string_rc(&self) -> Option<Rc<String>> {
613 match self {
614 Value::String(s) => Some(s.clone()),
615 _ => None,
616 }
617 }
618
619 pub fn as_task_handle(&self) -> Option<TaskHandle> {
620 match self {
621 Value::Task(handle) => Some(*handle),
622 _ => None,
623 }
624 }
625
626 pub fn as_array(&self) -> Option<Vec<Value>> {
627 match self {
628 Value::Array(arr) => Some(arr.borrow().clone()),
629 _ => None,
630 }
631 }
632
633 pub fn array_len(&self) -> Option<usize> {
634 match self {
635 Value::Array(arr) => Some(arr.borrow().len()),
636 _ => None,
637 }
638 }
639
640 pub fn array_get(&self, index: usize) -> Option<Value> {
641 match self {
642 Value::Array(arr) => arr.borrow().get(index).cloned(),
643 _ => None,
644 }
645 }
646
647 pub fn array_push(&self, value: Value) -> Result<(), String> {
648 match self {
649 Value::Array(arr) => {
650 arr.borrow_mut().push(value);
651 Ok(())
652 }
653
654 _ => Err("Cannot push to non-array".to_string()),
655 }
656 }
657
658 pub fn array_pop(&self) -> Result<Option<Value>, String> {
659 match self {
660 Value::Array(arr) => Ok(arr.borrow_mut().pop()),
661 _ => Err("Cannot pop from non-array".to_string()),
662 }
663 }
664
665 pub fn as_map(&self) -> Option<HashMap<ValueKey, Value>> {
666 match self {
667 Value::Map(map) => Some(map.borrow().clone()),
668 _ => None,
669 }
670 }
671
672 pub fn map_get(&self, key: &ValueKey) -> Option<Value> {
673 match self {
674 Value::Map(map) => map.borrow().get(key).cloned(),
675 _ => None,
676 }
677 }
678
679 pub fn map_set(&self, key: ValueKey, value: Value) -> Result<(), String> {
680 match self {
681 Value::Map(map) => {
682 map.borrow_mut().insert(key, value);
683 Ok(())
684 }
685
686 _ => Err("Cannot set key on non-map".to_string()),
687 }
688 }
689
690 pub fn map_has(&self, key: &ValueKey) -> Option<bool> {
691 match self {
692 Value::Map(map) => Some(map.borrow().contains_key(key)),
693 _ => None,
694 }
695 }
696
697 pub fn map_delete(&self, key: &ValueKey) -> Result<Option<Value>, String> {
698 match self {
699 Value::Map(map) => Ok(map.borrow_mut().remove(key)),
700 _ => Err("Cannot delete key from non-map".to_string()),
701 }
702 }
703
704 pub fn map_len(&self) -> Option<usize> {
705 match self {
706 Value::Map(map) => Some(map.borrow().len()),
707 _ => None,
708 }
709 }
710
711 pub fn string(s: impl Into<String>) -> Self {
712 Value::String(Rc::new(s.into()))
713 }
714
715 pub fn array(values: Vec<Value>) -> Self {
716 Value::Array(Rc::new(RefCell::new(values)))
717 }
718
719 pub fn tuple(values: Vec<Value>) -> Self {
720 Value::Tuple(Rc::new(values))
721 }
722
723 pub fn tuple_len(&self) -> Option<usize> {
724 match self {
725 Value::Tuple(values) => Some(values.len()),
726 _ => None,
727 }
728 }
729
730 pub fn tuple_get(&self, index: usize) -> Option<Value> {
731 match self {
732 Value::Tuple(values) => values.get(index).cloned(),
733 _ => None,
734 }
735 }
736
737 pub fn map(entries: HashMap<ValueKey, Value>) -> Self {
738 Value::Map(Rc::new(RefCell::new(entries)))
739 }
740
741 pub fn task(handle: TaskHandle) -> Self {
742 Value::Task(handle)
743 }
744
745 pub fn struct_get_field_rc(&self, field: &Rc<String>) -> Option<Value> {
746 match self {
747 Value::Struct { layout, fields, .. } => layout
748 .index_of_rc(field)
749 .or_else(|| layout.index_of_str(field.as_str()))
750 .or_else(|| {
751 layout
752 .field_names()
753 .iter()
754 .position(|name| name.as_str() == field.as_str())
755 })
756 .and_then(|idx| {
757 fields
758 .borrow()
759 .get(idx)
760 .cloned()
761 .map(|value| layout.materialize_field_value(idx, value))
762 }),
763 _ => None,
764 }
765 }
766
767 pub fn struct_get_field(&self, field: &str) -> Option<Value> {
768 match self {
769 Value::Struct { layout, fields, .. } => layout.index_of_str(field).and_then(|idx| {
770 fields
771 .borrow()
772 .get(idx)
773 .cloned()
774 .map(|value| layout.materialize_field_value(idx, value))
775 }),
776 _ => None,
777 }
778 }
779
780 pub fn struct_get_field_indexed(&self, index: usize) -> Option<Value> {
781 match self {
782 Value::Struct { layout, fields, .. } => fields
783 .borrow()
784 .get(index)
785 .cloned()
786 .map(|value| layout.materialize_field_value(index, value)),
787 _ => None,
788 }
789 }
790
791 pub fn struct_set_field_rc(&self, field: &Rc<String>, value: Value) -> Result<(), String> {
792 match self {
793 Value::Struct { layout, .. } => {
794 if let Some(index) = layout
795 .index_of_rc(field)
796 .or_else(|| layout.index_of_str(field.as_str()))
797 {
798 self.struct_set_field_indexed(index, value)
799 } else {
800 Err(format!(
801 "Struct '{}' has no field '{}'",
802 layout.name(),
803 field.as_str()
804 ))
805 }
806 }
807
808 _ => Err("Attempted to set field on non-struct value".to_string()),
809 }
810 }
811
812 pub fn struct_set_field(&self, field: &str, value: Value) -> Result<(), String> {
813 match self {
814 Value::Struct { layout, .. } => {
815 if let Some(index) = layout.index_of_str(field) {
816 self.struct_set_field_indexed(index, value)
817 } else {
818 Err(format!(
819 "Struct '{}' has no field '{}'",
820 layout.name(),
821 field
822 ))
823 }
824 }
825
826 _ => Err("Attempted to set field on non-struct value".to_string()),
827 }
828 }
829
830 pub fn struct_set_field_indexed(&self, index: usize, value: Value) -> Result<(), String> {
831 match self {
832 Value::Struct {
833 name,
834 layout,
835 fields,
836 } => {
837 let mut borrowed = fields.borrow_mut();
838 if index < borrowed.len() {
839 let canonical = layout.canonicalize_field_value(index, value)?;
840 borrowed[index] = canonical;
841 Ok(())
842 } else {
843 Err(format!(
844 "Struct '{}' field index {} out of bounds (len {})",
845 name,
846 index,
847 borrowed.len()
848 ))
849 }
850 }
851
852 _ => Err("Attempted to set field on non-struct value".to_string()),
853 }
854 }
855
856 pub fn enum_unit(enum_name: impl Into<String>, variant: impl Into<String>) -> Self {
857 Value::Enum {
858 enum_name: enum_name.into(),
859 variant: variant.into(),
860 values: None,
861 }
862 }
863
864 pub fn enum_variant(
865 enum_name: impl Into<String>,
866 variant: impl Into<String>,
867 values: Vec<Value>,
868 ) -> Self {
869 Value::Enum {
870 enum_name: enum_name.into(),
871 variant: variant.into(),
872 values: Some(Rc::new(values)),
873 }
874 }
875
876 pub fn as_enum(&self) -> Option<(&str, &str, Option<&[Value]>)> {
877 match self {
878 Value::Enum {
879 enum_name,
880 variant,
881 values,
882 } => Some((
883 enum_name.as_str(),
884 variant.as_str(),
885 values.as_ref().map(|v| v.as_slice()),
886 )),
887 _ => None,
888 }
889 }
890
891 pub fn is_enum_variant(&self, enum_name: &str, variant: &str) -> bool {
892 match self {
893 Value::Enum {
894 enum_name: en,
895 variant: v,
896 ..
897 } => (enum_name.is_empty() || en == enum_name) && v == variant,
898 _ => false,
899 }
900 }
901
902 pub fn some(value: Value) -> Self {
903 Value::enum_variant("Option", "Some", vec![value])
904 }
905
906 pub fn none() -> Self {
907 Value::enum_unit("Option", "None")
908 }
909
910 pub fn ok(value: Value) -> Self {
911 Value::enum_variant("Result", "Ok", vec![value])
912 }
913
914 pub fn err(error: Value) -> Self {
915 Value::enum_variant("Result", "Err", vec![error])
916 }
917
918 pub fn to_string(&self) -> String {
919 format!("{}", self)
920 }
921}
922
923impl fmt::Debug for Value {
924 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
925 match self {
926 Value::Nil => write!(f, "Nil"),
927 Value::Bool(b) => write!(f, "Bool({})", b),
928 Value::Int(i) => write!(f, "Int({})", i),
929 Value::Float(fl) => write!(f, "Float({})", fl),
930 Value::String(s) => write!(f, "String({:?})", s),
931 Value::Array(arr) => write!(f, "Array({:?})", arr.borrow()),
932 Value::Tuple(values) => write!(f, "Tuple({:?})", values),
933 Value::Map(map) => write!(f, "Map({:?})", map.borrow()),
934 Value::Struct {
935 name,
936 layout,
937 fields,
938 } => {
939 let borrowed = fields.borrow();
940 let mut display_fields = Vec::with_capacity(borrowed.len());
941 for (idx, field_name) in layout.field_names().iter().enumerate() {
942 let value = borrowed.get(idx).cloned().unwrap_or(Value::Nil);
943 display_fields.push((field_name.as_str().to_string(), value));
944 }
945
946 write!(
947 f,
948 "Struct {{ name: {:?}, fields: {:?} }}",
949 name, display_fields
950 )
951 }
952
953 Value::WeakStruct(weak) => {
954 if let Some(upgraded) = weak.upgrade() {
955 write!(f, "WeakStruct({:?})", upgraded)
956 } else {
957 write!(f, "WeakStruct(<dangling>)")
958 }
959 }
960
961 Value::Enum {
962 enum_name,
963 variant,
964 values,
965 } => {
966 write!(
967 f,
968 "Enum {{ enum: {:?}, variant: {:?}, values: {:?} }}",
969 enum_name, variant, values
970 )
971 }
972
973 Value::Function(idx) => write!(f, "Function({})", idx),
974 Value::NativeFunction(_) => write!(f, "NativeFunction(<fn>)"),
975 Value::Closure {
976 function_idx,
977 upvalues,
978 } => {
979 write!(
980 f,
981 "Closure {{ function: {}, upvalues: {:?} }}",
982 function_idx, upvalues
983 )
984 }
985
986 Value::Iterator(_) => write!(f, "Iterator(<state>)"),
987 Value::Task(handle) => write!(f, "Task({})", handle.0),
988 }
989 }
990}
991
992impl fmt::Display for Value {
993 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
994 match self {
995 Value::Nil => write!(f, "nil"),
996 Value::Bool(b) => write!(f, "{}", b),
997 Value::Int(i) => write!(f, "{}", i),
998 Value::Float(fl) => write!(f, "{}", fl),
999 Value::String(s) => write!(f, "{}", s),
1000 Value::Array(arr) => {
1001 write!(f, "[")?;
1002 let borrowed = arr.borrow();
1003 for (i, val) in borrowed.iter().enumerate() {
1004 if i > 0 {
1005 write!(f, ", ")?;
1006 }
1007
1008 write!(f, "{}", val)?;
1009 }
1010
1011 write!(f, "]")
1012 }
1013
1014 Value::Tuple(values) => {
1015 write!(f, "(")?;
1016 for (i, val) in values.iter().enumerate() {
1017 if i > 0 {
1018 write!(f, ", ")?;
1019 }
1020
1021 write!(f, "{}", val)?;
1022 }
1023
1024 write!(f, ")")
1025 }
1026
1027 Value::Map(map) => {
1028 write!(f, "{{")?;
1029 let borrowed = map.borrow();
1030 for (i, (k, v)) in borrowed.iter().enumerate() {
1031 if i > 0 {
1032 write!(f, ", ")?;
1033 }
1034
1035 write!(f, "{}: {}", k, v)?;
1036 }
1037
1038 write!(f, "}}")
1039 }
1040
1041 Value::Struct {
1042 name,
1043 layout,
1044 fields,
1045 } => {
1046 let borrowed = fields.borrow();
1047 write!(f, "{} {{", name)?;
1048 for (i, field_name) in layout.field_names().iter().enumerate() {
1049 if i > 0 {
1050 write!(f, ", ")?;
1051 }
1052
1053 let value = borrowed.get(i).unwrap_or(&Value::Nil);
1054 write!(f, "{}: {}", field_name, value)?;
1055 }
1056
1057 write!(f, "}}")
1058 }
1059
1060 Value::WeakStruct(weak) => {
1061 if let Some(strong) = weak.upgrade() {
1062 strong.fmt(f)
1063 } else {
1064 write!(f, "nil")
1065 }
1066 }
1067
1068 Value::Enum {
1069 enum_name,
1070 variant,
1071 values,
1072 } => {
1073 write!(f, "{}.{}", enum_name, variant)?;
1074 if let Some(vals) = values {
1075 write!(f, "(")?;
1076 for (i, val) in vals.iter().enumerate() {
1077 if i > 0 {
1078 write!(f, ", ")?;
1079 }
1080
1081 write!(f, "{}", val)?;
1082 }
1083
1084 write!(f, ")")?;
1085 }
1086
1087 Ok(())
1088 }
1089
1090 Value::Function(idx) => write!(f, "<function@{}>", idx),
1091 Value::NativeFunction(_) => write!(f, "<native function>"),
1092 Value::Closure { function_idx, .. } => write!(f, "<closure@{}>", function_idx),
1093 Value::Iterator(_) => write!(f, "<iterator>"),
1094 Value::Task(handle) => write!(f, "<task {}>", handle.0),
1095 }
1096 }
1097}
1098
1099impl PartialEq for Value {
1100 fn eq(&self, other: &Self) -> bool {
1101 match (self, other) {
1102 (Value::Nil, Value::Nil) => true,
1103 (Value::Bool(a), Value::Bool(b)) => a == b,
1104 (Value::Int(a), Value::Int(b)) => a == b,
1105 (Value::Float(a), Value::Float(b)) => a == b,
1106 (Value::String(a), Value::String(b)) => a == b,
1107 (Value::Array(a), Value::Array(b)) => *a.borrow() == *b.borrow(),
1108 (Value::Tuple(a), Value::Tuple(b)) => *a == *b,
1109 (Value::Map(a), Value::Map(b)) => *a.borrow() == *b.borrow(),
1110 (
1111 Value::Struct {
1112 name: n1,
1113 layout: l1,
1114 fields: f1,
1115 },
1116 Value::Struct {
1117 name: n2,
1118 layout: l2,
1119 fields: f2,
1120 },
1121 ) => {
1122 if n1 != n2 {
1123 return false;
1124 }
1125
1126 let borrowed_f1 = f1.borrow();
1127 let borrowed_f2 = f2.borrow();
1128 if borrowed_f1.len() != borrowed_f2.len() {
1129 return false;
1130 }
1131
1132 if Rc::ptr_eq(l1, l2) {
1133 return borrowed_f1
1134 .iter()
1135 .zip(borrowed_f2.iter())
1136 .all(|(a, b)| a == b);
1137 }
1138
1139 l1.field_names()
1140 .iter()
1141 .enumerate()
1142 .all(|(idx, field_name)| {
1143 if let Some(other_idx) = l2.index_of_rc(field_name) {
1144 borrowed_f1
1145 .get(idx)
1146 .zip(borrowed_f2.get(other_idx))
1147 .map(|(a, b)| a == b)
1148 .unwrap_or(false)
1149 } else {
1150 false
1151 }
1152 })
1153 }
1154
1155 (Value::WeakStruct(a), Value::WeakStruct(b)) => match (a.upgrade(), b.upgrade()) {
1156 (Some(left), Some(right)) => left == right,
1157 (None, None) => true,
1158 _ => false,
1159 },
1160 (Value::WeakStruct(a), other) => a
1161 .upgrade()
1162 .map(|upgraded| upgraded == *other)
1163 .unwrap_or(matches!(other, Value::Nil)),
1164 (value, Value::WeakStruct(b)) => b
1165 .upgrade()
1166 .map(|upgraded| *value == upgraded)
1167 .unwrap_or(matches!(value, Value::Nil)),
1168 (
1169 Value::Enum {
1170 enum_name: e1,
1171 variant: v1,
1172 values: vals1,
1173 },
1174 Value::Enum {
1175 enum_name: e2,
1176 variant: v2,
1177 values: vals2,
1178 },
1179 ) => e1 == e2 && v1 == v2 && vals1 == vals2,
1180 (Value::Function(a), Value::Function(b)) => a == b,
1181 (
1182 Value::Closure {
1183 function_idx: f1,
1184 upvalues: u1,
1185 },
1186 Value::Closure {
1187 function_idx: f2,
1188 upvalues: u2,
1189 },
1190 ) => f1 == f2 && Rc::ptr_eq(u1, u2),
1191 (Value::Iterator(_), Value::Iterator(_)) => false,
1192 (Value::Task(a), Value::Task(b)) => a == b,
1193 _ => false,
1194 }
1195 }
1196}
1197
1198#[cfg(feature = "std")]
1199#[no_mangle]
1200pub unsafe extern "C" fn jit_array_get_safe(
1201 array_value_ptr: *const Value,
1202 index: i64,
1203 out: *mut Value,
1204) -> u8 {
1205 if array_value_ptr.is_null() || out.is_null() {
1206 eprintln!("❌ jit_array_get_safe: null pointer detected!");
1207 return 0;
1208 }
1209
1210 let array_value = &*array_value_ptr;
1211 let arr = match array_value {
1212 Value::Array(arr) => arr,
1213 _ => {
1214 return 0;
1215 }
1216 };
1217 if index < 0 {
1218 return 0;
1219 }
1220
1221 let idx = index as usize;
1222 let borrowed = match arr.try_borrow() {
1223 Ok(b) => b,
1224 Err(_) => {
1225 return 0;
1226 }
1227 };
1228 if idx >= borrowed.len() {
1229 return 0;
1230 }
1231
1232 ptr::write(out, borrowed[idx].clone());
1233 1
1234}
1235
1236#[cfg(feature = "std")]
1237#[no_mangle]
1238pub unsafe extern "C" fn jit_array_len_safe(array_value_ptr: *const Value) -> i64 {
1239 if array_value_ptr.is_null() {
1240 return -1;
1241 }
1242
1243 let array_value = &*array_value_ptr;
1244 match array_value {
1245 Value::Array(arr) => match arr.try_borrow() {
1246 Ok(borrowed) => int_from_usize(borrowed.len()),
1247 Err(_) => -1,
1248 },
1249 _ => -1,
1250 }
1251}
1252
1253#[cfg(feature = "std")]
1254static JIT_NEW_ARRAY_COUNTER: core::sync::atomic::AtomicUsize =
1255 core::sync::atomic::AtomicUsize::new(0);
1256
1257#[cfg(feature = "std")]
1258#[no_mangle]
1259pub unsafe extern "C" fn jit_new_array_safe(
1260 elements_ptr: *const Value,
1261 element_count: usize,
1262 out_ptr: *mut Value,
1263) -> u8 {
1264 let call_num = JIT_NEW_ARRAY_COUNTER.fetch_add(1, core::sync::atomic::Ordering::SeqCst);
1265 if out_ptr.is_null() {
1268 return 0;
1270 }
1271
1272 let elements = if element_count == 0 {
1274 Vec::new()
1275 } else {
1276 if elements_ptr.is_null() {
1277 return 0;
1279 }
1280
1281 let slice = slice::from_raw_parts(elements_ptr, element_count);
1282 slice.to_vec()
1283 };
1284
1285 let array_value = Value::array(elements);
1287 ptr::write(out_ptr, array_value);
1289 1
1291}
1292
1293#[cfg(feature = "std")]
1294#[no_mangle]
1295pub unsafe extern "C" fn jit_array_push_safe(
1296 array_ptr: *const Value,
1297 value_ptr: *const Value,
1298) -> u8 {
1299 if array_ptr.is_null() || value_ptr.is_null() {
1300 return 0;
1301 }
1302
1303 let array_value = &*array_ptr;
1304 let value = &*value_ptr;
1305
1306 match array_value {
1307 Value::Array(arr) => {
1308 let cell_ptr = arr.as_ptr();
1310 (*cell_ptr).push(value.clone());
1311 1
1312 }
1313 _ => 0,
1314 }
1315}
1316
1317#[cfg(feature = "std")]
1322#[no_mangle]
1323pub unsafe extern "C" fn jit_unbox_array_int(
1324 array_value_ptr: *const Value,
1325 out_vec_ptr: *mut *mut LustInt,
1326 out_len: *mut usize,
1327 out_cap: *mut usize,
1328) -> u8 {
1329 if array_value_ptr.is_null() || out_vec_ptr.is_null() || out_len.is_null() || out_cap.is_null()
1330 {
1331 return 0;
1332 }
1333
1334 let array_value = &*array_value_ptr;
1335 match array_value {
1336 Value::Array(arr_rc) => {
1337 let cell_ptr = arr_rc.as_ptr();
1339 let vec_ref = &mut *cell_ptr;
1340
1341 let original_vec = core::mem::replace(vec_ref, Vec::new());
1343
1344 let mut specialized_vec: Vec<LustInt> = Vec::with_capacity(original_vec.len());
1346 for elem in original_vec.into_iter() {
1347 match elem {
1348 Value::Int(i) => specialized_vec.push(i),
1349 _ => {
1350 return 0;
1353 }
1354 }
1355 }
1356
1357 let len = specialized_vec.len();
1359 let cap = specialized_vec.capacity();
1360 let ptr = specialized_vec.as_mut_ptr();
1361
1362 core::mem::forget(specialized_vec);
1364
1365 ptr::write(out_vec_ptr, ptr);
1367 ptr::write(out_len, len);
1368 ptr::write(out_cap, cap);
1369
1370 1
1374 }
1375 _ => 0,
1376 }
1377}
1378
1379#[cfg(feature = "std")]
1383#[no_mangle]
1384pub unsafe extern "C" fn jit_rebox_array_int(
1385 vec_ptr: *mut LustInt,
1386 vec_len: usize,
1387 vec_cap: usize,
1388 array_value_ptr: *mut Value,
1389) -> u8 {
1390 if vec_ptr.is_null() || array_value_ptr.is_null() {
1391 return 0;
1392 }
1393
1394 let specialized_vec = Vec::from_raw_parts(vec_ptr, vec_len, vec_cap);
1396
1397 let array_value = &mut *array_value_ptr;
1399 match array_value {
1400 Value::Array(arr_rc) => {
1401 let cell_ptr = arr_rc.as_ptr();
1403 let vec_ref = &mut *cell_ptr;
1404
1405 *vec_ref = specialized_vec.into_iter().map(Value::Int).collect();
1407
1408 1
1409 }
1410 _ => {
1411 let value_vec: Vec<Value> = specialized_vec.into_iter().map(Value::Int).collect();
1414 let array_value_new = Value::array(value_vec);
1415 ptr::write(array_value_ptr, array_value_new);
1416 1
1417 }
1418 }
1419}
1420
1421#[cfg(feature = "std")]
1424#[no_mangle]
1425pub unsafe extern "C" fn jit_vec_int_push(
1426 vec_ptr: *mut *mut LustInt,
1427 vec_len: *mut usize,
1428 vec_cap: *mut usize,
1429 value: LustInt,
1430) -> u8 {
1431 if vec_ptr.is_null() || vec_len.is_null() || vec_cap.is_null() {
1432 return 0;
1433 }
1434
1435 let ptr = *vec_ptr;
1436 let len = *vec_len;
1437 let cap = *vec_cap;
1438
1439 let mut vec = Vec::from_raw_parts(ptr, len, cap);
1441
1442 vec.push(value);
1444
1445 let new_len = vec.len();
1447 let new_cap = vec.capacity();
1448 let new_ptr = vec.as_mut_ptr();
1449
1450 core::mem::forget(vec);
1452
1453 ptr::write(vec_ptr, new_ptr);
1455 ptr::write(vec_len, new_len);
1456 ptr::write(vec_cap, new_cap);
1457
1458 1
1459}
1460
1461#[cfg(feature = "std")]
1465#[no_mangle]
1466pub unsafe extern "C" fn jit_drop_vec_int(vec_ptr: *mut LustInt, vec_len: usize, vec_cap: usize) {
1467 eprintln!(
1468 "🗑️ jit_drop_vec_int: ptr={:p}, len={}, cap={}",
1469 vec_ptr, vec_len, vec_cap
1470 );
1471 eprintln!("🗑️ jit_drop_vec_int: THIS SHOULD NOT BE CALLED - THE VEC DATA IS STALE!");
1472
1473 eprintln!("🗑️ jit_drop_vec_int: skipping drop (would cause corruption)");
1476}
1477
1478#[cfg(feature = "std")]
1479#[no_mangle]
1480pub unsafe extern "C" fn jit_enum_is_some_safe(enum_ptr: *const Value, out_ptr: *mut Value) -> u8 {
1481 if enum_ptr.is_null() || out_ptr.is_null() {
1482 return 0;
1483 }
1484
1485 let enum_value = &*enum_ptr;
1486 match enum_value {
1487 Value::Enum { variant, .. } => {
1488 let is_some = variant == "Some";
1489 ptr::write(out_ptr, Value::Bool(is_some));
1490 1
1491 }
1492 _ => 0,
1493 }
1494}
1495
1496#[cfg(feature = "std")]
1497#[no_mangle]
1498pub unsafe extern "C" fn jit_enum_unwrap_safe(enum_ptr: *const Value, out_ptr: *mut Value) -> u8 {
1499 if enum_ptr.is_null() || out_ptr.is_null() {
1500 return 0;
1501 }
1502
1503 let enum_value = &*enum_ptr;
1504 match enum_value {
1505 Value::Enum {
1506 values: Some(vals), ..
1507 } if vals.len() == 1 => {
1508 ptr::write(out_ptr, vals[0].clone());
1509 1
1510 }
1511 _ => 0,
1512 }
1513}
1514
1515#[cfg(feature = "std")]
1516#[no_mangle]
1517pub unsafe extern "C" fn jit_set_field_strong_safe(
1518 object_ptr: *const Value,
1519 field_index: usize,
1520 value_ptr: *const Value,
1521) -> u8 {
1522 if object_ptr.is_null() || value_ptr.is_null() {
1523 return 0;
1524 }
1525
1526 let object = &*object_ptr;
1527 let value = (&*value_ptr).clone();
1528
1529 match object {
1530 Value::Struct { fields, .. } => {
1531 match fields.try_borrow_mut() {
1533 Ok(mut borrowed) => {
1534 if field_index < borrowed.len() {
1535 borrowed[field_index] = value;
1536 1
1537 } else {
1538 0
1539 }
1540 }
1541 Err(_) => 0,
1542 }
1543 }
1544 _ => 0,
1545 }
1546}
1547
1548#[cfg(feature = "std")]
1549#[no_mangle]
1550pub unsafe extern "C" fn jit_concat_safe(
1551 left_value_ptr: *const Value,
1552 right_value_ptr: *const Value,
1553 out: *mut Value,
1554) -> u8 {
1555 if left_value_ptr.is_null() || right_value_ptr.is_null() || out.is_null() {
1556 return 0;
1557 }
1558
1559 let left = &*left_value_ptr;
1560 let right = &*right_value_ptr;
1561 const NO_VM_ERROR: &str = "task API requires a running VM";
1562 let left_str = match VM::with_current(|vm| {
1563 let left_copy = left.clone();
1564 vm.value_to_string_for_concat(&left_copy)
1565 .map_err(|err| err.to_string())
1566 }) {
1567 Ok(rc) => rc,
1568 Err(err) if err == NO_VM_ERROR => Rc::new(left.to_string()),
1569 Err(_) => return 0,
1570 };
1571 let right_str = match VM::with_current(|vm| {
1572 let right_copy = right.clone();
1573 vm.value_to_string_for_concat(&right_copy)
1574 .map_err(|err| err.to_string())
1575 }) {
1576 Ok(rc) => rc,
1577 Err(err) if err == NO_VM_ERROR => Rc::new(right.to_string()),
1578 Err(_) => return 0,
1579 };
1580 let mut combined = String::with_capacity(left_str.len() + right_str.len());
1581 combined.push_str(left_str.as_ref());
1582 combined.push_str(right_str.as_ref());
1583 let result = Value::string(combined);
1584 ptr::write(out, result);
1585 1
1586}
1587
1588#[no_mangle]
1589pub unsafe extern "C" fn jit_guard_native_function(
1590 value_ptr: *const Value,
1591 expected_fn_ptr: *const (),
1592 register_index: u8,
1593) -> u8 {
1594 if value_ptr.is_null() || expected_fn_ptr.is_null() {
1595 jit::log(|| "jit_guard_native_function: null pointer input".to_string());
1596 return 0;
1597 }
1598
1599 match &*value_ptr {
1600 Value::NativeFunction(func) => {
1601 let actual = Rc::as_ptr(func) as *const ();
1602 if actual == expected_fn_ptr {
1603 1
1604 } else {
1605 jit::log(|| {
1606 format!(
1607 "jit_guard_native_function: pointer mismatch (reg {}) actual={:p} expected={:p}",
1608 register_index, actual, expected_fn_ptr
1609 )
1610 });
1611 0
1612 }
1613 }
1614
1615 other => {
1616 jit::log(|| {
1617 format!(
1618 "jit_guard_native_function: value not native in reg {} ({:?})",
1619 register_index,
1620 other.tag()
1621 )
1622 });
1623 0
1624 }
1625 }
1626}
1627
1628#[no_mangle]
1629pub unsafe extern "C" fn jit_guard_function_identity(
1630 value_ptr: *const Value,
1631 expected_kind: u8,
1632 expected_function_idx: usize,
1633 expected_upvalues: *const (),
1634 register_index: u8,
1635) -> u8 {
1636 if value_ptr.is_null() {
1637 jit::log(|| "jit_guard_function_identity: null pointer input".to_string());
1638 return 0;
1639 }
1640
1641 let value = &*value_ptr;
1642 match (expected_kind, value) {
1643 (0, Value::Function(idx)) => {
1644 if *idx == expected_function_idx {
1645 1
1646 } else {
1647 jit::log(|| {
1648 format!(
1649 "jit_guard_function_identity: function idx mismatch (reg {}) actual={} expected={}",
1650 register_index, idx, expected_function_idx
1651 )
1652 });
1653 0
1654 }
1655 }
1656
1657 (
1658 1,
1659 Value::Closure {
1660 function_idx,
1661 upvalues,
1662 },
1663 ) => {
1664 if *function_idx != expected_function_idx {
1665 jit::log(|| {
1666 format!(
1667 "jit_guard_function_identity: closure idx mismatch (reg {}) actual={} expected={}",
1668 register_index, function_idx, expected_function_idx
1669 )
1670 });
1671 return 0;
1672 }
1673
1674 let actual_ptr = Rc::as_ptr(upvalues) as *const ();
1675 if actual_ptr == expected_upvalues {
1676 1
1677 } else {
1678 jit::log(|| {
1679 format!(
1680 "jit_guard_function_identity: upvalues mismatch (reg {}) actual={:p} expected={:p}",
1681 register_index, actual_ptr, expected_upvalues
1682 )
1683 });
1684 0
1685 }
1686 }
1687
1688 (0, Value::Closure { function_idx, .. }) => {
1689 jit::log(|| {
1690 format!(
1691 "jit_guard_function_identity: expected function, saw closure (reg {}, idx {})",
1692 register_index, function_idx
1693 )
1694 });
1695 0
1696 }
1697
1698 (1, Value::Function(idx)) => {
1699 jit::log(|| {
1700 format!(
1701 "jit_guard_function_identity: expected closure, saw function (reg {}, idx {})",
1702 register_index, idx
1703 )
1704 });
1705 0
1706 }
1707
1708 (_, other) => {
1709 jit::log(|| {
1710 format!(
1711 "jit_guard_function_identity: value in reg {} not callable ({:?})",
1712 register_index,
1713 other.tag()
1714 )
1715 });
1716 0
1717 }
1718 }
1719}
1720
1721#[no_mangle]
1722pub unsafe extern "C" fn jit_call_native_safe(
1723 vm_ptr: *mut VM,
1724 callee_ptr: *const Value,
1725 expected_fn_ptr: *const (),
1726 args_ptr: *const Value,
1727 arg_count: u8,
1728 out: *mut Value,
1729) -> u8 {
1730 if vm_ptr.is_null() || callee_ptr.is_null() || expected_fn_ptr.is_null() || out.is_null() {
1731 jit::log(|| "jit_call_native_safe: null argument".to_string());
1732 return 0;
1733 }
1734
1735 let callee = &*callee_ptr;
1736 let native_fn = match callee {
1737 Value::NativeFunction(func) => func.clone(),
1738 other => {
1739 jit::log(|| {
1740 format!(
1741 "jit_call_native_safe: callee not native ({:?})",
1742 other.tag()
1743 )
1744 });
1745 return 0;
1746 }
1747 };
1748
1749 if Rc::as_ptr(&native_fn) as *const () != expected_fn_ptr {
1750 jit::log(|| {
1751 format!(
1752 "jit_call_native_safe: pointer mismatch actual={:p} expected={:p}",
1753 Rc::as_ptr(&native_fn),
1754 expected_fn_ptr
1755 )
1756 });
1757 return 0;
1758 }
1759
1760 let mut args = Vec::with_capacity(arg_count as usize);
1761 if arg_count > 0 {
1762 if args_ptr.is_null() {
1763 jit::log(|| "jit_call_native_safe: args_ptr null with non-zero arg_count".to_string());
1764 return 0;
1765 }
1766
1767 for i in 0..(arg_count as usize) {
1768 let arg = &*args_ptr.add(i);
1769 args.push(arg.clone());
1770 }
1771 }
1772
1773 push_vm_ptr(vm_ptr);
1774 let outcome = native_fn(&args);
1775 pop_vm_ptr();
1776
1777 let outcome = match outcome {
1778 Ok(result) => result,
1779 Err(err) => {
1780 jit::log(|| format!("jit_call_native_safe: native returned error: {}", err));
1781 return 0;
1782 }
1783 };
1784
1785 match outcome {
1786 NativeCallResult::Return(value) => {
1787 ptr::write(out, value);
1788 1
1789 }
1790
1791 NativeCallResult::Yield(_) => {
1792 jit::log(|| "jit_call_native_safe: native attempted to yield".to_string());
1793 0
1794 }
1795
1796 NativeCallResult::Stop(_) => {
1797 jit::log(|| "jit_call_native_safe: native attempted to stop".to_string());
1798 0
1799 }
1800 }
1801}
1802
1803#[no_mangle]
1804pub unsafe extern "C" fn jit_call_function_safe(
1805 vm_ptr: *mut VM,
1806 callee_ptr: *const Value,
1807 args_ptr: *const Value,
1808 arg_count: u8,
1809 dest_reg: u8,
1810) -> u8 {
1811 if vm_ptr.is_null() || callee_ptr.is_null() {
1812 jit::log(|| "jit_call_function_safe: null argument".to_string());
1813 return 0;
1814 }
1815
1816 if arg_count > 0 && args_ptr.is_null() {
1817 jit::log(|| "jit_call_function_safe: args_ptr null with non-zero arg_count".to_string());
1818 return 0;
1819 }
1820
1821 let callee = (&*callee_ptr).clone();
1823 let mut args = Vec::with_capacity(arg_count as usize);
1824 for i in 0..(arg_count as usize) {
1825 let arg_ptr = args_ptr.add(i);
1826 args.push((&*arg_ptr).clone());
1827 }
1828
1829 let vm = &mut *vm_ptr;
1830 push_vm_ptr(vm_ptr);
1831
1832 let jit_was_enabled = vm.jit.enabled;
1834 vm.jit.enabled = false;
1835
1836 let call_result = vm.call_value(&callee, args);
1837
1838 vm.jit.enabled = jit_was_enabled;
1840 pop_vm_ptr();
1841
1842 match call_result {
1843 Ok(value) => {
1844 let vm = &mut *vm_ptr;
1846 if let Some(frame) = vm.call_stack.last_mut() {
1847 if (dest_reg as usize) < frame.registers.len() {
1848 frame.registers[dest_reg as usize] = value;
1849 1
1850 } else {
1851 jit::log(|| {
1852 format!(
1853 "jit_call_function_safe: dest_reg {} out of bounds",
1854 dest_reg
1855 )
1856 });
1857 0
1858 }
1859 } else {
1860 jit::log(|| "jit_call_function_safe: no call frame".to_string());
1861 0
1862 }
1863 }
1864
1865 Err(err) => {
1866 jit::log(|| format!("jit_call_function_safe: {}", err));
1867 0
1868 }
1869 }
1870}
1871
1872#[no_mangle]
1873pub unsafe extern "C" fn jit_current_registers(vm_ptr: *mut VM) -> *mut Value {
1874 if vm_ptr.is_null() {
1875 return core::ptr::null_mut();
1876 }
1877
1878 let vm = &mut *vm_ptr;
1879 vm.call_stack
1880 .last_mut()
1881 .map(|frame| frame.registers.as_mut_ptr())
1882 .unwrap_or(core::ptr::null_mut())
1883}
1884
1885#[no_mangle]
1886pub unsafe extern "C" fn jit_value_is_truthy(value_ptr: *const Value) -> u8 {
1887 if value_ptr.is_null() {
1888 return 0;
1889 }
1890
1891 let value = &*value_ptr;
1892 if value.is_truthy() {
1893 1
1894 } else {
1895 0
1896 }
1897}
1898
1899#[no_mangle]
1900pub unsafe extern "C" fn jit_new_enum_unit_safe(
1901 enum_name_ptr: *const u8,
1902 enum_name_len: usize,
1903 variant_name_ptr: *const u8,
1904 variant_name_len: usize,
1905 out: *mut Value,
1906) -> u8 {
1907 if enum_name_ptr.is_null() || variant_name_ptr.is_null() || out.is_null() {
1908 return 0;
1909 }
1910
1911 let enum_name_slice = slice::from_raw_parts(enum_name_ptr, enum_name_len);
1912 let variant_name_slice = slice::from_raw_parts(variant_name_ptr, variant_name_len);
1913 let enum_name = match str::from_utf8(enum_name_slice) {
1914 Ok(s) => s.to_string(),
1915 Err(_) => return 0,
1916 };
1917 let variant_name = match str::from_utf8(variant_name_slice) {
1918 Ok(s) => s.to_string(),
1919 Err(_) => return 0,
1920 };
1921 let value = Value::enum_unit(enum_name, variant_name);
1922 ptr::write(out, value);
1923 1
1924}
1925
1926#[no_mangle]
1927pub unsafe extern "C" fn jit_new_enum_variant_safe(
1928 enum_name_ptr: *const u8,
1929 enum_name_len: usize,
1930 variant_name_ptr: *const u8,
1931 variant_name_len: usize,
1932 values_ptr: *const Value,
1933 value_count: usize,
1934 out: *mut Value,
1935) -> u8 {
1936 if enum_name_ptr.is_null() || variant_name_ptr.is_null() || out.is_null() {
1937 return 0;
1938 }
1939
1940 if value_count > 0 && values_ptr.is_null() {
1941 return 0;
1942 }
1943
1944 let enum_name_slice = slice::from_raw_parts(enum_name_ptr, enum_name_len);
1945 let variant_name_slice = slice::from_raw_parts(variant_name_ptr, variant_name_len);
1946 let enum_name = match str::from_utf8(enum_name_slice) {
1947 Ok(s) => s.to_string(),
1948 Err(_) => return 0,
1949 };
1950 let variant_name = match str::from_utf8(variant_name_slice) {
1951 Ok(s) => s.to_string(),
1952 Err(_) => return 0,
1953 };
1954 let mut values = Vec::with_capacity(value_count);
1955 for i in 0..value_count {
1956 let value = &*values_ptr.add(i);
1957 values.push(value.clone());
1958 }
1959
1960 let value = Value::enum_variant(enum_name, variant_name, values);
1961 ptr::write(out, value);
1962 1
1963}
1964
1965#[no_mangle]
1966pub unsafe extern "C" fn jit_is_enum_variant_safe(
1967 value_ptr: *const Value,
1968 enum_name_ptr: *const u8,
1969 enum_name_len: usize,
1970 variant_name_ptr: *const u8,
1971 variant_name_len: usize,
1972) -> u8 {
1973 if value_ptr.is_null() || enum_name_ptr.is_null() || variant_name_ptr.is_null() {
1974 return 0;
1975 }
1976
1977 let value = &*value_ptr;
1978 let enum_name_slice = slice::from_raw_parts(enum_name_ptr, enum_name_len);
1979 let variant_name_slice = slice::from_raw_parts(variant_name_ptr, variant_name_len);
1980 let enum_name = match str::from_utf8(enum_name_slice) {
1981 Ok(s) => s,
1982 Err(_) => return 0,
1983 };
1984 let variant_name = match str::from_utf8(variant_name_slice) {
1985 Ok(s) => s,
1986 Err(_) => return 0,
1987 };
1988 if value.is_enum_variant(enum_name, variant_name) {
1989 1
1990 } else {
1991 0
1992 }
1993}
1994
1995#[no_mangle]
1996pub unsafe extern "C" fn jit_get_enum_value_safe(
1997 enum_ptr: *const Value,
1998 index: usize,
1999 out: *mut Value,
2000) -> u8 {
2001 if enum_ptr.is_null() || out.is_null() {
2002 return 0;
2003 }
2004
2005 let enum_value = &*enum_ptr;
2006 if let Some((_, _, Some(values))) = enum_value.as_enum() {
2007 if index < values.len() {
2008 ptr::write(out, values[index].clone());
2009 1
2010 } else {
2011 0
2012 }
2013 } else {
2014 0
2015 }
2016}
2017
2018#[no_mangle]
2019pub unsafe extern "C" fn jit_call_method_safe(
2020 vm_ptr: *mut VM,
2021 object_ptr: *const Value,
2022 method_name_ptr: *const u8,
2023 method_name_len: usize,
2024 args_ptr: *const Value,
2025 arg_count: u8,
2026 dest_reg: u8,
2027) -> u8 {
2028 if vm_ptr.is_null() || object_ptr.is_null() || method_name_ptr.is_null() {
2029 jit::log(|| "jit_call_method_safe: null pointer argument".to_string());
2030 return 0;
2031 }
2032
2033 if arg_count > 0 && args_ptr.is_null() {
2034 return 0;
2035 }
2036
2037 let method_name_slice = slice::from_raw_parts(method_name_ptr, method_name_len);
2038 let method_name = match str::from_utf8(method_name_slice) {
2039 Ok(s) => s,
2040 Err(_) => return 0,
2041 };
2042
2043 let object = (&*object_ptr).clone();
2044 if matches!(object, Value::Struct { .. }) {
2045 return 0;
2046 }
2047
2048 let mut args = Vec::with_capacity(arg_count as usize);
2049 for i in 0..arg_count {
2050 let arg_ptr = args_ptr.add(i as usize);
2051 args.push((&*arg_ptr).clone());
2052 }
2053
2054 crate::vm::push_vm_ptr(vm_ptr);
2055 let outcome = call_builtin_method_simple(&object, method_name, args);
2056 crate::vm::pop_vm_ptr();
2057 match outcome {
2058 Ok(val) => {
2059 let vm = &mut *vm_ptr;
2060 if let Some(frame) = vm.call_stack.last_mut() {
2061 if (dest_reg as usize) < frame.registers.len() {
2062 frame.registers[dest_reg as usize] = val;
2063 1
2064 } else {
2065 jit::log(|| {
2066 format!("jit_call_method_safe: dest_reg {} out of bounds", dest_reg)
2067 });
2068 0
2069 }
2070 } else {
2071 jit::log(|| "jit_call_method_safe: no call frame".to_string());
2072 0
2073 }
2074 }
2075 Err(_) => 0,
2076 }
2077}
2078
2079fn call_builtin_method_simple(
2080 object: &Value,
2081 method_name: &str,
2082 args: Vec<Value>,
2083) -> Result<Value, String> {
2084 match object {
2085 Value::Struct { name, .. } => Err(format!(
2086 "User-defined methods on {} require deoptimization",
2087 name
2088 )),
2089 Value::Iterator(state_rc) => match method_name {
2090 "next" => {
2091 let mut state = state_rc.borrow_mut();
2092 match &mut *state {
2093 IteratorState::Array { items, index } => {
2094 if *index < items.len() {
2095 let v = items[*index].clone();
2096 *index += 1;
2097 Ok(Value::some(v))
2098 } else {
2099 Ok(Value::none())
2100 }
2101 }
2102
2103 IteratorState::MapPairs { items, index } => {
2104 if *index < items.len() {
2105 let (k, v) = items[*index].clone();
2106 *index += 1;
2107 Ok(Value::some(Value::array(vec![k.to_value(), v])))
2108 } else {
2109 Ok(Value::none())
2110 }
2111 }
2112 }
2113 }
2114
2115 _ => Err(format!(
2116 "Iterator method '{}' not supported in JIT",
2117 method_name
2118 )),
2119 },
2120 Value::Enum {
2121 enum_name,
2122 variant,
2123 values,
2124 } if enum_name == "Option" => match method_name {
2125 "is_some" => Ok(Value::Bool(variant == "Some")),
2126 "is_none" => Ok(Value::Bool(variant == "None")),
2127 "unwrap" => {
2128 if variant == "Some" {
2129 if let Some(vals) = values {
2130 if vals.len() == 1 {
2131 Ok(vals[0].clone())
2132 } else {
2133 Err("Option::Some should have exactly 1 value".to_string())
2134 }
2135 } else {
2136 Err("Option::Some should have a value".to_string())
2137 }
2138 } else {
2139 Err("Called unwrap() on Option::None".to_string())
2140 }
2141 }
2142
2143 _ => Err(format!(
2144 "Option method '{}' not supported in JIT",
2145 method_name
2146 )),
2147 },
2148 Value::Array(arr) => match method_name {
2149 "len" => Ok(Value::Int(int_from_usize(arr.borrow().len()))),
2150 "push" => {
2151 let value = args
2152 .get(0)
2153 .cloned()
2154 .ok_or_else(|| "Array:push requires a value argument".to_string())?;
2155 arr.borrow_mut().push(value);
2156 Ok(Value::Nil)
2157 }
2158 "pop" => {
2159 let popped = arr.borrow_mut().pop();
2160 Ok(popped.map(Value::some).unwrap_or_else(Value::none))
2161 }
2162 "first" => {
2163 let borrowed = arr.borrow();
2164 Ok(borrowed
2165 .first()
2166 .cloned()
2167 .map(Value::some)
2168 .unwrap_or_else(Value::none))
2169 }
2170 "last" => {
2171 let borrowed = arr.borrow();
2172 Ok(borrowed
2173 .last()
2174 .cloned()
2175 .map(Value::some)
2176 .unwrap_or_else(Value::none))
2177 }
2178 "get" => {
2179 let index = args
2180 .get(0)
2181 .and_then(Value::as_int)
2182 .ok_or_else(|| "Array:get requires an integer index".to_string())?;
2183 let borrowed = arr.borrow();
2184 Ok(borrowed
2185 .get(index as usize)
2186 .cloned()
2187 .map(Value::some)
2188 .unwrap_or_else(Value::none))
2189 }
2190 "iter" => {
2191 let items = arr.borrow().clone();
2192 let iter = IteratorState::Array { items, index: 0 };
2193 Ok(Value::Iterator(Rc::new(RefCell::new(iter))))
2194 }
2195 _ => Err(format!(
2196 "Array method '{}' not supported in JIT",
2197 method_name
2198 )),
2199 },
2200 _ => Err(format!(
2201 "Method '{}' not supported in JIT (deoptimizing)",
2202 method_name
2203 )),
2204 }
2205}
2206
2207#[no_mangle]
2208pub unsafe extern "C" fn jit_get_field_safe(
2209 object_ptr: *const Value,
2210 field_name_ptr: *const u8,
2211 field_name_len: usize,
2212 out: *mut Value,
2213) -> u8 {
2214 if object_ptr.is_null() || field_name_ptr.is_null() || out.is_null() {
2215 return 0;
2216 }
2217
2218 let field_name_slice = slice::from_raw_parts(field_name_ptr, field_name_len);
2219 let field_name = match str::from_utf8(field_name_slice) {
2220 Ok(s) => s,
2221 Err(_) => return 0,
2222 };
2223 let object = &*object_ptr;
2224 let field_value = match object {
2225 Value::Struct { layout, fields, .. } => match layout.index_of_str(field_name) {
2226 Some(idx) => match fields.borrow().get(idx) {
2227 Some(val) => val.clone(),
2228 None => return 0,
2229 },
2230 None => return 0,
2231 },
2232 _ => return 0,
2233 };
2234 ptr::write(out, field_value);
2235 1
2236}
2237
2238#[no_mangle]
2239pub unsafe extern "C" fn jit_set_field_safe(
2240 object_ptr: *const Value,
2241 field_name_ptr: *const u8,
2242 field_name_len: usize,
2243 value_ptr: *const Value,
2244) -> u8 {
2245 if object_ptr.is_null() || field_name_ptr.is_null() || value_ptr.is_null() {
2246 return 0;
2247 }
2248
2249 let field_name_slice = slice::from_raw_parts(field_name_ptr, field_name_len);
2250 let field_name = match str::from_utf8(field_name_slice) {
2251 Ok(s) => s,
2252 Err(_) => return 0,
2253 };
2254 let object = &*object_ptr;
2255 let value = (&*value_ptr).clone();
2256 match object {
2257 Value::Struct { .. } => match object.struct_set_field(field_name, value) {
2258 Ok(()) => 1,
2259 Err(_) => 0,
2260 },
2261 Value::Map(map) => {
2262 use crate::bytecode::ValueKey;
2263 let key = ValueKey::String(Rc::new(field_name.to_string()));
2264 map.borrow_mut().insert(key, value);
2265 1
2266 }
2267
2268 _ => 0,
2269 }
2270}
2271
2272#[no_mangle]
2273pub unsafe extern "C" fn jit_get_field_indexed_safe(
2274 object_ptr: *const Value,
2275 field_index: usize,
2276 out: *mut Value,
2277) -> u8 {
2278 if object_ptr.is_null() || out.is_null() {
2279 return 0;
2280 }
2281
2282 let object = &*object_ptr;
2283 match object.struct_get_field_indexed(field_index) {
2284 Some(value) => {
2285 ptr::write(out, value);
2286 1
2287 }
2288
2289 None => 0,
2290 }
2291}
2292
2293#[no_mangle]
2294pub unsafe extern "C" fn jit_set_field_indexed_safe(
2295 object_ptr: *const Value,
2296 field_index: usize,
2297 value_ptr: *const Value,
2298) -> u8 {
2299 if object_ptr.is_null() || value_ptr.is_null() {
2300 return 0;
2301 }
2302
2303 let object = &*object_ptr;
2304 let value = (&*value_ptr).clone();
2305 match object.struct_set_field_indexed(field_index, value) {
2306 Ok(()) => 1,
2307 Err(_) => 0,
2308 }
2309}
2310
2311#[no_mangle]
2312pub unsafe extern "C" fn jit_get_field_indexed_int_fast(
2313 object_ptr: *const Value,
2314 field_index: usize,
2315 out: *mut Value,
2316) -> u8 {
2317 if object_ptr.is_null() || out.is_null() {
2318 return 0;
2319 }
2320
2321 let object = &*object_ptr;
2322 let out_ref = &mut *out;
2323 match object {
2324 Value::Struct { layout, fields, .. } => {
2325 if layout.is_weak(field_index) {
2326 return 0;
2327 }
2328
2329 if let Ok(borrowed) = fields.try_borrow() {
2330 if let Some(Value::Int(val)) = borrowed.get(field_index) {
2331 *out_ref = Value::Int(*val);
2332 return 1;
2333 }
2334 }
2335
2336 0
2337 }
2338
2339 _ => 0,
2340 }
2341}
2342
2343#[no_mangle]
2344pub unsafe extern "C" fn jit_set_field_indexed_int_fast(
2345 object_ptr: *const Value,
2346 field_index: usize,
2347 value_ptr: *const Value,
2348) -> u8 {
2349 if object_ptr.is_null() || value_ptr.is_null() {
2350 return 0;
2351 }
2352
2353 let object = &*object_ptr;
2354 let value = &*value_ptr;
2355 let new_value = match value {
2356 Value::Int(v) => *v,
2357 _ => return 0,
2358 };
2359 match object {
2360 Value::Struct { layout, fields, .. } => {
2361 if layout.is_weak(field_index) {
2362 return 0;
2363 }
2364
2365 if let Ok(mut borrowed) = fields.try_borrow_mut() {
2366 if field_index < borrowed.len() {
2367 borrowed[field_index] = Value::Int(new_value);
2368 return 1;
2369 }
2370 }
2371
2372 0
2373 }
2374
2375 _ => 0,
2376 }
2377}
2378
2379#[no_mangle]
2380pub unsafe extern "C" fn jit_new_struct_safe(
2381 vm_ptr: *mut VM,
2382 struct_name_ptr: *const u8,
2383 struct_name_len: usize,
2384 field_names_ptr: *const *const u8,
2385 field_name_lens_ptr: *const usize,
2386 field_values_ptr: *const Value,
2387 field_count: usize,
2388 out: *mut Value,
2389) -> u8 {
2390 if struct_name_ptr.is_null() || out.is_null() || vm_ptr.is_null() {
2391 jit::log(|| "jit_new_struct_safe: null pointer input".to_string());
2392 return 0;
2393 }
2394
2395 if field_count > 0
2396 && (field_names_ptr.is_null()
2397 || field_name_lens_ptr.is_null()
2398 || field_values_ptr.is_null())
2399 {
2400 return 0;
2401 }
2402
2403 let struct_name_slice = slice::from_raw_parts(struct_name_ptr, struct_name_len);
2404 let struct_name = match str::from_utf8(struct_name_slice) {
2405 Ok(s) => s.to_string(),
2406 Err(_) => return 0,
2407 };
2408 let mut fields = Vec::with_capacity(field_count);
2409 for i in 0..field_count {
2410 let field_name_ptr = *field_names_ptr.add(i);
2411 let field_name_len = *field_name_lens_ptr.add(i);
2412 let field_name_slice = slice::from_raw_parts(field_name_ptr, field_name_len);
2413 let field_name = match str::from_utf8(field_name_slice) {
2414 Ok(s) => Rc::new(s.to_string()),
2415 Err(_) => return 0,
2416 };
2417 let field_value_ptr = field_values_ptr.add(i);
2418 let field_value = (&*field_value_ptr).clone();
2419 fields.push((field_name, field_value));
2420 }
2421
2422 let vm = &mut *vm_ptr;
2423 let struct_value = match vm.instantiate_struct(&struct_name, fields) {
2424 Ok(value) => value,
2425 Err(err) => {
2426 jit::log(|| {
2427 format!(
2428 "jit_new_struct_safe: failed to instantiate '{}': {}",
2429 struct_name, err
2430 )
2431 });
2432 return 0;
2433 }
2434 };
2435 ptr::write(out, struct_value);
2436 1
2437}
2438
2439#[no_mangle]
2440pub unsafe extern "C" fn jit_move_safe(src_ptr: *const Value, dest_ptr: *mut Value) -> u8 {
2441 if src_ptr.is_null() || dest_ptr.is_null() {
2442 return 0;
2443 }
2444
2445 let src_value = &*src_ptr;
2446 let cloned_value = src_value.clone();
2447 ptr::write(dest_ptr, cloned_value);
2448 1
2449}