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