Skip to main content

tl_compiler/
jit_runtime.rs

1// ThinkingLanguage — JIT Runtime Helpers
2// extern "C" functions callable from Cranelift-generated native code.
3// These handle dynamic type dispatch that the JIT can't do statically.
4
5use crate::value::VmValue;
6use std::sync::Arc;
7
8/// Runtime addition: handles int+int, float+float, int+float, string+string
9#[unsafe(no_mangle)]
10pub extern "C" fn tl_rt_add(a: *const VmValue, b: *const VmValue, out: *mut VmValue) {
11    let a = unsafe { &*a };
12    let b = unsafe { &*b };
13    let result = match (a, b) {
14        (VmValue::Int(x), VmValue::Int(y)) => VmValue::Int(x + y),
15        (VmValue::Float(x), VmValue::Float(y)) => VmValue::Float(x + y),
16        (VmValue::Int(x), VmValue::Float(y)) => VmValue::Float(*x as f64 + y),
17        (VmValue::Float(x), VmValue::Int(y)) => VmValue::Float(x + *y as f64),
18        (VmValue::String(x), VmValue::String(y)) => {
19            VmValue::String(Arc::from(format!("{x}{y}").as_str()))
20        }
21        _ => VmValue::None,
22    };
23    unsafe {
24        out.write(result);
25    }
26}
27
28/// Runtime subtraction
29#[unsafe(no_mangle)]
30pub extern "C" fn tl_rt_sub(a: *const VmValue, b: *const VmValue, out: *mut VmValue) {
31    let a = unsafe { &*a };
32    let b = unsafe { &*b };
33    let result = match (a, b) {
34        (VmValue::Int(x), VmValue::Int(y)) => VmValue::Int(x - y),
35        (VmValue::Float(x), VmValue::Float(y)) => VmValue::Float(x - y),
36        (VmValue::Int(x), VmValue::Float(y)) => VmValue::Float(*x as f64 - y),
37        (VmValue::Float(x), VmValue::Int(y)) => VmValue::Float(x - *y as f64),
38        _ => VmValue::None,
39    };
40    unsafe {
41        out.write(result);
42    }
43}
44
45/// Runtime multiplication
46#[unsafe(no_mangle)]
47pub extern "C" fn tl_rt_mul(a: *const VmValue, b: *const VmValue, out: *mut VmValue) {
48    let a = unsafe { &*a };
49    let b = unsafe { &*b };
50    let result = match (a, b) {
51        (VmValue::Int(x), VmValue::Int(y)) => VmValue::Int(x * y),
52        (VmValue::Float(x), VmValue::Float(y)) => VmValue::Float(x * y),
53        (VmValue::Int(x), VmValue::Float(y)) => VmValue::Float(*x as f64 * y),
54        (VmValue::Float(x), VmValue::Int(y)) => VmValue::Float(x * *y as f64),
55        _ => VmValue::None,
56    };
57    unsafe {
58        out.write(result);
59    }
60}
61
62/// Runtime comparison: returns -1, 0, or 1
63#[unsafe(no_mangle)]
64pub extern "C" fn tl_rt_cmp(a: *const VmValue, b: *const VmValue) -> i64 {
65    let a = unsafe { &*a };
66    let b = unsafe { &*b };
67    match (a, b) {
68        (VmValue::Int(x), VmValue::Int(y)) => {
69            if x < y {
70                -1
71            } else if x > y {
72                1
73            } else {
74                0
75            }
76        }
77        (VmValue::Float(x), VmValue::Float(y)) => {
78            if x < y {
79                -1.0 as i64
80            } else if x > y {
81                1
82            } else {
83                0
84            }
85        }
86        _ => 0,
87    }
88}
89
90/// Runtime truthiness check
91#[unsafe(no_mangle)]
92pub extern "C" fn tl_rt_is_truthy(val: *const VmValue) -> i64 {
93    let val = unsafe { &*val };
94    if val.is_truthy() { 1 } else { 0 }
95}