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")]
1254#[no_mangle]
1255pub unsafe extern "C" fn jit_concat_safe(
1256 left_value_ptr: *const Value,
1257 right_value_ptr: *const Value,
1258 out: *mut Value,
1259) -> u8 {
1260 if left_value_ptr.is_null() || right_value_ptr.is_null() || out.is_null() {
1261 return 0;
1262 }
1263
1264 let left = &*left_value_ptr;
1265 let right = &*right_value_ptr;
1266 const NO_VM_ERROR: &str = "task API requires a running VM";
1267 let left_str = match VM::with_current(|vm| {
1268 let left_copy = left.clone();
1269 vm.value_to_string_for_concat(&left_copy)
1270 .map_err(|err| err.to_string())
1271 }) {
1272 Ok(rc) => rc,
1273 Err(err) if err == NO_VM_ERROR => Rc::new(left.to_string()),
1274 Err(_) => return 0,
1275 };
1276 let right_str = match VM::with_current(|vm| {
1277 let right_copy = right.clone();
1278 vm.value_to_string_for_concat(&right_copy)
1279 .map_err(|err| err.to_string())
1280 }) {
1281 Ok(rc) => rc,
1282 Err(err) if err == NO_VM_ERROR => Rc::new(right.to_string()),
1283 Err(_) => return 0,
1284 };
1285 let mut combined = String::with_capacity(left_str.len() + right_str.len());
1286 combined.push_str(left_str.as_ref());
1287 combined.push_str(right_str.as_ref());
1288 let result = Value::string(combined);
1289 ptr::write(out, result);
1290 1
1291}
1292
1293#[no_mangle]
1294pub unsafe extern "C" fn jit_guard_native_function(
1295 value_ptr: *const Value,
1296 expected_fn_ptr: *const (),
1297 register_index: u8,
1298) -> u8 {
1299 if value_ptr.is_null() || expected_fn_ptr.is_null() {
1300 jit::log(|| "jit_guard_native_function: null pointer input".to_string());
1301 return 0;
1302 }
1303
1304 match &*value_ptr {
1305 Value::NativeFunction(func) => {
1306 let actual = Rc::as_ptr(func) as *const ();
1307 if actual == expected_fn_ptr {
1308 1
1309 } else {
1310 jit::log(|| {
1311 format!(
1312 "jit_guard_native_function: pointer mismatch (reg {}) actual={:p} expected={:p}",
1313 register_index, actual, expected_fn_ptr
1314 )
1315 });
1316 0
1317 }
1318 }
1319
1320 other => {
1321 jit::log(|| {
1322 format!(
1323 "jit_guard_native_function: value not native in reg {} ({:?})",
1324 register_index,
1325 other.tag()
1326 )
1327 });
1328 0
1329 }
1330 }
1331}
1332
1333#[no_mangle]
1334pub unsafe extern "C" fn jit_call_native_safe(
1335 vm_ptr: *mut VM,
1336 callee_ptr: *const Value,
1337 expected_fn_ptr: *const (),
1338 args_ptr: *const Value,
1339 arg_count: u8,
1340 out: *mut Value,
1341) -> u8 {
1342 if vm_ptr.is_null() || callee_ptr.is_null() || expected_fn_ptr.is_null() || out.is_null() {
1343 jit::log(|| "jit_call_native_safe: null argument".to_string());
1344 return 0;
1345 }
1346
1347 let callee = &*callee_ptr;
1348 let native_fn = match callee {
1349 Value::NativeFunction(func) => func.clone(),
1350 other => {
1351 jit::log(|| {
1352 format!(
1353 "jit_call_native_safe: callee not native ({:?})",
1354 other.tag()
1355 )
1356 });
1357 return 0;
1358 }
1359 };
1360
1361 if Rc::as_ptr(&native_fn) as *const () != expected_fn_ptr {
1362 jit::log(|| {
1363 format!(
1364 "jit_call_native_safe: pointer mismatch actual={:p} expected={:p}",
1365 Rc::as_ptr(&native_fn),
1366 expected_fn_ptr
1367 )
1368 });
1369 return 0;
1370 }
1371
1372 let mut args = Vec::with_capacity(arg_count as usize);
1373 if arg_count > 0 {
1374 if args_ptr.is_null() {
1375 jit::log(|| "jit_call_native_safe: args_ptr null with non-zero arg_count".to_string());
1376 return 0;
1377 }
1378
1379 for i in 0..(arg_count as usize) {
1380 let arg = &*args_ptr.add(i);
1381 args.push(arg.clone());
1382 }
1383 }
1384
1385 push_vm_ptr(vm_ptr);
1386 let outcome = native_fn(&args);
1387 pop_vm_ptr();
1388
1389 let outcome = match outcome {
1390 Ok(result) => result,
1391 Err(err) => {
1392 jit::log(|| format!("jit_call_native_safe: native returned error: {}", err));
1393 return 0;
1394 }
1395 };
1396
1397 match outcome {
1398 NativeCallResult::Return(value) => {
1399 ptr::write(out, value);
1400 1
1401 }
1402
1403 NativeCallResult::Yield(_) => {
1404 jit::log(|| "jit_call_native_safe: native attempted to yield".to_string());
1405 0
1406 }
1407
1408 NativeCallResult::Stop(_) => {
1409 jit::log(|| "jit_call_native_safe: native attempted to stop".to_string());
1410 0
1411 }
1412 }
1413}
1414
1415#[no_mangle]
1416pub unsafe extern "C" fn jit_call_method_safe(
1417 object_ptr: *const Value,
1418 method_name_ptr: *const u8,
1419 method_name_len: usize,
1420 args_ptr: *const Value,
1421 arg_count: u8,
1422 out: *mut Value,
1423) -> u8 {
1424 if object_ptr.is_null() || method_name_ptr.is_null() || out.is_null() {
1425 return 0;
1426 }
1427
1428 if arg_count > 0 && args_ptr.is_null() {
1429 return 0;
1430 }
1431
1432 let method_name_slice = slice::from_raw_parts(method_name_ptr, method_name_len);
1433 let method_name = match str::from_utf8(method_name_slice) {
1434 Ok(s) => s,
1435 Err(_) => return 0,
1436 };
1437 let object = &*object_ptr;
1438 if matches!(object, Value::Struct { .. }) {
1439 return 0;
1440 }
1441
1442 let mut args = Vec::with_capacity(arg_count as usize);
1443 for i in 0..arg_count {
1444 let arg_ptr = args_ptr.add(i as usize);
1445 args.push((&*arg_ptr).clone());
1446 }
1447
1448 let result = match call_builtin_method_simple(object, method_name, args) {
1449 Ok(val) => val,
1450 Err(_) => return 0,
1451 };
1452 ptr::write(out, result);
1453 1
1454}
1455
1456fn call_builtin_method_simple(
1457 object: &Value,
1458 method_name: &str,
1459 args: Vec<Value>,
1460) -> Result<Value, String> {
1461 match object {
1462 Value::Struct { name, .. } => Err(format!(
1463 "User-defined methods on {} require deoptimization",
1464 name
1465 )),
1466 Value::Iterator(state_rc) => match method_name {
1467 "next" => {
1468 let mut state = state_rc.borrow_mut();
1469 match &mut *state {
1470 IteratorState::Array { items, index } => {
1471 if *index < items.len() {
1472 let v = items[*index].clone();
1473 *index += 1;
1474 Ok(Value::some(v))
1475 } else {
1476 Ok(Value::none())
1477 }
1478 }
1479
1480 IteratorState::MapPairs { items, index } => {
1481 if *index < items.len() {
1482 let (k, v) = items[*index].clone();
1483 *index += 1;
1484 Ok(Value::some(Value::array(vec![k.to_value(), v])))
1485 } else {
1486 Ok(Value::none())
1487 }
1488 }
1489 }
1490 }
1491
1492 _ => Err(format!(
1493 "Iterator method '{}' not supported in JIT",
1494 method_name
1495 )),
1496 },
1497 Value::Enum {
1498 enum_name,
1499 variant,
1500 values,
1501 } if enum_name == "Option" => match method_name {
1502 "unwrap" => {
1503 if variant == "Some" {
1504 if let Some(vals) = values {
1505 if vals.len() == 1 {
1506 Ok(vals[0].clone())
1507 } else {
1508 Err("Option::Some should have exactly 1 value".to_string())
1509 }
1510 } else {
1511 Err("Option::Some should have a value".to_string())
1512 }
1513 } else {
1514 Err("Called unwrap() on Option::None".to_string())
1515 }
1516 }
1517
1518 _ => Err(format!(
1519 "Option method '{}' not supported in JIT",
1520 method_name
1521 )),
1522 },
1523 Value::Array(arr) => match method_name {
1524 "len" => Ok(Value::Int(int_from_usize(arr.borrow().len()))),
1525 "push" => {
1526 let value = args
1527 .get(0)
1528 .cloned()
1529 .ok_or_else(|| "Array:push requires a value argument".to_string())?;
1530 arr.borrow_mut().push(value);
1531 Ok(Value::Nil)
1532 }
1533 "pop" => {
1534 let popped = arr.borrow_mut().pop();
1535 Ok(popped.map(Value::some).unwrap_or_else(Value::none))
1536 }
1537 "first" => {
1538 let borrowed = arr.borrow();
1539 Ok(borrowed
1540 .first()
1541 .cloned()
1542 .map(Value::some)
1543 .unwrap_or_else(Value::none))
1544 }
1545 "last" => {
1546 let borrowed = arr.borrow();
1547 Ok(borrowed
1548 .last()
1549 .cloned()
1550 .map(Value::some)
1551 .unwrap_or_else(Value::none))
1552 }
1553 "get" => {
1554 let index = args
1555 .get(0)
1556 .and_then(Value::as_int)
1557 .ok_or_else(|| "Array:get requires an integer index".to_string())?;
1558 let borrowed = arr.borrow();
1559 Ok(borrowed
1560 .get(index as usize)
1561 .cloned()
1562 .map(Value::some)
1563 .unwrap_or_else(Value::none))
1564 }
1565 "iter" => {
1566 let items = arr.borrow().clone();
1567 let iter = IteratorState::Array { items, index: 0 };
1568 Ok(Value::Iterator(Rc::new(RefCell::new(iter))))
1569 }
1570 _ => Err(format!(
1571 "Array method '{}' not supported in JIT",
1572 method_name
1573 )),
1574 },
1575 _ => Err(format!(
1576 "Method '{}' not supported in JIT (deoptimizing)",
1577 method_name
1578 )),
1579 }
1580}
1581
1582#[no_mangle]
1583pub unsafe extern "C" fn jit_get_field_safe(
1584 object_ptr: *const Value,
1585 field_name_ptr: *const u8,
1586 field_name_len: usize,
1587 out: *mut Value,
1588) -> u8 {
1589 if object_ptr.is_null() || field_name_ptr.is_null() || out.is_null() {
1590 return 0;
1591 }
1592
1593 let field_name_slice = slice::from_raw_parts(field_name_ptr, field_name_len);
1594 let field_name = match str::from_utf8(field_name_slice) {
1595 Ok(s) => s,
1596 Err(_) => return 0,
1597 };
1598 let object = &*object_ptr;
1599 let field_value = match object {
1600 Value::Struct { layout, fields, .. } => match layout.index_of_str(field_name) {
1601 Some(idx) => match fields.borrow().get(idx) {
1602 Some(val) => val.clone(),
1603 None => return 0,
1604 },
1605 None => return 0,
1606 },
1607 _ => return 0,
1608 };
1609 ptr::write(out, field_value);
1610 1
1611}
1612
1613#[no_mangle]
1614pub unsafe extern "C" fn jit_set_field_safe(
1615 object_ptr: *const Value,
1616 field_name_ptr: *const u8,
1617 field_name_len: usize,
1618 value_ptr: *const Value,
1619) -> u8 {
1620 if object_ptr.is_null() || field_name_ptr.is_null() || value_ptr.is_null() {
1621 return 0;
1622 }
1623
1624 let field_name_slice = slice::from_raw_parts(field_name_ptr, field_name_len);
1625 let field_name = match str::from_utf8(field_name_slice) {
1626 Ok(s) => s,
1627 Err(_) => return 0,
1628 };
1629 let object = &*object_ptr;
1630 let value = (&*value_ptr).clone();
1631 match object {
1632 Value::Struct { .. } => match object.struct_set_field(field_name, value) {
1633 Ok(()) => 1,
1634 Err(_) => 0,
1635 },
1636 Value::Map(map) => {
1637 use crate::bytecode::ValueKey;
1638 let key = ValueKey::String(Rc::new(field_name.to_string()));
1639 map.borrow_mut().insert(key, value);
1640 1
1641 }
1642
1643 _ => 0,
1644 }
1645}
1646
1647#[no_mangle]
1648pub unsafe extern "C" fn jit_get_field_indexed_safe(
1649 object_ptr: *const Value,
1650 field_index: usize,
1651 out: *mut Value,
1652) -> u8 {
1653 if object_ptr.is_null() || out.is_null() {
1654 return 0;
1655 }
1656
1657 let object = &*object_ptr;
1658 match object.struct_get_field_indexed(field_index) {
1659 Some(value) => {
1660 ptr::write(out, value);
1661 1
1662 }
1663
1664 None => 0,
1665 }
1666}
1667
1668#[no_mangle]
1669pub unsafe extern "C" fn jit_set_field_indexed_safe(
1670 object_ptr: *const Value,
1671 field_index: usize,
1672 value_ptr: *const Value,
1673) -> u8 {
1674 if object_ptr.is_null() || value_ptr.is_null() {
1675 return 0;
1676 }
1677
1678 let object = &*object_ptr;
1679 let value = (&*value_ptr).clone();
1680 match object.struct_set_field_indexed(field_index, value) {
1681 Ok(()) => 1,
1682 Err(_) => 0,
1683 }
1684}
1685
1686#[no_mangle]
1687pub unsafe extern "C" fn jit_get_field_indexed_int_fast(
1688 object_ptr: *const Value,
1689 field_index: usize,
1690 out: *mut Value,
1691) -> u8 {
1692 if object_ptr.is_null() || out.is_null() {
1693 return 0;
1694 }
1695
1696 let object = &*object_ptr;
1697 let out_ref = &mut *out;
1698 match object {
1699 Value::Struct { layout, fields, .. } => {
1700 if layout.is_weak(field_index) {
1701 return 0;
1702 }
1703
1704 if let Ok(borrowed) = fields.try_borrow() {
1705 if let Some(Value::Int(val)) = borrowed.get(field_index) {
1706 *out_ref = Value::Int(*val);
1707 return 1;
1708 }
1709 }
1710
1711 0
1712 }
1713
1714 _ => 0,
1715 }
1716}
1717
1718#[no_mangle]
1719pub unsafe extern "C" fn jit_set_field_indexed_int_fast(
1720 object_ptr: *const Value,
1721 field_index: usize,
1722 value_ptr: *const Value,
1723) -> u8 {
1724 if object_ptr.is_null() || value_ptr.is_null() {
1725 return 0;
1726 }
1727
1728 let object = &*object_ptr;
1729 let value = &*value_ptr;
1730 let new_value = match value {
1731 Value::Int(v) => *v,
1732 _ => return 0,
1733 };
1734 match object {
1735 Value::Struct { layout, fields, .. } => {
1736 if layout.is_weak(field_index) {
1737 return 0;
1738 }
1739
1740 if let Ok(mut borrowed) = fields.try_borrow_mut() {
1741 if field_index < borrowed.len() {
1742 borrowed[field_index] = Value::Int(new_value);
1743 return 1;
1744 }
1745 }
1746
1747 0
1748 }
1749
1750 _ => 0,
1751 }
1752}
1753
1754#[no_mangle]
1755pub unsafe extern "C" fn jit_new_struct_safe(
1756 struct_name_ptr: *const u8,
1757 struct_name_len: usize,
1758 field_names_ptr: *const *const u8,
1759 field_name_lens_ptr: *const usize,
1760 field_values_ptr: *const Value,
1761 field_count: usize,
1762 out: *mut Value,
1763) -> u8 {
1764 if struct_name_ptr.is_null() || out.is_null() {
1765 return 0;
1766 }
1767
1768 if field_count > 0
1769 && (field_names_ptr.is_null()
1770 || field_name_lens_ptr.is_null()
1771 || field_values_ptr.is_null())
1772 {
1773 return 0;
1774 }
1775
1776 let struct_name_slice = slice::from_raw_parts(struct_name_ptr, struct_name_len);
1777 let struct_name = match str::from_utf8(struct_name_slice) {
1778 Ok(s) => s.to_string(),
1779 Err(_) => return 0,
1780 };
1781 let mut fields = Vec::with_capacity(field_count);
1782 for i in 0..field_count {
1783 let field_name_ptr = *field_names_ptr.add(i);
1784 let field_name_len = *field_name_lens_ptr.add(i);
1785 let field_name_slice = slice::from_raw_parts(field_name_ptr, field_name_len);
1786 let field_name = match str::from_utf8(field_name_slice) {
1787 Ok(s) => Rc::new(s.to_string()),
1788 Err(_) => return 0,
1789 };
1790 let field_value_ptr = field_values_ptr.add(i);
1791 let field_value = (&*field_value_ptr).clone();
1792 fields.push((field_name, field_value));
1793 }
1794
1795 let struct_value = match crate::vm::VM::with_current(move |vm| {
1796 vm.instantiate_struct(&struct_name, fields)
1797 .map_err(|err| err.to_string())
1798 }) {
1799 Ok(value) => value,
1800 Err(_) => return 0,
1801 };
1802 ptr::write(out, struct_value);
1803 1
1804}
1805
1806#[no_mangle]
1807pub unsafe extern "C" fn jit_move_safe(src_ptr: *const Value, dest_ptr: *mut Value) -> u8 {
1808 if src_ptr.is_null() || dest_ptr.is_null() {
1809 return 0;
1810 }
1811
1812 let src_value = &*src_ptr;
1813 let cloned_value = src_value.clone();
1814 ptr::write(dest_ptr, cloned_value);
1815 1
1816}