1use crate::jit;
2use crate::vm::{pop_vm_ptr, push_vm_ptr, VM};
3use std::cell::RefCell;
4use std::collections::HashMap;
5use std::fmt;
6use std::hash::{Hash, Hasher};
7use std::rc::{Rc, Weak};
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
9pub struct TaskHandle(pub u64);
10impl TaskHandle {
11 pub fn id(&self) -> u64 {
12 self.0
13 }
14}
15
16#[derive(Clone, Debug)]
17pub enum ValueKey {
18 Int(i64),
19 Float(f64),
20 String(Rc<String>),
21 Bool(bool),
22}
23
24impl ValueKey {
25 pub fn from_value(value: &Value) -> Option<Self> {
26 match value {
27 Value::Int(i) => Some(ValueKey::Int(*i)),
28 Value::Float(f) => Some(ValueKey::Float(*f)),
29 Value::String(s) => Some(ValueKey::String(s.clone())),
30 Value::Bool(b) => Some(ValueKey::Bool(*b)),
31 _ => None,
32 }
33 }
34
35 pub fn to_value(&self) -> Value {
36 match self {
37 ValueKey::Int(i) => Value::Int(*i),
38 ValueKey::Float(f) => Value::Float(*f),
39 ValueKey::String(s) => Value::String(s.clone()),
40 ValueKey::Bool(b) => Value::Bool(*b),
41 }
42 }
43}
44
45impl PartialEq for ValueKey {
46 fn eq(&self, other: &Self) -> bool {
47 match (self, other) {
48 (ValueKey::Int(a), ValueKey::Int(b)) => a == b,
49 (ValueKey::Float(a), ValueKey::Float(b)) => {
50 if a.is_nan() && b.is_nan() {
51 true
52 } else {
53 a == b
54 }
55 }
56
57 (ValueKey::String(a), ValueKey::String(b)) => a == b,
58 (ValueKey::Bool(a), ValueKey::Bool(b)) => a == b,
59 _ => false,
60 }
61 }
62}
63
64impl Eq for ValueKey {}
65impl Hash for ValueKey {
66 fn hash<H: Hasher>(&self, state: &mut H) {
67 match self {
68 ValueKey::Int(i) => {
69 0u8.hash(state);
70 i.hash(state);
71 }
72
73 ValueKey::Float(f) => {
74 1u8.hash(state);
75 if f.is_nan() {
76 u64::MAX.hash(state);
77 } else {
78 f.to_bits().hash(state);
79 }
80 }
81
82 ValueKey::String(s) => {
83 2u8.hash(state);
84 s.hash(state);
85 }
86
87 ValueKey::Bool(b) => {
88 3u8.hash(state);
89 b.hash(state);
90 }
91 }
92 }
93}
94
95impl fmt::Display for ValueKey {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 match self {
98 ValueKey::Int(i) => write!(f, "{}", i),
99 ValueKey::Float(fl) => write!(f, "{}", fl),
100 ValueKey::String(s) => write!(f, "{}", s),
101 ValueKey::Bool(b) => write!(f, "{}", b),
102 }
103 }
104}
105
106#[repr(u8)]
107#[derive(Debug, Clone, Copy, PartialEq, Eq)]
108pub enum ValueTag {
109 Nil,
110 Bool,
111 Int,
112 Float,
113 String,
114 Array,
115 Tuple,
116 Map,
117 Table,
118 Struct,
119 Enum,
120 Function,
121 NativeFunction,
122 Closure,
123 Iterator,
124 Task,
125}
126
127impl ValueTag {
128 #[inline]
129 pub const fn as_u8(self) -> u8 {
130 self as u8
131 }
132}
133
134#[derive(Debug, Clone, Copy, PartialEq, Eq)]
135pub enum FieldStorage {
136 Strong,
137 Weak,
138}
139
140#[derive(Debug)]
141pub struct StructLayout {
142 name: String,
143 field_names: Vec<Rc<String>>,
144 field_lookup_ptr: HashMap<usize, usize>,
145 field_lookup_str: HashMap<String, usize>,
146 field_storage: Vec<FieldStorage>,
147}
148
149impl StructLayout {
150 pub fn new(
151 name: String,
152 field_names: Vec<Rc<String>>,
153 field_storage: Vec<FieldStorage>,
154 ) -> Self {
155 debug_assert_eq!(
156 field_names.len(),
157 field_storage.len(),
158 "StructLayout::new expects field names and storage metadata to align"
159 );
160 let mut field_lookup_ptr = HashMap::with_capacity(field_names.len());
161 let mut field_lookup_str = HashMap::with_capacity(field_names.len());
162 for (index, field_name_rc) in field_names.iter().enumerate() {
163 let ptr = Rc::as_ptr(field_name_rc) as usize;
164 field_lookup_ptr.insert(ptr, index);
165 field_lookup_str.insert((**field_name_rc).clone(), index);
166 }
167
168 Self {
169 name,
170 field_names,
171 field_lookup_ptr,
172 field_lookup_str,
173 field_storage,
174 }
175 }
176
177 #[inline]
178 pub fn name(&self) -> &str {
179 &self.name
180 }
181
182 #[inline]
183 pub fn field_names(&self) -> &[Rc<String>] {
184 &self.field_names
185 }
186
187 #[inline]
188 pub fn index_of_rc(&self, key: &Rc<String>) -> Option<usize> {
189 let ptr = Rc::as_ptr(key) as usize;
190 self.field_lookup_ptr
191 .get(&ptr)
192 .copied()
193 .or_else(|| self.field_lookup_str.get(key.as_str()).copied())
194 }
195
196 #[inline]
197 pub fn index_of_str(&self, key: &str) -> Option<usize> {
198 self.field_lookup_str.get(key).copied()
199 }
200
201 #[inline]
202 pub fn field_storage(&self, index: usize) -> FieldStorage {
203 self.field_storage[index]
204 }
205
206 #[inline]
207 pub fn is_weak(&self, index: usize) -> bool {
208 matches!(self.field_storage(index), FieldStorage::Weak)
209 }
210
211 pub fn canonicalize_field_value(&self, index: usize, value: Value) -> Result<Value, String> {
212 match self.field_storage(index) {
213 FieldStorage::Strong => Ok(value),
214 FieldStorage::Weak => self.canonicalize_weak_field(index, value),
215 }
216 }
217
218 pub fn materialize_field_value(&self, index: usize, value: Value) -> Value {
219 match self.field_storage(index) {
220 FieldStorage::Strong => value,
221 FieldStorage::Weak => self.materialize_weak_field(value),
222 }
223 }
224
225 fn canonicalize_weak_field(&self, index: usize, value: Value) -> Result<Value, String> {
226 let field_name = self.field_names[index].as_str();
227 match value {
228 Value::Enum {
229 enum_name,
230 variant,
231 values,
232 } if enum_name == "Option" => {
233 if variant == "Some" {
234 if let Some(inner_values) = values {
235 if let Some(inner) = inner_values.get(0) {
236 let coerced = self.to_weak_struct(field_name, inner.clone())?;
237 Ok(Value::enum_variant("Option", "Some", vec![coerced]))
238 } else {
239 Ok(Value::enum_unit("Option", "None"))
240 }
241 } else {
242 Ok(Value::enum_unit("Option", "None"))
243 }
244 } else if variant == "None" {
245 Ok(Value::enum_unit("Option", "None"))
246 } else {
247 Err(format!(
248 "Struct '{}' field '{}' uses 'ref' and must store Option values; received variant '{}'",
249 self.name, field_name, variant
250 ))
251 }
252 }
253
254 Value::Nil => Ok(Value::enum_unit("Option", "None")),
255 other => {
256 let coerced = self.to_weak_struct(field_name, other)?;
257 Ok(Value::enum_variant("Option", "Some", vec![coerced]))
258 }
259 }
260 }
261
262 fn materialize_weak_field(&self, value: Value) -> Value {
263 match value {
264 Value::Enum {
265 enum_name,
266 variant,
267 values,
268 } if enum_name == "Option" => {
269 if variant == "Some" {
270 if let Some(inner_values) = values {
271 if let Some(inner) = inner_values.get(0) {
272 match inner {
273 Value::WeakStruct(ref weak) => {
274 if let Some(upgraded) = weak.upgrade() {
275 Value::enum_variant("Option", "Some", vec![upgraded])
276 } else {
277 Value::enum_unit("Option", "None")
278 }
279 }
280
281 _ => Value::enum_variant("Option", "Some", vec![inner.clone()]),
282 }
283 } else {
284 Value::enum_unit("Option", "None")
285 }
286 } else {
287 Value::enum_unit("Option", "None")
288 }
289 } else {
290 Value::enum_unit("Option", "None")
291 }
292 }
293
294 Value::Nil => Value::enum_unit("Option", "None"),
295 other => Value::enum_variant("Option", "Some", vec![other]),
296 }
297 }
298
299 fn to_weak_struct(&self, field_name: &str, value: Value) -> Result<Value, String> {
300 match value {
301 Value::Struct {
302 name,
303 layout,
304 fields,
305 } => Ok(Value::WeakStruct(WeakStructRef::new(name, layout, &fields))),
306 Value::WeakStruct(_) => Ok(value),
307 other => {
308 let ty = other.type_of();
309 Err(format!(
310 "Struct '{}' field '{}' expects a struct reference but received value of type '{:?}'",
311 self.name, field_name, ty
312 ))
313 }
314 }
315 }
316}
317
318#[repr(C, u8)]
319#[derive(Clone)]
320pub enum Value {
321 Nil,
322 Bool(bool),
323 Int(i64),
324 Float(f64),
325 String(Rc<String>),
326 Array(Rc<RefCell<Vec<Value>>>),
327 Tuple(Rc<Vec<Value>>),
328 Map(Rc<RefCell<HashMap<ValueKey, Value>>>),
329 Table(Rc<RefCell<HashMap<ValueKey, Value>>>),
330 Struct {
331 name: String,
332 layout: Rc<StructLayout>,
333 fields: Rc<RefCell<Vec<Value>>>,
334 },
335 WeakStruct(WeakStructRef),
336 Enum {
337 enum_name: String,
338 variant: String,
339 values: Option<Rc<Vec<Value>>>,
340 },
341 Function(usize),
342 NativeFunction(NativeFn),
343 Closure {
344 function_idx: usize,
345 upvalues: Rc<Vec<Upvalue>>,
346 },
347 Iterator(Rc<RefCell<IteratorState>>),
348 Task(TaskHandle),
349}
350
351#[derive(Debug, Clone)]
352pub struct WeakStructRef {
353 name: String,
354 layout: Rc<StructLayout>,
355 fields: Weak<RefCell<Vec<Value>>>,
356}
357
358impl WeakStructRef {
359 pub fn new(name: String, layout: Rc<StructLayout>, fields: &Rc<RefCell<Vec<Value>>>) -> Self {
360 Self {
361 name,
362 layout,
363 fields: Rc::downgrade(fields),
364 }
365 }
366
367 pub fn upgrade(&self) -> Option<Value> {
368 self.fields.upgrade().map(|fields| Value::Struct {
369 name: self.name.clone(),
370 layout: self.layout.clone(),
371 fields,
372 })
373 }
374
375 pub fn struct_name(&self) -> &str {
376 &self.name
377 }
378}
379
380#[derive(Clone)]
381pub enum IteratorState {
382 Array {
383 items: Vec<Value>,
384 index: usize,
385 },
386 MapPairs {
387 items: Vec<(ValueKey, Value)>,
388 index: usize,
389 },
390 TablePairs {
391 items: Vec<(ValueKey, Value)>,
392 index: usize,
393 },
394}
395
396#[derive(Clone)]
397pub struct Upvalue {
398 value: Rc<RefCell<Value>>,
399}
400
401impl Upvalue {
402 pub fn new(value: Value) -> Self {
403 Self {
404 value: Rc::new(RefCell::new(value)),
405 }
406 }
407
408 pub fn get(&self) -> Value {
409 self.value.borrow().clone()
410 }
411
412 pub fn set(&self, value: Value) {
413 *self.value.borrow_mut() = value;
414 }
415}
416
417impl fmt::Debug for Upvalue {
418 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419 write!(f, "Upvalue({:?})", self.value.borrow())
420 }
421}
422
423#[derive(Debug, Clone)]
424pub enum NativeCallResult {
425 Return(Value),
426 Yield(Value),
427 Stop(Value),
428}
429
430impl From<Value> for NativeCallResult {
431 fn from(value: Value) -> Self {
432 NativeCallResult::Return(value)
433 }
434}
435
436pub type NativeFn = Rc<dyn Fn(&[Value]) -> Result<NativeCallResult, String>>;
437#[derive(Debug, Clone, Copy, PartialEq, Eq)]
438pub enum ValueType {
439 Nil,
440 Bool,
441 Int,
442 Float,
443 String,
444 Array,
445 Tuple,
446 Map,
447 Table,
448 Struct,
449 Enum,
450 Function,
451 NativeFunction,
452 Closure,
453 Iterator,
454 Task,
455}
456
457impl Value {
458 #[inline]
459 pub fn tag(&self) -> ValueTag {
460 match self {
461 Value::Nil => ValueTag::Nil,
462 Value::Bool(_) => ValueTag::Bool,
463 Value::Int(_) => ValueTag::Int,
464 Value::Float(_) => ValueTag::Float,
465 Value::String(_) => ValueTag::String,
466 Value::Array(_) => ValueTag::Array,
467 Value::Tuple(_) => ValueTag::Tuple,
468 Value::Map(_) => ValueTag::Map,
469 Value::Table(_) => ValueTag::Table,
470 Value::Struct { .. } | Value::WeakStruct(_) => ValueTag::Struct,
471 Value::Enum { .. } => ValueTag::Enum,
472 Value::Function(_) => ValueTag::Function,
473 Value::NativeFunction(_) => ValueTag::NativeFunction,
474 Value::Closure { .. } => ValueTag::Closure,
475 Value::Iterator(_) => ValueTag::Iterator,
476 Value::Task(_) => ValueTag::Task,
477 }
478 }
479
480 pub fn type_of(&self) -> ValueType {
481 match self {
482 Value::Nil => ValueType::Nil,
483 Value::Bool(_) => ValueType::Bool,
484 Value::Int(_) => ValueType::Int,
485 Value::Float(_) => ValueType::Float,
486 Value::String(_) => ValueType::String,
487 Value::Array(_) => ValueType::Array,
488 Value::Tuple(_) => ValueType::Tuple,
489 Value::Map(_) => ValueType::Map,
490 Value::Table(_) => ValueType::Table,
491 Value::Struct { .. } | Value::WeakStruct(_) => ValueType::Struct,
492 Value::Enum { .. } => ValueType::Enum,
493 Value::Function(_) => ValueType::Function,
494 Value::NativeFunction(_) => ValueType::NativeFunction,
495 Value::Closure { .. } => ValueType::Closure,
496 Value::Iterator(_) => ValueType::Iterator,
497 Value::Task(_) => ValueType::Task,
498 }
499 }
500
501 pub fn is_truthy(&self) -> bool {
502 !matches!(self, Value::Nil | Value::Bool(false))
503 }
504
505 pub fn to_bool(&self) -> bool {
506 self.is_truthy()
507 }
508
509 pub fn as_int(&self) -> Option<i64> {
510 match self {
511 Value::Int(i) => Some(*i),
512 Value::Float(f) => Some(*f as i64),
513 _ => None,
514 }
515 }
516
517 pub fn as_float(&self) -> Option<f64> {
518 match self {
519 Value::Float(f) => Some(*f),
520 Value::Int(i) => Some(*i as f64),
521 _ => None,
522 }
523 }
524
525 pub fn as_string(&self) -> Option<&str> {
526 match self {
527 Value::String(s) => Some(s.as_str()),
528 _ => None,
529 }
530 }
531
532 pub fn as_string_rc(&self) -> Option<Rc<String>> {
533 match self {
534 Value::String(s) => Some(s.clone()),
535 _ => None,
536 }
537 }
538
539 pub fn as_task_handle(&self) -> Option<TaskHandle> {
540 match self {
541 Value::Task(handle) => Some(*handle),
542 _ => None,
543 }
544 }
545
546 pub fn as_array(&self) -> Option<Vec<Value>> {
547 match self {
548 Value::Array(arr) => Some(arr.borrow().clone()),
549 _ => None,
550 }
551 }
552
553 pub fn array_len(&self) -> Option<usize> {
554 match self {
555 Value::Array(arr) => Some(arr.borrow().len()),
556 _ => None,
557 }
558 }
559
560 pub fn array_get(&self, index: usize) -> Option<Value> {
561 match self {
562 Value::Array(arr) => arr.borrow().get(index).cloned(),
563 _ => None,
564 }
565 }
566
567 pub fn array_push(&self, value: Value) -> Result<(), String> {
568 match self {
569 Value::Array(arr) => {
570 arr.borrow_mut().push(value);
571 Ok(())
572 }
573
574 _ => Err("Cannot push to non-array".to_string()),
575 }
576 }
577
578 pub fn array_pop(&self) -> Result<Option<Value>, String> {
579 match self {
580 Value::Array(arr) => Ok(arr.borrow_mut().pop()),
581 _ => Err("Cannot pop from non-array".to_string()),
582 }
583 }
584
585 pub fn as_map(&self) -> Option<HashMap<ValueKey, Value>> {
586 match self {
587 Value::Map(map) => Some(map.borrow().clone()),
588 _ => None,
589 }
590 }
591
592 pub fn map_get(&self, key: &ValueKey) -> Option<Value> {
593 match self {
594 Value::Map(map) => map.borrow().get(key).cloned(),
595 _ => None,
596 }
597 }
598
599 pub fn map_set(&self, key: ValueKey, value: Value) -> Result<(), String> {
600 match self {
601 Value::Map(map) => {
602 map.borrow_mut().insert(key, value);
603 Ok(())
604 }
605
606 _ => Err("Cannot set key on non-map".to_string()),
607 }
608 }
609
610 pub fn map_has(&self, key: &ValueKey) -> Option<bool> {
611 match self {
612 Value::Map(map) => Some(map.borrow().contains_key(key)),
613 _ => None,
614 }
615 }
616
617 pub fn map_delete(&self, key: &ValueKey) -> Result<Option<Value>, String> {
618 match self {
619 Value::Map(map) => Ok(map.borrow_mut().remove(key)),
620 _ => Err("Cannot delete key from non-map".to_string()),
621 }
622 }
623
624 pub fn map_len(&self) -> Option<usize> {
625 match self {
626 Value::Map(map) => Some(map.borrow().len()),
627 _ => None,
628 }
629 }
630
631 pub fn as_table(&self) -> Option<HashMap<ValueKey, Value>> {
632 match self {
633 Value::Table(table) => Some(table.borrow().clone()),
634 _ => None,
635 }
636 }
637
638 pub fn table_get(&self, key: &ValueKey) -> Option<Value> {
639 match self {
640 Value::Table(table) => table.borrow().get(key).cloned(),
641 _ => None,
642 }
643 }
644
645 pub fn table_set(&self, key: ValueKey, value: Value) -> Result<(), String> {
646 match self {
647 Value::Table(table) => {
648 table.borrow_mut().insert(key, value);
649 Ok(())
650 }
651
652 _ => Err("Cannot set key on non-table".to_string()),
653 }
654 }
655
656 pub fn table_has(&self, key: &ValueKey) -> Option<bool> {
657 match self {
658 Value::Table(table) => Some(table.borrow().contains_key(key)),
659 _ => None,
660 }
661 }
662
663 pub fn table_delete(&self, key: &ValueKey) -> Result<Option<Value>, String> {
664 match self {
665 Value::Table(table) => Ok(table.borrow_mut().remove(key)),
666 _ => Err("Cannot delete key from non-table".to_string()),
667 }
668 }
669
670 pub fn table_len(&self) -> Option<usize> {
671 match self {
672 Value::Table(table) => Some(table.borrow().len()),
673 _ => None,
674 }
675 }
676
677 pub fn string(s: impl Into<String>) -> Self {
678 Value::String(Rc::new(s.into()))
679 }
680
681 pub fn array(values: Vec<Value>) -> Self {
682 Value::Array(Rc::new(RefCell::new(values)))
683 }
684
685 pub fn tuple(values: Vec<Value>) -> Self {
686 Value::Tuple(Rc::new(values))
687 }
688
689 pub fn tuple_len(&self) -> Option<usize> {
690 match self {
691 Value::Tuple(values) => Some(values.len()),
692 _ => None,
693 }
694 }
695
696 pub fn tuple_get(&self, index: usize) -> Option<Value> {
697 match self {
698 Value::Tuple(values) => values.get(index).cloned(),
699 _ => None,
700 }
701 }
702
703 pub fn map(entries: HashMap<ValueKey, Value>) -> Self {
704 Value::Map(Rc::new(RefCell::new(entries)))
705 }
706
707 pub fn table(entries: HashMap<ValueKey, Value>) -> Self {
708 Value::Table(Rc::new(RefCell::new(entries)))
709 }
710
711 pub fn task(handle: TaskHandle) -> Self {
712 Value::Task(handle)
713 }
714
715 pub fn struct_get_field_rc(&self, field: &Rc<String>) -> Option<Value> {
716 match self {
717 Value::Struct { layout, fields, .. } => layout
718 .index_of_rc(field)
719 .or_else(|| layout.index_of_str(field.as_str()))
720 .and_then(|idx| {
721 fields
722 .borrow()
723 .get(idx)
724 .cloned()
725 .map(|value| layout.materialize_field_value(idx, value))
726 }),
727 _ => None,
728 }
729 }
730
731 pub fn struct_get_field(&self, field: &str) -> Option<Value> {
732 match self {
733 Value::Struct { layout, fields, .. } => layout.index_of_str(field).and_then(|idx| {
734 fields
735 .borrow()
736 .get(idx)
737 .cloned()
738 .map(|value| layout.materialize_field_value(idx, value))
739 }),
740 _ => None,
741 }
742 }
743
744 pub fn struct_get_field_indexed(&self, index: usize) -> Option<Value> {
745 match self {
746 Value::Struct { layout, fields, .. } => fields
747 .borrow()
748 .get(index)
749 .cloned()
750 .map(|value| layout.materialize_field_value(index, value)),
751 _ => None,
752 }
753 }
754
755 pub fn struct_set_field_rc(&self, field: &Rc<String>, value: Value) -> Result<(), String> {
756 match self {
757 Value::Struct { layout, .. } => {
758 if let Some(index) = layout
759 .index_of_rc(field)
760 .or_else(|| layout.index_of_str(field.as_str()))
761 {
762 self.struct_set_field_indexed(index, value)
763 } else {
764 Err(format!(
765 "Struct '{}' has no field '{}'",
766 layout.name(),
767 field.as_str()
768 ))
769 }
770 }
771
772 _ => Err("Attempted to set field on non-struct value".to_string()),
773 }
774 }
775
776 pub fn struct_set_field(&self, field: &str, value: Value) -> Result<(), String> {
777 match self {
778 Value::Struct { layout, .. } => {
779 if let Some(index) = layout.index_of_str(field) {
780 self.struct_set_field_indexed(index, value)
781 } else {
782 Err(format!(
783 "Struct '{}' has no field '{}'",
784 layout.name(),
785 field
786 ))
787 }
788 }
789
790 _ => Err("Attempted to set field on non-struct value".to_string()),
791 }
792 }
793
794 pub fn struct_set_field_indexed(&self, index: usize, value: Value) -> Result<(), String> {
795 match self {
796 Value::Struct {
797 name,
798 layout,
799 fields,
800 } => {
801 let mut borrowed = fields.borrow_mut();
802 if index < borrowed.len() {
803 let canonical = layout.canonicalize_field_value(index, value)?;
804 borrowed[index] = canonical;
805 Ok(())
806 } else {
807 Err(format!(
808 "Struct '{}' field index {} out of bounds (len {})",
809 name,
810 index,
811 borrowed.len()
812 ))
813 }
814 }
815
816 _ => Err("Attempted to set field on non-struct value".to_string()),
817 }
818 }
819
820 pub fn enum_unit(enum_name: impl Into<String>, variant: impl Into<String>) -> Self {
821 Value::Enum {
822 enum_name: enum_name.into(),
823 variant: variant.into(),
824 values: None,
825 }
826 }
827
828 pub fn enum_variant(
829 enum_name: impl Into<String>,
830 variant: impl Into<String>,
831 values: Vec<Value>,
832 ) -> Self {
833 Value::Enum {
834 enum_name: enum_name.into(),
835 variant: variant.into(),
836 values: Some(Rc::new(values)),
837 }
838 }
839
840 pub fn as_enum(&self) -> Option<(&str, &str, Option<&[Value]>)> {
841 match self {
842 Value::Enum {
843 enum_name,
844 variant,
845 values,
846 } => Some((
847 enum_name.as_str(),
848 variant.as_str(),
849 values.as_ref().map(|v| v.as_slice()),
850 )),
851 _ => None,
852 }
853 }
854
855 pub fn is_enum_variant(&self, enum_name: &str, variant: &str) -> bool {
856 match self {
857 Value::Enum {
858 enum_name: en,
859 variant: v,
860 ..
861 } => (enum_name.is_empty() || en == enum_name) && v == variant,
862 _ => false,
863 }
864 }
865
866 pub fn some(value: Value) -> Self {
867 Value::enum_variant("Option", "Some", vec![value])
868 }
869
870 pub fn none() -> Self {
871 Value::enum_unit("Option", "None")
872 }
873
874 pub fn ok(value: Value) -> Self {
875 Value::enum_variant("Result", "Ok", vec![value])
876 }
877
878 pub fn err(error: Value) -> Self {
879 Value::enum_variant("Result", "Err", vec![error])
880 }
881
882 pub fn to_string(&self) -> String {
883 format!("{}", self)
884 }
885}
886
887impl fmt::Debug for Value {
888 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
889 match self {
890 Value::Nil => write!(f, "Nil"),
891 Value::Bool(b) => write!(f, "Bool({})", b),
892 Value::Int(i) => write!(f, "Int({})", i),
893 Value::Float(fl) => write!(f, "Float({})", fl),
894 Value::String(s) => write!(f, "String({:?})", s),
895 Value::Array(arr) => write!(f, "Array({:?})", arr.borrow()),
896 Value::Tuple(values) => write!(f, "Tuple({:?})", values),
897 Value::Map(map) => write!(f, "Map({:?})", map.borrow()),
898 Value::Table(table) => write!(f, "Table({:?})", table.borrow()),
899 Value::Struct {
900 name,
901 layout,
902 fields,
903 } => {
904 let borrowed = fields.borrow();
905 let mut display_fields = Vec::with_capacity(borrowed.len());
906 for (idx, field_name) in layout.field_names().iter().enumerate() {
907 let value = borrowed.get(idx).cloned().unwrap_or(Value::Nil);
908 display_fields.push((field_name.as_str().to_string(), value));
909 }
910
911 write!(
912 f,
913 "Struct {{ name: {:?}, fields: {:?} }}",
914 name, display_fields
915 )
916 }
917
918 Value::WeakStruct(weak) => {
919 if let Some(upgraded) = weak.upgrade() {
920 write!(f, "WeakStruct({:?})", upgraded)
921 } else {
922 write!(f, "WeakStruct(<dangling>)")
923 }
924 }
925
926 Value::Enum {
927 enum_name,
928 variant,
929 values,
930 } => {
931 write!(
932 f,
933 "Enum {{ enum: {:?}, variant: {:?}, values: {:?} }}",
934 enum_name, variant, values
935 )
936 }
937
938 Value::Function(idx) => write!(f, "Function({})", idx),
939 Value::NativeFunction(_) => write!(f, "NativeFunction(<fn>)"),
940 Value::Closure {
941 function_idx,
942 upvalues,
943 } => {
944 write!(
945 f,
946 "Closure {{ function: {}, upvalues: {:?} }}",
947 function_idx, upvalues
948 )
949 }
950
951 Value::Iterator(_) => write!(f, "Iterator(<state>)"),
952 Value::Task(handle) => write!(f, "Task({})", handle.0),
953 }
954 }
955}
956
957impl fmt::Display for Value {
958 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
959 match self {
960 Value::Nil => write!(f, "nil"),
961 Value::Bool(b) => write!(f, "{}", b),
962 Value::Int(i) => write!(f, "{}", i),
963 Value::Float(fl) => write!(f, "{}", fl),
964 Value::String(s) => write!(f, "{}", s),
965 Value::Array(arr) => {
966 write!(f, "[")?;
967 let borrowed = arr.borrow();
968 for (i, val) in borrowed.iter().enumerate() {
969 if i > 0 {
970 write!(f, ", ")?;
971 }
972
973 write!(f, "{}", val)?;
974 }
975
976 write!(f, "]")
977 }
978
979 Value::Tuple(values) => {
980 write!(f, "(")?;
981 for (i, val) in values.iter().enumerate() {
982 if i > 0 {
983 write!(f, ", ")?;
984 }
985
986 write!(f, "{}", val)?;
987 }
988
989 write!(f, ")")
990 }
991
992 Value::Map(map) => {
993 write!(f, "{{")?;
994 let borrowed = map.borrow();
995 for (i, (k, v)) in borrowed.iter().enumerate() {
996 if i > 0 {
997 write!(f, ", ")?;
998 }
999
1000 write!(f, "{}: {}", k, v)?;
1001 }
1002
1003 write!(f, "}}")
1004 }
1005
1006 Value::Table(table) => {
1007 write!(f, "{{")?;
1008 let borrowed = table.borrow();
1009 for (i, (k, v)) in borrowed.iter().enumerate() {
1010 if i > 0 {
1011 write!(f, ", ")?;
1012 }
1013
1014 write!(f, "{}: {}", k, v)?;
1015 }
1016
1017 write!(f, "}}")
1018 }
1019
1020 Value::Struct {
1021 name,
1022 layout,
1023 fields,
1024 } => {
1025 let borrowed = fields.borrow();
1026 write!(f, "{} {{", name)?;
1027 for (i, field_name) in layout.field_names().iter().enumerate() {
1028 if i > 0 {
1029 write!(f, ", ")?;
1030 }
1031
1032 let value = borrowed.get(i).unwrap_or(&Value::Nil);
1033 write!(f, "{}: {}", field_name, value)?;
1034 }
1035
1036 write!(f, "}}")
1037 }
1038
1039 Value::WeakStruct(weak) => {
1040 if let Some(strong) = weak.upgrade() {
1041 strong.fmt(f)
1042 } else {
1043 write!(f, "nil")
1044 }
1045 }
1046
1047 Value::Enum {
1048 enum_name,
1049 variant,
1050 values,
1051 } => {
1052 write!(f, "{}.{}", enum_name, variant)?;
1053 if let Some(vals) = values {
1054 write!(f, "(")?;
1055 for (i, val) in vals.iter().enumerate() {
1056 if i > 0 {
1057 write!(f, ", ")?;
1058 }
1059
1060 write!(f, "{}", val)?;
1061 }
1062
1063 write!(f, ")")?;
1064 }
1065
1066 Ok(())
1067 }
1068
1069 Value::Function(idx) => write!(f, "<function@{}>", idx),
1070 Value::NativeFunction(_) => write!(f, "<native function>"),
1071 Value::Closure { function_idx, .. } => write!(f, "<closure@{}>", function_idx),
1072 Value::Iterator(_) => write!(f, "<iterator>"),
1073 Value::Task(handle) => write!(f, "<task {}>", handle.0),
1074 }
1075 }
1076}
1077
1078impl PartialEq for Value {
1079 fn eq(&self, other: &Self) -> bool {
1080 match (self, other) {
1081 (Value::Nil, Value::Nil) => true,
1082 (Value::Bool(a), Value::Bool(b)) => a == b,
1083 (Value::Int(a), Value::Int(b)) => a == b,
1084 (Value::Float(a), Value::Float(b)) => a == b,
1085 (Value::String(a), Value::String(b)) => a == b,
1086 (Value::Array(a), Value::Array(b)) => *a.borrow() == *b.borrow(),
1087 (Value::Tuple(a), Value::Tuple(b)) => *a == *b,
1088 (Value::Map(a), Value::Map(b)) => *a.borrow() == *b.borrow(),
1089 (Value::Table(a), Value::Table(b)) => *a.borrow() == *b.borrow(),
1090 (
1091 Value::Struct {
1092 name: n1,
1093 layout: l1,
1094 fields: f1,
1095 },
1096 Value::Struct {
1097 name: n2,
1098 layout: l2,
1099 fields: f2,
1100 },
1101 ) => {
1102 if n1 != n2 {
1103 return false;
1104 }
1105
1106 let borrowed_f1 = f1.borrow();
1107 let borrowed_f2 = f2.borrow();
1108 if borrowed_f1.len() != borrowed_f2.len() {
1109 return false;
1110 }
1111
1112 if Rc::ptr_eq(l1, l2) {
1113 return borrowed_f1
1114 .iter()
1115 .zip(borrowed_f2.iter())
1116 .all(|(a, b)| a == b);
1117 }
1118
1119 l1.field_names()
1120 .iter()
1121 .enumerate()
1122 .all(|(idx, field_name)| {
1123 if let Some(other_idx) = l2.index_of_rc(field_name) {
1124 borrowed_f1
1125 .get(idx)
1126 .zip(borrowed_f2.get(other_idx))
1127 .map(|(a, b)| a == b)
1128 .unwrap_or(false)
1129 } else {
1130 false
1131 }
1132 })
1133 }
1134
1135 (Value::WeakStruct(a), Value::WeakStruct(b)) => match (a.upgrade(), b.upgrade()) {
1136 (Some(left), Some(right)) => left == right,
1137 (None, None) => true,
1138 _ => false,
1139 },
1140 (Value::WeakStruct(a), other) => a
1141 .upgrade()
1142 .map(|upgraded| upgraded == *other)
1143 .unwrap_or(matches!(other, Value::Nil)),
1144 (value, Value::WeakStruct(b)) => b
1145 .upgrade()
1146 .map(|upgraded| *value == upgraded)
1147 .unwrap_or(matches!(value, Value::Nil)),
1148 (
1149 Value::Enum {
1150 enum_name: e1,
1151 variant: v1,
1152 values: vals1,
1153 },
1154 Value::Enum {
1155 enum_name: e2,
1156 variant: v2,
1157 values: vals2,
1158 },
1159 ) => e1 == e2 && v1 == v2 && vals1 == vals2,
1160 (Value::Function(a), Value::Function(b)) => a == b,
1161 (
1162 Value::Closure {
1163 function_idx: f1,
1164 upvalues: u1,
1165 },
1166 Value::Closure {
1167 function_idx: f2,
1168 upvalues: u2,
1169 },
1170 ) => f1 == f2 && Rc::ptr_eq(u1, u2),
1171 (Value::Iterator(_), Value::Iterator(_)) => false,
1172 (Value::Task(a), Value::Task(b)) => a == b,
1173 _ => false,
1174 }
1175 }
1176}
1177
1178#[no_mangle]
1179pub unsafe extern "C" fn jit_array_get_safe(
1180 array_value_ptr: *const Value,
1181 index: i64,
1182 out: *mut Value,
1183) -> u8 {
1184 if array_value_ptr.is_null() || out.is_null() {
1185 eprintln!("❌ jit_array_get_safe: null pointer detected!");
1186 return 0;
1187 }
1188
1189 let array_value = &*array_value_ptr;
1190 let arr = match array_value {
1191 Value::Array(arr) => arr,
1192 _ => {
1193 return 0;
1194 }
1195 };
1196 if index < 0 {
1197 return 0;
1198 }
1199
1200 let idx = index as usize;
1201 let borrowed = match arr.try_borrow() {
1202 Ok(b) => b,
1203 Err(_) => {
1204 return 0;
1205 }
1206 };
1207 if idx >= borrowed.len() {
1208 return 0;
1209 }
1210
1211 std::ptr::write(out, borrowed[idx].clone());
1212 1
1213}
1214
1215#[no_mangle]
1216pub unsafe extern "C" fn jit_array_len_safe(array_value_ptr: *const Value) -> i64 {
1217 if array_value_ptr.is_null() {
1218 return -1;
1219 }
1220
1221 let array_value = &*array_value_ptr;
1222 match array_value {
1223 Value::Array(arr) => match arr.try_borrow() {
1224 Ok(borrowed) => borrowed.len() as i64,
1225 Err(_) => -1,
1226 },
1227 _ => -1,
1228 }
1229}
1230
1231#[no_mangle]
1232pub unsafe extern "C" fn jit_concat_safe(
1233 left_value_ptr: *const Value,
1234 right_value_ptr: *const Value,
1235 out: *mut Value,
1236) -> u8 {
1237 if left_value_ptr.is_null() || right_value_ptr.is_null() || out.is_null() {
1238 return 0;
1239 }
1240
1241 let left = &*left_value_ptr;
1242 let right = &*right_value_ptr;
1243 const NO_VM_ERROR: &str = "task API requires a running VM";
1244 let left_str = match VM::with_current(|vm| {
1245 let left_copy = left.clone();
1246 vm.value_to_string_for_concat(&left_copy)
1247 .map_err(|err| err.to_string())
1248 }) {
1249 Ok(rc) => rc,
1250 Err(err) if err == NO_VM_ERROR => Rc::new(left.to_string()),
1251 Err(_) => return 0,
1252 };
1253 let right_str = match VM::with_current(|vm| {
1254 let right_copy = right.clone();
1255 vm.value_to_string_for_concat(&right_copy)
1256 .map_err(|err| err.to_string())
1257 }) {
1258 Ok(rc) => rc,
1259 Err(err) if err == NO_VM_ERROR => Rc::new(right.to_string()),
1260 Err(_) => return 0,
1261 };
1262 let mut combined = String::with_capacity(left_str.len() + right_str.len());
1263 combined.push_str(left_str.as_ref());
1264 combined.push_str(right_str.as_ref());
1265 let result = Value::string(combined);
1266 std::ptr::write(out, result);
1267 1
1268}
1269
1270#[no_mangle]
1271pub unsafe extern "C" fn jit_guard_native_function(
1272 value_ptr: *const Value,
1273 expected_fn_ptr: *const (),
1274 register_index: u8,
1275) -> u8 {
1276 if value_ptr.is_null() || expected_fn_ptr.is_null() {
1277 jit::log(|| "jit_guard_native_function: null pointer input".to_string());
1278 return 0;
1279 }
1280
1281 match &*value_ptr {
1282 Value::NativeFunction(func) => {
1283 let actual = Rc::as_ptr(func) as *const ();
1284 if actual == expected_fn_ptr {
1285 1
1286 } else {
1287 jit::log(|| {
1288 format!(
1289 "jit_guard_native_function: pointer mismatch (reg {}) actual={:p} expected={:p}",
1290 register_index, actual, expected_fn_ptr
1291 )
1292 });
1293 0
1294 }
1295 }
1296
1297 other => {
1298 jit::log(|| {
1299 format!(
1300 "jit_guard_native_function: value not native in reg {} ({:?})",
1301 register_index,
1302 other.tag()
1303 )
1304 });
1305 0
1306 }
1307 }
1308}
1309
1310#[no_mangle]
1311pub unsafe extern "C" fn jit_call_native_safe(
1312 vm_ptr: *mut VM,
1313 callee_ptr: *const Value,
1314 expected_fn_ptr: *const (),
1315 args_ptr: *const Value,
1316 arg_count: u8,
1317 out: *mut Value,
1318) -> u8 {
1319 if vm_ptr.is_null() || callee_ptr.is_null() || expected_fn_ptr.is_null() || out.is_null() {
1320 jit::log(|| "jit_call_native_safe: null argument".to_string());
1321 return 0;
1322 }
1323
1324 let callee = &*callee_ptr;
1325 let native_fn = match callee {
1326 Value::NativeFunction(func) => func.clone(),
1327 other => {
1328 jit::log(|| format!("jit_call_native_safe: callee not native ({:?})", other.tag()));
1329 return 0;
1330 }
1331 };
1332
1333 if Rc::as_ptr(&native_fn) as *const () != expected_fn_ptr {
1334 jit::log(|| {
1335 format!(
1336 "jit_call_native_safe: pointer mismatch actual={:p} expected={:p}",
1337 Rc::as_ptr(&native_fn),
1338 expected_fn_ptr
1339 )
1340 });
1341 return 0;
1342 }
1343
1344 let mut args = Vec::with_capacity(arg_count as usize);
1345 if arg_count > 0 {
1346 if args_ptr.is_null() {
1347 jit::log(|| "jit_call_native_safe: args_ptr null with non-zero arg_count".to_string());
1348 return 0;
1349 }
1350
1351 for i in 0..(arg_count as usize) {
1352 let arg = &*args_ptr.add(i);
1353 args.push(arg.clone());
1354 }
1355 }
1356
1357 push_vm_ptr(vm_ptr);
1358 let outcome = native_fn(&args);
1359 pop_vm_ptr();
1360
1361 let outcome = match outcome {
1362 Ok(result) => result,
1363 Err(err) => {
1364 jit::log(|| format!("jit_call_native_safe: native returned error: {}", err));
1365 return 0;
1366 }
1367 };
1368
1369 match outcome {
1370 NativeCallResult::Return(value) => {
1371 std::ptr::write(out, value);
1372 1
1373 }
1374
1375 NativeCallResult::Yield(_) => {
1376 jit::log(|| "jit_call_native_safe: native attempted to yield".to_string());
1377 0
1378 }
1379
1380 NativeCallResult::Stop(_) => {
1381 jit::log(|| "jit_call_native_safe: native attempted to stop".to_string());
1382 0
1383 }
1384 }
1385}
1386
1387#[no_mangle]
1388pub unsafe extern "C" fn jit_call_method_safe(
1389 object_ptr: *const Value,
1390 method_name_ptr: *const u8,
1391 method_name_len: usize,
1392 args_ptr: *const Value,
1393 arg_count: u8,
1394 out: *mut Value,
1395) -> u8 {
1396 if object_ptr.is_null() || method_name_ptr.is_null() || out.is_null() {
1397 return 0;
1398 }
1399
1400 if arg_count > 0 && args_ptr.is_null() {
1401 return 0;
1402 }
1403
1404 let method_name_slice = std::slice::from_raw_parts(method_name_ptr, method_name_len);
1405 let method_name = match std::str::from_utf8(method_name_slice) {
1406 Ok(s) => s,
1407 Err(_) => return 0,
1408 };
1409 let object = &*object_ptr;
1410 if matches!(object, Value::Struct { .. }) {
1411 return 0;
1412 }
1413
1414 let mut args = Vec::with_capacity(arg_count as usize);
1415 for i in 0..arg_count {
1416 let arg_ptr = args_ptr.add(i as usize);
1417 args.push((&*arg_ptr).clone());
1418 }
1419
1420 let result = match call_builtin_method_simple(object, method_name, args) {
1421 Ok(val) => val,
1422 Err(_) => return 0,
1423 };
1424 std::ptr::write(out, result);
1425 1
1426}
1427
1428fn call_builtin_method_simple(
1429 object: &Value,
1430 method_name: &str,
1431 args: Vec<Value>,
1432) -> Result<Value, String> {
1433 match object {
1434 Value::Struct { name, .. } => Err(format!(
1435 "User-defined methods on {} require deoptimization",
1436 name
1437 )),
1438 Value::Iterator(state_rc) => match method_name {
1439 "next" => {
1440 let mut state = state_rc.borrow_mut();
1441 match &mut *state {
1442 IteratorState::Array { items, index } => {
1443 if *index < items.len() {
1444 let v = items[*index].clone();
1445 *index += 1;
1446 Ok(Value::some(v))
1447 } else {
1448 Ok(Value::none())
1449 }
1450 }
1451
1452 IteratorState::MapPairs { items, index } => {
1453 if *index < items.len() {
1454 let (k, v) = items[*index].clone();
1455 *index += 1;
1456 Ok(Value::some(Value::array(vec![k.to_value(), v])))
1457 } else {
1458 Ok(Value::none())
1459 }
1460 }
1461
1462 IteratorState::TablePairs { items, index } => {
1463 if *index < items.len() {
1464 let (k, v) = items[*index].clone();
1465 *index += 1;
1466 Ok(Value::some(Value::array(vec![k.to_value(), v])))
1467 } else {
1468 Ok(Value::none())
1469 }
1470 }
1471 }
1472 }
1473
1474 _ => Err(format!(
1475 "Iterator method '{}' not supported in JIT",
1476 method_name
1477 )),
1478 },
1479 Value::Enum {
1480 enum_name,
1481 variant,
1482 values,
1483 } if enum_name == "Option" => match method_name {
1484 "unwrap" => {
1485 if variant == "Some" {
1486 if let Some(vals) = values {
1487 if vals.len() == 1 {
1488 Ok(vals[0].clone())
1489 } else {
1490 Err("Option::Some should have exactly 1 value".to_string())
1491 }
1492 } else {
1493 Err("Option::Some should have a value".to_string())
1494 }
1495 } else {
1496 Err("Called unwrap() on Option::None".to_string())
1497 }
1498 }
1499
1500 _ => Err(format!(
1501 "Option method '{}' not supported in JIT",
1502 method_name
1503 )),
1504 },
1505 Value::Array(arr) => match method_name {
1506 "len" => Ok(Value::Int(arr.borrow().len() as i64)),
1507 "push" => {
1508 let value = args
1509 .get(0)
1510 .cloned()
1511 .ok_or_else(|| "Array:push requires a value argument".to_string())?;
1512 arr.borrow_mut().push(value);
1513 Ok(Value::Nil)
1514 }
1515 "pop" => {
1516 let popped = arr.borrow_mut().pop();
1517 Ok(popped.map(Value::some).unwrap_or_else(Value::none))
1518 }
1519 "first" => {
1520 let borrowed = arr.borrow();
1521 Ok(borrowed.first().cloned().map(Value::some).unwrap_or_else(Value::none))
1522 }
1523 "last" => {
1524 let borrowed = arr.borrow();
1525 Ok(borrowed.last().cloned().map(Value::some).unwrap_or_else(Value::none))
1526 }
1527 "get" => {
1528 let index = args
1529 .get(0)
1530 .and_then(Value::as_int)
1531 .ok_or_else(|| "Array:get requires an integer index".to_string())?;
1532 let borrowed = arr.borrow();
1533 Ok(borrowed
1534 .get(index as usize)
1535 .cloned()
1536 .map(Value::some)
1537 .unwrap_or_else(Value::none))
1538 }
1539 "iter" => {
1540 let items = arr.borrow().clone();
1541 let iter = IteratorState::Array { items, index: 0 };
1542 Ok(Value::Iterator(Rc::new(RefCell::new(iter))))
1543 }
1544 _ => Err(format!(
1545 "Array method '{}' not supported in JIT",
1546 method_name
1547 )),
1548 },
1549 _ => Err(format!(
1550 "Method '{}' not supported in JIT (deoptimizing)",
1551 method_name
1552 )),
1553 }
1554}
1555
1556#[no_mangle]
1557pub unsafe extern "C" fn jit_get_field_safe(
1558 object_ptr: *const Value,
1559 field_name_ptr: *const u8,
1560 field_name_len: usize,
1561 out: *mut Value,
1562) -> u8 {
1563 if object_ptr.is_null() || field_name_ptr.is_null() || out.is_null() {
1564 return 0;
1565 }
1566
1567 let field_name_slice = std::slice::from_raw_parts(field_name_ptr, field_name_len);
1568 let field_name = match std::str::from_utf8(field_name_slice) {
1569 Ok(s) => s,
1570 Err(_) => return 0,
1571 };
1572 let object = &*object_ptr;
1573 let field_value = match object {
1574 Value::Struct { layout, fields, .. } => match layout.index_of_str(field_name) {
1575 Some(idx) => match fields.borrow().get(idx) {
1576 Some(val) => val.clone(),
1577 None => return 0,
1578 },
1579 None => return 0,
1580 },
1581 _ => return 0,
1582 };
1583 std::ptr::write(out, field_value);
1584 1
1585}
1586
1587#[no_mangle]
1588pub unsafe extern "C" fn jit_set_field_safe(
1589 object_ptr: *const Value,
1590 field_name_ptr: *const u8,
1591 field_name_len: usize,
1592 value_ptr: *const Value,
1593) -> u8 {
1594 if object_ptr.is_null() || field_name_ptr.is_null() || value_ptr.is_null() {
1595 return 0;
1596 }
1597
1598 let field_name_slice = std::slice::from_raw_parts(field_name_ptr, field_name_len);
1599 let field_name = match std::str::from_utf8(field_name_slice) {
1600 Ok(s) => s,
1601 Err(_) => return 0,
1602 };
1603 let object = &*object_ptr;
1604 let value = (&*value_ptr).clone();
1605 match object {
1606 Value::Struct { .. } => match object.struct_set_field(field_name, value) {
1607 Ok(()) => 1,
1608 Err(_) => 0,
1609 },
1610 Value::Map(map) => {
1611 use crate::bytecode::ValueKey;
1612 let key = ValueKey::String(Rc::new(field_name.to_string()));
1613 map.borrow_mut().insert(key, value);
1614 1
1615 }
1616
1617 _ => 0,
1618 }
1619}
1620
1621#[no_mangle]
1622pub unsafe extern "C" fn jit_get_field_indexed_safe(
1623 object_ptr: *const Value,
1624 field_index: usize,
1625 out: *mut Value,
1626) -> u8 {
1627 if object_ptr.is_null() || out.is_null() {
1628 return 0;
1629 }
1630
1631 let object = &*object_ptr;
1632 match object.struct_get_field_indexed(field_index) {
1633 Some(value) => {
1634 std::ptr::write(out, value);
1635 1
1636 }
1637
1638 None => 0,
1639 }
1640}
1641
1642#[no_mangle]
1643pub unsafe extern "C" fn jit_set_field_indexed_safe(
1644 object_ptr: *const Value,
1645 field_index: usize,
1646 value_ptr: *const Value,
1647) -> u8 {
1648 if object_ptr.is_null() || value_ptr.is_null() {
1649 return 0;
1650 }
1651
1652 let object = &*object_ptr;
1653 let value = (&*value_ptr).clone();
1654 match object.struct_set_field_indexed(field_index, value) {
1655 Ok(()) => 1,
1656 Err(_) => 0,
1657 }
1658}
1659
1660#[no_mangle]
1661pub unsafe extern "C" fn jit_get_field_indexed_int_fast(
1662 object_ptr: *const Value,
1663 field_index: usize,
1664 out: *mut Value,
1665) -> u8 {
1666 if object_ptr.is_null() || out.is_null() {
1667 return 0;
1668 }
1669
1670 let object = &*object_ptr;
1671 let out_ref = &mut *out;
1672 match object {
1673 Value::Struct { layout, fields, .. } => {
1674 if layout.is_weak(field_index) {
1675 return 0;
1676 }
1677
1678 if let Ok(borrowed) = fields.try_borrow() {
1679 if let Some(Value::Int(val)) = borrowed.get(field_index) {
1680 *out_ref = Value::Int(*val);
1681 return 1;
1682 }
1683 }
1684
1685 0
1686 }
1687
1688 _ => 0,
1689 }
1690}
1691
1692#[no_mangle]
1693pub unsafe extern "C" fn jit_set_field_indexed_int_fast(
1694 object_ptr: *const Value,
1695 field_index: usize,
1696 value_ptr: *const Value,
1697) -> u8 {
1698 if object_ptr.is_null() || value_ptr.is_null() {
1699 return 0;
1700 }
1701
1702 let object = &*object_ptr;
1703 let value = &*value_ptr;
1704 let new_value = match value {
1705 Value::Int(v) => *v,
1706 _ => return 0,
1707 };
1708 match object {
1709 Value::Struct { layout, fields, .. } => {
1710 if layout.is_weak(field_index) {
1711 return 0;
1712 }
1713
1714 if let Ok(mut borrowed) = fields.try_borrow_mut() {
1715 if field_index < borrowed.len() {
1716 borrowed[field_index] = Value::Int(new_value);
1717 return 1;
1718 }
1719 }
1720
1721 0
1722 }
1723
1724 _ => 0,
1725 }
1726}
1727
1728#[no_mangle]
1729pub unsafe extern "C" fn jit_new_struct_safe(
1730 struct_name_ptr: *const u8,
1731 struct_name_len: usize,
1732 field_names_ptr: *const *const u8,
1733 field_name_lens_ptr: *const usize,
1734 field_values_ptr: *const Value,
1735 field_count: usize,
1736 out: *mut Value,
1737) -> u8 {
1738 if struct_name_ptr.is_null() || out.is_null() {
1739 return 0;
1740 }
1741
1742 if field_count > 0
1743 && (field_names_ptr.is_null()
1744 || field_name_lens_ptr.is_null()
1745 || field_values_ptr.is_null())
1746 {
1747 return 0;
1748 }
1749
1750 let struct_name_slice = std::slice::from_raw_parts(struct_name_ptr, struct_name_len);
1751 let struct_name = match std::str::from_utf8(struct_name_slice) {
1752 Ok(s) => s.to_string(),
1753 Err(_) => return 0,
1754 };
1755 let mut fields = Vec::with_capacity(field_count);
1756 for i in 0..field_count {
1757 let field_name_ptr = *field_names_ptr.add(i);
1758 let field_name_len = *field_name_lens_ptr.add(i);
1759 let field_name_slice = std::slice::from_raw_parts(field_name_ptr, field_name_len);
1760 let field_name = match std::str::from_utf8(field_name_slice) {
1761 Ok(s) => Rc::new(s.to_string()),
1762 Err(_) => return 0,
1763 };
1764 let field_value_ptr = field_values_ptr.add(i);
1765 let field_value = (&*field_value_ptr).clone();
1766 fields.push((field_name, field_value));
1767 }
1768
1769 let struct_value = match crate::vm::VM::with_current(move |vm| {
1770 vm.instantiate_struct(&struct_name, fields)
1771 .map_err(|err| err.to_string())
1772 }) {
1773 Ok(value) => value,
1774 Err(_) => return 0,
1775 };
1776 std::ptr::write(out, struct_value);
1777 1
1778}
1779
1780#[no_mangle]
1781pub unsafe extern "C" fn jit_move_safe(src_ptr: *const Value, dest_ptr: *mut Value) -> u8 {
1782 if src_ptr.is_null() || dest_ptr.is_null() {
1783 return 0;
1784 }
1785
1786 let src_value = &*src_ptr;
1787 let cloned_value = src_value.clone();
1788 std::ptr::write(dest_ptr, cloned_value);
1789 1
1790}