diff --git a/SLS_Rust/sls/Cargo.toml b/SLS_Rust/sls/Cargo.toml index 2647058..012605c 100644 --- a/SLS_Rust/sls/Cargo.toml +++ b/SLS_Rust/sls/Cargo.toml @@ -1,9 +1,11 @@ [package] name = "sls" -version = "0.1.0" +version = "0.0.1-alpha" edition = "2021" [dependencies] +bitflags = "2.4" +rand = "0.8" [build-dependencies] rustc_version = "0.4" diff --git a/SLS_Rust/sls/core b/SLS_Rust/sls/core new file mode 100644 index 0000000..d863bd6 Binary files /dev/null and b/SLS_Rust/sls/core differ diff --git a/SLS_Rust/sls/src/builtin.rs b/SLS_Rust/sls/src/builtin.rs index 5a2fed6..2e67d40 100644 --- a/SLS_Rust/sls/src/builtin.rs +++ b/SLS_Rust/sls/src/builtin.rs @@ -1,5 +1,1108 @@ -use crate::interpreter::InterpreterState; +use crate::interpreter::{InterpreterState, StackValue, FunctionItem}; +use crate::lexer::{Token, Identifier}; +use std::collections::HashMap; -pub fn load_builtins(_state: &mut InterpreterState) -> bool { - false +// 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.drain(0..2); + + 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.drain(0..2); + + 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.drain(0..2); + + 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.drain(0..2); + 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.drain(0..2); + + 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.drain(0..2); + 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.drain(0..2); + 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.drain(0..2); + 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.drain(0..2); + 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.drain(0..2); + 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.drain(0..2); + 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.drain(0..2); + 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(val) = extract_numeric_type(&state.stack[state.stack.len()-1]) 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(val) = extract_numeric_type(&state.stack[state.stack.len()-1]) 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.drain(0..2); + + 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(val) = extract_numeric_type(&state.stack[state.stack.len()-1]) 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(val) = extract_numeric_type(&state.stack[state.stack.len()-1]) 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.drain(0..2); + 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.drain(0..2); + 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(val) = extract_numeric_type(&state.stack[state.stack.len()-1]) 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.drain(0..2); + 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.drain(0..2); + 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(val) = extract_numeric_type(&state.stack[state.stack.len()-1]) 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(val) = extract_numeric_type(&state.stack[state.stack.len()-1]) 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(val) = extract_numeric_type(&state.stack[state.stack.len()-1]) 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(val) = extract_numeric_type(&state.stack[state.stack.len()-1]) 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(val) = extract_numeric_type(&state.stack[state.stack.len()-1]) 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(val) = extract_numeric_type(&state.stack[state.stack.len()-1]) 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(val) = extract_numeric_type(&state.stack[state.stack.len()-1]) 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(val) = extract_numeric_type(&state.stack[state.stack.len()-1]) 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(val) = extract_numeric_type(&state.stack[state.stack.len()-1]) 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.drain(0..2); + + // 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.drain(0..2); + + 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.drain(0..2); + 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.drain(0..2); + 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(val) = extract_numeric_type(&state.stack[state.stack.len()-1]) 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.drain(0..3); + + 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.drain(0..2); + + 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.drain(0..3); + + 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.drain(0..2); + + 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 +} + +// 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(func)); +} + +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) { + println!("Error in __builtin.sls"); + return false; + } + } + } + Err(e) => { + dbg!(e); + return false + } + } + + true } diff --git a/SLS_Rust/sls/src/file.rs b/SLS_Rust/sls/src/file.rs index 4b016fd..4ee584d 100644 --- a/SLS_Rust/sls/src/file.rs +++ b/SLS_Rust/sls/src/file.rs @@ -21,7 +21,7 @@ pub fn exec_file(interpreter: &mut InterpreterState, filename: &str) -> bool { match result { LexResult::Ok(tokens) => { for token in tokens { - if !interpreter.execute(token) { + if !interpreter.execute(&token) { return false; } } diff --git a/SLS_Rust/sls/src/interpreter.rs b/SLS_Rust/sls/src/interpreter.rs index ae4ee2d..5c8e4e1 100644 --- a/SLS_Rust/sls/src/interpreter.rs +++ b/SLS_Rust/sls/src/interpreter.rs @@ -27,7 +27,7 @@ pub enum StackValue { TokenString(TokenString), - Callable(FunctionItem), + Callable(TokenString), } #[derive(Debug, Clone)] @@ -54,31 +54,31 @@ impl InterpreterState { load_builtins(self) } - pub fn push_token(&mut self, token: Token) -> bool { + pub fn push_token(&mut self, token: &Token) -> bool { let value = match token { Token::Eof => return true, Token::Identifier(id) => { - StackValue::Identifier(id) + StackValue::Identifier(id.clone()) } - Token::I64(v) => StackValue::I64(v), - Token::I32(v) => StackValue::I32(v), - Token::I16(v) => StackValue::I16(v), - Token::I8(v) => StackValue::I8(v), + Token::I64(v) => StackValue::I64(*v), + Token::I32(v) => StackValue::I32(*v), + Token::I16(v) => StackValue::I16(*v), + Token::I8(v) => StackValue::I8(*v), - Token::U64(v) => StackValue::U64(v), - Token::U32(v) => StackValue::U32(v), - Token::U16(v) => StackValue::U16(v), - Token::U8(v) => StackValue::U8(v), + Token::U64(v) => StackValue::U64(*v), + Token::U32(v) => StackValue::U32(*v), + Token::U16(v) => StackValue::U16(*v), + Token::U8(v) => StackValue::U8(*v), - Token::Float(v) => StackValue::F32(v), - Token::Double(v) => StackValue::F64(v), + Token::Float(v) => StackValue::F32(*v), + Token::Double(v) => StackValue::F64(*v), - Token::Character(c) => StackValue::Character(c), - Token::Boolean(b) => StackValue::Boolean(b), + Token::Character(c) => StackValue::Character(*c), + Token::Boolean(b) => StackValue::Boolean(*b), - Token::TokenString(ts) => StackValue::TokenString(ts), + Token::TokenString(ts) => StackValue::TokenString(ts.clone()), Token::StringLiteral(_) | Token::Array(_) | @@ -97,12 +97,12 @@ impl InterpreterState { match item { FunctionItem::Builtin(f) => f(self), - FunctionItem::TokenString(ts) => self.execute_token_string(ts), + FunctionItem::TokenString(ts) => self.execute_token_string(&ts), } } - pub fn execute_token_string(&mut self, ts: TokenString) -> bool { - for token in ts.tokens { + pub fn execute_token_string(&mut self, ts: &TokenString) -> bool { + for token in &ts.tokens { if let Token::Identifier(id) = &token { if !id.is_literal { if !self.execute_func(&id.name) { @@ -112,14 +112,14 @@ impl InterpreterState { } } - if !self.push_token(token) { + if !self.push_token(&token) { return false; } } true } - pub fn execute(&mut self, token: Token) -> bool { + pub fn execute(&mut self, token: &Token) -> bool { match token { Token::Identifier(id) if !id.is_literal => { self.execute_func(&id.name) diff --git a/SLS_Rust/sls/src/repl.rs b/SLS_Rust/sls/src/repl.rs index c78b658..46c4b53 100644 --- a/SLS_Rust/sls/src/repl.rs +++ b/SLS_Rust/sls/src/repl.rs @@ -69,7 +69,7 @@ pub fn repl() -> i32 { match result { LexResult::Ok(tokens) => { for token in tokens { - if !interpreter.execute(token) { + if !interpreter.execute(&token) { println!("A runtime error occured!"); break; }