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 { 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 { 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::(); 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 { 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, 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 }