YREA-SLS/SLS_Rust/sls/src/builtin.rs

1187 lines
34 KiB
Rust

use crate::interpreter::{
InterpreterState,
StackValue,
FunctionItem,
BuiltinFunction,
BuiltinFn,
};
use crate::lexer::{Token, Identifier};
use std::collections::HashMap;
// Numeric type flags
bitflags::bitflags! {
#[derive(Debug, Clone, Copy)]
struct NumericType: u32 {
const FLOAT = 1 << 0;
const SIGNED = 1 << 1;
const BITS_64 = 1 << 2;
const BITS_32 = 1 << 3;
const BITS_16 = 1 << 4;
const BITS_8 = 1 << 5;
}
}
struct NumericValue {
float_val: f64,
int_val: u64,
type_flags: NumericType,
}
// Extract numeric value from a single stack item
fn extract_numeric_type(item: &StackValue) -> Option<NumericValue> {
let mut val = NumericValue {
float_val: 0.0,
int_val: 0,
type_flags: NumericType::empty(),
};
match item {
StackValue::I64(v) => {
val.int_val = *v as u64;
val.float_val = *v as f64;
val.type_flags = NumericType::BITS_64 | NumericType::SIGNED;
}
StackValue::I32(v) => {
val.int_val = *v as u64;
val.float_val = *v as f64;
val.type_flags = NumericType::BITS_32 | NumericType::SIGNED;
}
StackValue::I16(v) => {
val.int_val = *v as u64;
val.float_val = *v as f64;
val.type_flags = NumericType::BITS_16 | NumericType::SIGNED;
}
StackValue::I8(v) => {
val.int_val = *v as u64;
val.float_val = *v as f64;
val.type_flags = NumericType::BITS_8 | NumericType::SIGNED;
}
StackValue::U64(v) => {
val.int_val = *v;
val.float_val = *v as f64;
val.type_flags = NumericType::BITS_64;
}
StackValue::U32(v) => {
val.int_val = *v as u64;
val.float_val = *v as f64;
val.type_flags = NumericType::BITS_32;
}
StackValue::U16(v) => {
val.int_val = *v as u64;
val.float_val = *v as f64;
val.type_flags = NumericType::BITS_16;
}
StackValue::U8(v) => {
val.int_val = *v as u64;
val.float_val = *v as f64;
val.type_flags = NumericType::BITS_8;
}
StackValue::F32(v) => {
val.float_val = *v as f64;
val.type_flags = NumericType::BITS_32 | NumericType::FLOAT;
}
StackValue::F64(v) => {
val.float_val = *v;
val.type_flags = NumericType::BITS_64 | NumericType::FLOAT;
}
StackValue::Character(v) => {
val.int_val = *v as u64;
val.float_val = *v as f64;
}
StackValue::Boolean(v) => {
val.int_val = *v as u64;
val.float_val = if *v { 1.0 } else { 0.0 };
}
_ => return None,
}
Some(val)
}
// Extract two numeric values from stack
fn extract_numeric_types(state: &InterpreterState) -> Option<(NumericValue, NumericValue, NumericType)> {
if state.stack.len() < 2 {
return None;
}
let a = extract_numeric_type(&state.stack[state.stack.len()-1])?;
let b = extract_numeric_type(&state.stack[state.stack.len()-2])?;
// Combine type flags
let combined = a.type_flags | b.type_flags;
Some((a, b, combined))
}
// Convert numeric result to appropriate token based on type flags
fn numeric_to_token(float_val: f64, int_val: u64, type_flags: NumericType) -> Token {
if type_flags.contains(NumericType::FLOAT) {
if type_flags.contains(NumericType::BITS_64) {
Token::Double(float_val)
} else {
Token::Float(float_val as f32)
}
} else if type_flags.contains(NumericType::SIGNED) {
if type_flags.contains(NumericType::BITS_64) {
Token::I64(int_val as i64)
} else if type_flags.contains(NumericType::BITS_32) {
Token::I32(int_val as i32)
} else if type_flags.contains(NumericType::BITS_16) {
Token::I16(int_val as i16)
} else {
Token::I8(int_val as i8)
}
} else {
if type_flags.contains(NumericType::BITS_64) {
Token::U64(int_val)
} else if type_flags.contains(NumericType::BITS_32) {
Token::U32(int_val as u32)
} else if type_flags.contains(NumericType::BITS_16) {
Token::U16(int_val as u16)
} else {
Token::U8(int_val as u8)
}
}
}
// Check if value is truthy
fn is_truthy(item: &StackValue) -> bool {
match item {
StackValue::I64(v) => *v != 0,
StackValue::I32(v) => *v != 0,
StackValue::I16(v) => *v != 0,
StackValue::I8(v) => *v != 0,
StackValue::U64(v) => *v != 0,
StackValue::U32(v) => *v != 0,
StackValue::U16(v) => *v != 0,
StackValue::U8(v) => *v != 0,
StackValue::F32(v) => *v != 0.0,
StackValue::F64(v) => *v != 0.0,
StackValue::Character(v) => *v != 0,
StackValue::Boolean(v) => *v,
StackValue::TokenString(ts) => {
!ts.tokens.is_empty() && !matches!(ts.tokens[0], Token::Eof)
}
StackValue::Callable(_) => false,
_ => false,
}
}
// Extract scalar value (for indexing operations)
fn extract_scalar(item: &StackValue) -> Option<usize> {
match item {
StackValue::I64(v) if *v >= 0 => Some(*v as usize),
StackValue::I32(v) if *v >= 0 => Some(*v as usize),
StackValue::I16(v) if *v >= 0 => Some(*v as usize),
StackValue::I8(v) if *v >= 0 => Some(*v as usize),
StackValue::U64(v) => Some(*v as usize),
StackValue::U32(v) => Some(*v as usize),
StackValue::U16(v) => Some(*v as usize),
StackValue::U8(v) => Some(*v as usize),
StackValue::Character(v) => Some(*v as usize),
StackValue::Boolean(v) => Some(*v as usize),
_ => None,
}
}
// Builtin function implementations
pub fn builtin_addition(state: &mut InterpreterState) -> bool {
let Some((a, b, type_flags)) = extract_numeric_types(state) else {
return false;
};
state.stack.pop();
state.stack.pop();
let result = if type_flags.contains(NumericType::FLOAT) {
numeric_to_token(b.float_val + a.float_val, 0, type_flags)
} else {
numeric_to_token(0.0, b.int_val.wrapping_add(a.int_val), type_flags)
};
state.push_token(&result);
true
}
pub fn builtin_subtraction(state: &mut InterpreterState) -> bool {
let Some((a, b, type_flags)) = extract_numeric_types(state) else {
return false;
};
state.stack.pop();
state.stack.pop();
let result = if type_flags.contains(NumericType::FLOAT) {
numeric_to_token(b.float_val - a.float_val, 0, type_flags)
} else {
numeric_to_token(0.0, b.int_val.wrapping_sub(a.int_val), type_flags)
};
state.push_token(&result);
true
}
pub fn builtin_multiplication(state: &mut InterpreterState) -> bool {
let Some((a, b, type_flags)) = extract_numeric_types(state) else {
return false;
};
state.stack.pop();
state.stack.pop();
let result = if type_flags.contains(NumericType::FLOAT) {
numeric_to_token(b.float_val * a.float_val, 0, type_flags)
} else {
numeric_to_token(0.0, b.int_val.wrapping_mul(a.int_val), type_flags)
};
state.push_token(&result);
true
}
pub fn builtin_division(state: &mut InterpreterState) -> bool {
let Some((a, b, _)) = extract_numeric_types(state) else {
return false;
};
if a.float_val == 0.0 {
return false;
}
state.stack.pop();
state.stack.pop();
state.stack.push(StackValue::F64(b.float_val / a.float_val));
true
}
pub fn builtin_modulus(state: &mut InterpreterState) -> bool {
let Some((a, b, type_flags)) = extract_numeric_types(state) else {
return false;
};
if type_flags.contains(NumericType::FLOAT) || a.int_val == 0 {
return false;
}
state.stack.pop();
state.stack.pop();
let result = numeric_to_token(0.0, b.int_val % a.int_val, type_flags);
state.push_token(&result);
true
}
pub fn builtin_exponential(state: &mut InterpreterState) -> bool {
let Some((a, b, _)) = extract_numeric_types(state) else {
return false;
};
state.stack.pop();
state.stack.pop();
state.stack.push(StackValue::F64(b.float_val.powf(a.float_val)));
true
}
pub fn builtin_greater_than(state: &mut InterpreterState) -> bool {
let Some((a, b, _)) = extract_numeric_types(state) else {
return false;
};
state.stack.pop();
state.stack.pop();
state.stack.push(StackValue::Boolean(b.float_val > a.float_val));
true
}
pub fn builtin_greater_than_or_equal_to(state: &mut InterpreterState) -> bool {
let Some((a, b, _)) = extract_numeric_types(state) else {
return false;
};
state.stack.pop();
state.stack.pop();
state.stack.push(StackValue::Boolean(b.float_val >= a.float_val));
true
}
pub fn builtin_less_than(state: &mut InterpreterState) -> bool {
let Some((a, b, _)) = extract_numeric_types(state) else {
return false;
};
state.stack.pop();
state.stack.pop();
state.stack.push(StackValue::Boolean(b.float_val < a.float_val));
true
}
pub fn builtin_less_than_or_equal_to(state: &mut InterpreterState) -> bool {
let Some((a, b, _)) = extract_numeric_types(state) else {
return false;
};
state.stack.pop();
state.stack.pop();
state.stack.push(StackValue::Boolean(b.float_val <= a.float_val));
true
}
pub fn builtin_equal_to(state: &mut InterpreterState) -> bool {
let Some((a, b, _)) = extract_numeric_types(state) else {
return false;
};
state.stack.pop();
state.stack.pop();
state.stack.push(StackValue::Boolean(b.float_val == a.float_val));
true
}
pub fn builtin_not_equal_to(state: &mut InterpreterState) -> bool {
let Some((a, b, _)) = extract_numeric_types(state) else {
return false;
};
state.stack.pop();
state.stack.pop();
state.stack.push(StackValue::Boolean(b.float_val != a.float_val));
true
}
pub fn builtin_abs(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let Some(last) = state.stack.last() else { return false };
let Some(val) = extract_numeric_type(last) else { return false };
if !val.type_flags.contains(NumericType::SIGNED | NumericType::FLOAT) {
return false;
}
state.stack.pop();
let result = if val.type_flags.contains(NumericType::FLOAT) {
numeric_to_token(val.float_val.abs(), 0, val.type_flags)
} else {
numeric_to_token(0.0, (val.int_val as i64).unsigned_abs(), val.type_flags)
};
state.push_token(&result);
true
}
pub fn builtin_acos(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let Some(last) = state.stack.last() else { return false };
let Some(val) = extract_numeric_type(last) else { return false };
if val.float_val < -1.0 || val.float_val > 1.0 {
return false;
}
state.stack.pop();
state.stack.push(StackValue::F64(val.float_val.acos()));
true
}
pub fn builtin_and(state: &mut InterpreterState) -> bool {
let Some((a, b, type_flags)) = extract_numeric_types(state) else {
return false;
};
state.stack.pop();
state.stack.pop();
let result = if type_flags.contains(NumericType::FLOAT) {
b.float_val != 0.0 && a.float_val != 0.0
} else {
b.int_val != 0 && a.int_val != 0
};
state.stack.push(StackValue::Boolean(result));
true
}
pub fn builtin_asin(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let Some(last) = state.stack.last() else { return false };
let Some(val) = extract_numeric_type(last) else { return false };
if val.float_val < -1.0 || val.float_val > 1.0 {
return false;
}
state.stack.pop();
state.stack.push(StackValue::F64(val.float_val.asin()));
true
}
pub fn builtin_atan(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let Some(last) = state.stack.last() else { return false };
let Some(val) = extract_numeric_type(last) else { return false };
state.stack.pop();
state.stack.push(StackValue::F64(val.float_val.atan()));
true
}
pub fn builtin_atan2(state: &mut InterpreterState) -> bool {
let Some((a, b, _)) = extract_numeric_types(state) else {
return false;
};
state.stack.pop();
state.stack.pop();
state.stack.push(StackValue::F64(b.float_val.atan2(a.float_val)));
true
}
// Bitwise operations
pub fn builtin_bitand(state: &mut InterpreterState) -> bool {
let Some((a, b, type_flags)) = extract_numeric_types(state) else {
return false;
};
if type_flags.contains(NumericType::FLOAT) {
return false;
}
state.stack.pop();
state.stack.pop();
let result = numeric_to_token(0.0, b.int_val & a.int_val, type_flags);
state.push_token(&result);
true
}
pub fn builtin_bitnot(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let Some(last) = state.stack.last() else { return false };
let Some(val) = extract_numeric_type(last) else { return false };
if val.type_flags.contains(NumericType::FLOAT) {
return false;
}
state.stack.pop();
let result = numeric_to_token(0.0, !val.int_val, val.type_flags);
state.push_token(&result);
true
}
pub fn builtin_bitor(state: &mut InterpreterState) -> bool {
let Some((a, b, type_flags)) = extract_numeric_types(state) else {
return false;
};
if type_flags.contains(NumericType::FLOAT) {
return false;
}
state.stack.pop();
state.stack.pop();
let result = numeric_to_token(0.0, b.int_val | a.int_val, type_flags);
state.push_token(&result);
true
}
pub fn builtin_bitxor(state: &mut InterpreterState) -> bool {
let Some((a, b, type_flags)) = extract_numeric_types(state) else {
return false;
};
if type_flags.contains(NumericType::FLOAT) {
return false;
}
state.stack.pop();
state.stack.pop();
let result = numeric_to_token(0.0, b.int_val ^ a.int_val, type_flags);
state.push_token(&result);
true
}
// Math functions
pub fn builtin_ceil(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let Some(last) = state.stack.last() else { return false };
let Some(val) = extract_numeric_type(last) else { return false };
state.stack.pop();
state.stack.push(StackValue::F64(val.float_val.ceil()));
true
}
pub fn builtin_floor(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let Some(last) = state.stack.last() else { return false };
let Some(val) = extract_numeric_type(last) else { return false };
state.stack.pop();
state.stack.push(StackValue::F64(val.float_val.floor()));
true
}
pub fn builtin_round(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let Some(last) = state.stack.last() else { return false };
let Some(val) = extract_numeric_type(last) else { return false };
state.stack.pop();
state.stack.push(StackValue::F64(val.float_val.round()));
true
}
pub fn builtin_sqrt(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let Some(last) = state.stack.last() else { return false };
let Some(val) = extract_numeric_type(last) else { return false };
if val.float_val < 0.0 {
return false;
}
state.stack.pop();
state.stack.push(StackValue::F64(val.float_val.sqrt()));
true
}
pub fn builtin_sin(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let Some(last) = state.stack.last() else { return false };
let Some(val) = extract_numeric_type(last) else { return false };
state.stack.pop();
state.stack.push(StackValue::F64(val.float_val.sin()));
true
}
pub fn builtin_cos(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let Some(last) = state.stack.last() else { return false };
let Some(val) = extract_numeric_type(last) else { return false };
state.stack.pop();
state.stack.push(StackValue::F64(val.float_val.cos()));
true
}
pub fn builtin_tan(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let Some(last) = state.stack.last() else { return false };
let Some(val) = extract_numeric_type(last) else { return false };
state.stack.pop();
state.stack.push(StackValue::F64(val.float_val.tan()));
true
}
pub fn builtin_ln(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let Some(last) = state.stack.last() else { return false };
let Some(val) = extract_numeric_type(last) else { return false };
if val.float_val <= 0.0 {
return false;
}
state.stack.pop();
state.stack.push(StackValue::F64(val.float_val.ln()));
true
}
pub fn builtin_log(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let Some(last) = state.stack.last() else { return false };
let Some(val) = extract_numeric_type(last) else { return false };
if val.float_val <= 0.0 {
return false;
}
state.stack.pop();
state.stack.push(StackValue::F64(val.float_val.log10()));
true
}
// Stack operations
pub fn builtin_depth(state: &mut InterpreterState) -> bool {
state.stack.push(StackValue::U64(state.stack.len() as u64));
true
}
pub fn builtin_drop(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
state.stack.pop();
true
}
pub fn builtin_dup(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let item = state.stack[state.stack.len()-1].clone();
state.stack.push(item);
true
}
pub fn builtin_swap(state: &mut InterpreterState) -> bool {
if state.stack.len() < 2 {
return false;
}
state.stack.swap(0, 1);
true
}
pub fn builtin_pick(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let Some(index) = extract_scalar(&state.stack[state.stack.len()-1]) else {
return false;
};
if index + 1 >= state.stack.len() {
return false;
}
let item = state.stack[index + 1].clone();
state.stack.pop();
state.stack.push(item);
true
}
pub fn builtin_roll(state: &mut InterpreterState) -> bool {
if state.stack.len() < 2 {
return false;
}
let Some(times) = extract_scalar(&state.stack[state.stack.len()-1]) else {
return false;
};
let Some(count) = extract_scalar(&state.stack[state.stack.len()-2]) else {
return false;
};
if count == 0 || count + 2 > state.stack.len() {
return false;
}
state.stack.pop();
state.stack.pop();
// Rotate the top 'count' items 'times' times
for _ in 0..times {
let item = state.stack.remove(count - 1);
state.stack.push(item);
}
true
}
// Logical operations
pub fn builtin_not(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let truthy = is_truthy(&state.stack[state.stack.len()-1]);
state.stack.pop();
state.stack.push(StackValue::Boolean(!truthy));
true
}
pub fn builtin_or(state: &mut InterpreterState) -> bool {
let Some((a, b, type_flags)) = extract_numeric_types(state) else {
return false;
};
state.stack.pop();
state.stack.pop();
let result = if type_flags.contains(NumericType::FLOAT) {
b.float_val != 0.0 || a.float_val != 0.0
} else {
b.int_val != 0 || a.int_val != 0
};
state.stack.push(StackValue::Boolean(result));
true
}
// Shift operations
pub fn builtin_shl(state: &mut InterpreterState) -> bool {
let Some((a, b, type_flags)) = extract_numeric_types(state) else {
return false;
};
if type_flags.contains(NumericType::FLOAT) {
return false;
}
state.stack.pop();
state.stack.pop();
let result = numeric_to_token(0.0, b.int_val << a.int_val, type_flags);
state.push_token(&result);
true
}
pub fn builtin_shr(state: &mut InterpreterState) -> bool {
let Some((a, b, type_flags)) = extract_numeric_types(state) else {
return false;
};
if type_flags.contains(NumericType::FLOAT) {
return false;
}
state.stack.pop();
state.stack.pop();
let result = numeric_to_token(0.0, b.int_val >> a.int_val, type_flags);
state.push_token(&result);
true
}
// Random operations
pub fn builtin_rand(state: &mut InterpreterState) -> bool {
use rand::Rng;
let val = rand::thread_rng().gen::<f64>();
state.stack.push(StackValue::F64(val));
true
}
pub fn builtin_seed(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let Some(last) = state.stack.last() else { return false };
let Some(val) = extract_numeric_type(last) else { return false };
if val.type_flags.contains(NumericType::FLOAT) {
return false;
}
state.stack.pop();
// Note: Rust's rand crate doesn't have global seeding
// You'd need to store the RNG in InterpreterState
true
}
// Control flow operations
pub fn builtin_if(state: &mut InterpreterState) -> bool {
if state.stack.len() < 3 {
return false;
}
let else_block = match &state.stack[state.stack.len()-1] {
StackValue::TokenString(ts) | StackValue::Callable(ts) => ts.clone(),
_ => return false,
};
let then_block = match &state.stack[state.stack.len()-2] {
StackValue::TokenString(ts) | StackValue::Callable(ts) => ts.clone(),
_ => return false,
};
let condition = is_truthy(&state.stack[state.stack.len()-3]);
state.stack.pop();
state.stack.pop();
state.stack.pop();
if condition {
state.execute_token_string(&then_block)
} else {
state.execute_token_string(&else_block)
}
}
pub fn builtin_while(state: &mut InterpreterState) -> bool {
if state.stack.len() < 2 {
return false;
}
let while_block = match &state.stack[state.stack.len()-1] {
StackValue::TokenString(ts) | StackValue::Callable(ts) => ts.clone(),
_ => return false,
};
let cond_block = match &state.stack[state.stack.len()-2] {
StackValue::TokenString(ts) | StackValue::Callable(ts) => ts.clone(),
_ => return false,
};
state.stack.pop();
state.stack.pop();
loop {
if !state.execute_token_string(&cond_block) {
return false;
}
if state.stack.is_empty() {
return false;
}
let condition = is_truthy(&state.stack[state.stack.len()-1]);
state.stack.pop();
if !condition {
break;
}
if !state.execute_token_string(&while_block) {
return false;
}
}
true
}
pub fn builtin_for(state: &mut InterpreterState) -> bool {
if state.stack.len() < 3 {
return false;
}
let for_block = match &state.stack[state.stack.len()-1] {
StackValue::TokenString(ts) | StackValue::Callable(ts) => ts.clone(),
_ => return false,
};
let Some(end) = extract_scalar(&state.stack[state.stack.len()-2]) else {
return false;
};
let Some(start) = extract_scalar(&state.stack[state.stack.len()-3]) else {
return false;
};
state.stack.pop();
state.stack.pop();
state.stack.pop();
for i in start..end {
state.stack.push(StackValue::I64(i as i64));
if !state.execute_token_string(&for_block) {
return false;
}
}
true
}
pub fn builtin_lambda(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let stack_len = state.stack.len();
match &mut state.stack[stack_len-1] {
StackValue::TokenString(ts) => {
let callable = StackValue::Callable(ts.clone());
state.stack[stack_len-1] = callable;
true
}
_ => false,
}
}
pub fn builtin_eval(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let code = state.stack.pop();
match code {
Some(StackValue::TokenString(ts)) | Some(StackValue::Callable(ts)) => {
state.execute_token_string(&ts)
}
Some(StackValue::Identifier(id)) => {
state.execute_func(&id.name)
}
_ => false,
}
}
pub fn builtin_const(state: &mut InterpreterState) -> bool {
if state.stack.len() < 2 {
return false;
}
let name = match &state.stack[state.stack.len()-1] {
StackValue::Identifier(id) => id.name.clone(),
_ => return false,
};
let value = match &state.stack[state.stack.len()-2] {
StackValue::Callable(ts) => ts.clone(),
_ => return false,
};
if state.functions.contains_key(&name) {
return false;
}
state.stack.pop();
state.stack.pop();
state.functions.insert(name, FunctionItem::TokenString(value));
true
}
pub fn builtin_type_of(state: &mut InterpreterState) -> bool {
if state.stack.is_empty() {
return false;
}
let type_name = match &state.stack[state.stack.len()-1] {
StackValue::Identifier(_) => "Identifier",
StackValue::I64(_) => "i64",
StackValue::I32(_) => "i32",
StackValue::I16(_) => "i16",
StackValue::I8(_) => "i8",
StackValue::U64(_) => "u64",
StackValue::U32(_) => "u32",
StackValue::U16(_) => "u16",
StackValue::U8(_) => "u8",
StackValue::F32(_) => "f32",
StackValue::F64(_) => "f64",
StackValue::Character(_) => "char",
StackValue::Boolean(_) => "bool",
StackValue::TokenString(_) => "TokenString",
StackValue::Callable(_) => "Callable",
};
state.stack.pop();
state.stack.push(StackValue::Identifier(Identifier {
name: type_name.to_string(),
is_literal: true,
}));
true
}
pub fn lookup_builtin(name: &str) -> Option<BuiltinFn> {
if name == "+" { Some(builtin_addition) }
else if name == "-" { Some(builtin_subtraction) }
else if name == "*" { Some(builtin_multiplication) }
else if name == "/" { Some(builtin_division) }
else if name == "%" { Some(builtin_modulus) }
else if name == "^" { Some(builtin_exponential) }
else if name == ">" { Some(builtin_greater_than) }
else if name == ">=" { Some(builtin_greater_than_or_equal_to) }
else if name == "<" { Some(builtin_less_than) }
else if name == "<=" { Some(builtin_less_than_or_equal_to) }
else if name == "==" { Some(builtin_equal_to) }
else if name == "!=" { Some(builtin_not_equal_to) }
else if name == "abs" { Some(builtin_abs) }
else if name == "acos" { Some(builtin_acos) }
else if name == "asin" { Some(builtin_asin) }
else if name == "atan" { Some(builtin_atan) }
else if name == "atan2" { Some(builtin_atan2) }
else if name == "ceil" { Some(builtin_ceil) }
else if name == "floor" { Some(builtin_floor) }
else if name == "round" { Some(builtin_round) }
else if name == "sqrt" { Some(builtin_sqrt) }
else if name == "sin" { Some(builtin_sin) }
else if name == "cos" { Some(builtin_cos) }
else if name == "tan" { Some(builtin_tan) }
else if name == "ln" { Some(builtin_ln) }
else if name == "log" { Some(builtin_log) }
else if name == "and" { Some(builtin_and) }
else if name == "or" { Some(builtin_or) }
else if name == "not" { Some(builtin_not) }
else if name == "bitand" { Some(builtin_bitand) }
else if name == "bitnot" { Some(builtin_bitnot) }
else if name == "bitor" { Some(builtin_bitor) }
else if name == "bitxor" { Some(builtin_bitxor) }
else if name == "shl" { Some(builtin_shl) }
else if name == "shr" { Some(builtin_shr) }
else if name == "depth" { Some(builtin_depth) }
else if name == "drop" { Some(builtin_drop) }
else if name == "dup" { Some(builtin_dup) }
else if name == "swap" { Some(builtin_swap) }
else if name == "pick" { Some(builtin_pick) }
else if name == "roll" { Some(builtin_roll) }
else if name == "if" { Some(builtin_if) }
else if name == "while" { Some(builtin_while) }
else if name == "for" { Some(builtin_for) }
else if name == "lambda" { Some(builtin_lambda) }
else if name == "eval" { Some(builtin_eval) }
else if name == "const" { Some(builtin_const) }
else if name == "type_of" { Some(builtin_type_of) }
else if name == "rand" { Some(builtin_rand) }
else if name == "seed" { Some(builtin_seed) }
else { None }
}
// Helper to add builtin to function table
fn register_builtin(
functions: &mut HashMap<String, FunctionItem>,
name: &str,
func: fn(&mut InterpreterState) -> bool,
) {
functions.insert(name.to_string(), FunctionItem::Builtin(BuiltinFunction {
name: name.to_string(),
function: match lookup_builtin(name) {
Some(func) => func,
None => panic!("Builtin Not Found!"),
}
}));
}
pub fn load_builtins(state: &mut InterpreterState) -> bool {
// Arithmetic
register_builtin(&mut state.functions, "+", builtin_addition);
register_builtin(&mut state.functions, "-", builtin_subtraction);
register_builtin(&mut state.functions, "*", builtin_multiplication);
register_builtin(&mut state.functions, "/", builtin_division);
register_builtin(&mut state.functions, "%", builtin_modulus);
register_builtin(&mut state.functions, "^", builtin_exponential);
// Comparison
register_builtin(&mut state.functions, ">", builtin_greater_than);
register_builtin(&mut state.functions, ">=", builtin_greater_than_or_equal_to);
register_builtin(&mut state.functions, "<", builtin_less_than);
register_builtin(&mut state.functions, "<=", builtin_less_than_or_equal_to);
register_builtin(&mut state.functions, "==", builtin_equal_to);
register_builtin(&mut state.functions, "!=", builtin_not_equal_to);
// Math functions
register_builtin(&mut state.functions, "abs", builtin_abs);
register_builtin(&mut state.functions, "acos", builtin_acos);
register_builtin(&mut state.functions, "asin", builtin_asin);
register_builtin(&mut state.functions, "atan", builtin_atan);
register_builtin(&mut state.functions, "atan2", builtin_atan2);
register_builtin(&mut state.functions, "ceil", builtin_ceil);
register_builtin(&mut state.functions, "floor", builtin_floor);
register_builtin(&mut state.functions, "round", builtin_round);
register_builtin(&mut state.functions, "sqrt", builtin_sqrt);
register_builtin(&mut state.functions, "sin", builtin_sin);
register_builtin(&mut state.functions, "cos", builtin_cos);
register_builtin(&mut state.functions, "tan", builtin_tan);
register_builtin(&mut state.functions, "ln", builtin_ln);
register_builtin(&mut state.functions, "log", builtin_log);
// Logical
register_builtin(&mut state.functions, "and", builtin_and);
register_builtin(&mut state.functions, "or", builtin_or);
register_builtin(&mut state.functions, "not", builtin_not);
// Bitwise
register_builtin(&mut state.functions, "bitand", builtin_bitand);
register_builtin(&mut state.functions, "bitnot", builtin_bitnot);
register_builtin(&mut state.functions, "bitor", builtin_bitor);
register_builtin(&mut state.functions, "bitxor", builtin_bitxor);
register_builtin(&mut state.functions, "shl", builtin_shl);
register_builtin(&mut state.functions, "shr", builtin_shr);
// Stack operations
register_builtin(&mut state.functions, "depth", builtin_depth);
register_builtin(&mut state.functions, "drop", builtin_drop);
register_builtin(&mut state.functions, "dup", builtin_dup);
register_builtin(&mut state.functions, "swap", builtin_swap);
register_builtin(&mut state.functions, "pick", builtin_pick);
register_builtin(&mut state.functions, "roll", builtin_roll);
// Control flow
register_builtin(&mut state.functions, "if", builtin_if);
register_builtin(&mut state.functions, "while", builtin_while);
register_builtin(&mut state.functions, "for", builtin_for);
register_builtin(&mut state.functions, "lambda", builtin_lambda);
register_builtin(&mut state.functions, "eval", builtin_eval);
register_builtin(&mut state.functions, "const", builtin_const);
// Utility
register_builtin(&mut state.functions, "type_of", builtin_type_of);
register_builtin(&mut state.functions, "rand", builtin_rand);
register_builtin(&mut state.functions, "seed", builtin_seed);
// Load SLS-defined builtins
let builtin_code = r#"
// Kyler Olsen
// YREA SLS
// SLS Defined Builtin Operators
// November 2025
{ ln swap ln swap / } lambda ::logb const
{ 1 pick 1 pick < { swap drop } { drop } if } lambda ::max const
{ 1 pick 1 pick < { drop } { swap drop } if } lambda ::min const
{ 3 1 roll } lambda ::rot const
"#;
use crate::lexer::{LexerInfo, lexical_analysis};
let mut lexer = LexerInfo::new("__builtin.sls", builtin_code);
match lexical_analysis(&mut lexer) {
Ok(tokens) => {
for token in tokens {
if matches!(token, Token::Eof) {
break;
}
if !state.execute(&token) {
eprintln!("Error in __builtin.sls");
return false;
}
}
}
Err(e) => {
dbg!(e);
return false
}
}
true
}