From 3a57fd7373fbe723484ad6f8b1f3b8b820c94be9 Mon Sep 17 00:00:00 2001 From: Kyler Date: Wed, 3 Dec 2025 23:43:32 -0700 Subject: [PATCH] Added builtin operators to python port --- SLS_Python/sls_py/builtin.py | 1268 +++++++++++++++++++++++++++++++++- 1 file changed, 1264 insertions(+), 4 deletions(-) diff --git a/SLS_Python/sls_py/builtin.py b/SLS_Python/sls_py/builtin.py index d8b9d23..93d56ba 100644 --- a/SLS_Python/sls_py/builtin.py +++ b/SLS_Python/sls_py/builtin.py @@ -1,9 +1,1269 @@ - -from typing import TYPE_CHECKING +from __future__ import annotations +import math +import random +from typing import TYPE_CHECKING, Optional, Tuple if TYPE_CHECKING: - from .interpreter import InterpreterState + from .interpreter import InterpreterState, StackEntry +from .interpreter import StackType, FunctionItem +from .lexer import Token, TokenType, IntegerLiteral, IntegerBuiltInType, Identifier + + +# ===================================================================== +# Helper Functions +# ===================================================================== + +class NumericTypeFlags: + """Flags to track numeric type properties""" + FLOAT = 1 << 0 + SIGNED = 1 << 1 + BITS_64 = 1 << 2 + BITS_32 = 1 << 3 + BITS_16 = 1 << 4 + BITS_8 = 1 << 5 + + +def extract_numeric_value(entry: "StackEntry") -> Optional[Tuple[float, int, int]]: + """ + Extract numeric value from stack entry. + Returns: (float_value, int_value, type_flags) or None if not numeric + """ + flags = 0 + fval = 0.0 + ival = 0 + + if entry.type == StackType.I64: + ival = int(entry.value) + fval = float(ival) + flags = NumericTypeFlags.BITS_64 | NumericTypeFlags.SIGNED + elif entry.type == StackType.I32: + ival = int(entry.value) + fval = float(ival) + flags = NumericTypeFlags.BITS_32 | NumericTypeFlags.SIGNED + elif entry.type == StackType.I16: + ival = int(entry.value) + fval = float(ival) + flags = NumericTypeFlags.BITS_16 | NumericTypeFlags.SIGNED + elif entry.type == StackType.I8: + ival = int(entry.value) + fval = float(ival) + flags = NumericTypeFlags.BITS_8 | NumericTypeFlags.SIGNED + elif entry.type == StackType.U64: + ival = int(entry.value) + fval = float(ival) + flags = NumericTypeFlags.BITS_64 + elif entry.type == StackType.U32: + ival = int(entry.value) + fval = float(ival) + flags = NumericTypeFlags.BITS_32 + elif entry.type == StackType.U16: + ival = int(entry.value) + fval = float(ival) + flags = NumericTypeFlags.BITS_16 + elif entry.type == StackType.U8: + ival = int(entry.value) + fval = float(ival) + flags = NumericTypeFlags.BITS_8 + elif entry.type == StackType.FLOAT: + fval = float(entry.value) + flags = NumericTypeFlags.BITS_32 | NumericTypeFlags.FLOAT + elif entry.type == StackType.DOUBLE: + fval = float(entry.value) + flags = NumericTypeFlags.BITS_64 | NumericTypeFlags.FLOAT + elif entry.type == StackType.CHARACTER: + ival = int(entry.value) + fval = float(ival) + flags = NumericTypeFlags.BITS_8 + elif entry.type == StackType.BOOLEAN: + ival = 1 if entry.value else 0 + fval = float(ival) + flags = NumericTypeFlags.BITS_8 + else: + return None + + return (fval, ival, flags) + + +def get_numeric_two(state: "InterpreterState") -> Optional[Tuple[float, float, int, int, int]]: + """ + Extract two numeric values from top of stack. + Returns: (fval_a, fval_b, ival_a, ival_b, combined_flags) or None + """ + if len(state.stack) < 2: + return None + + entry_a = state.stack[-1] + entry_b = state.stack[-2] + + result_a = extract_numeric_value(entry_a) + result_b = extract_numeric_value(entry_b) + + if result_a is None or result_b is None: + return None + + fval_a, ival_a, flags_a = result_a + fval_b, ival_b, flags_b = result_b + + # Combine flags (bitwise OR) + combined_flags = flags_a | flags_b + + return (fval_a, fval_b, ival_a, ival_b, combined_flags) + + +def get_numeric_one(state: "InterpreterState") -> Optional[Tuple[float, int, int]]: + """ + Extract one numeric value from top of stack. + Returns: (fval, ival, flags) or None + """ + if len(state.stack) < 1: + return None + + entry = state.stack[-1] + result = extract_numeric_value(entry) + + if result is None: + return None + + return result + + +def create_numeric_token(flags: int, fval: float, ival: int) -> Token: + """Create a token from numeric value based on type flags""" + if flags & NumericTypeFlags.FLOAT: + if flags & NumericTypeFlags.BITS_64: + return Token(type=TokenType.DOUBLE, double_literal=fval) + else: + return Token(type=TokenType.FLOAT, float_literal=float(fval)) + else: + # Integer type + if flags & NumericTypeFlags.SIGNED: + if flags & NumericTypeFlags.BITS_64: + int_type = IntegerBuiltInType.I64 + elif flags & NumericTypeFlags.BITS_32: + int_type = IntegerBuiltInType.I32 + elif flags & NumericTypeFlags.BITS_16: + int_type = IntegerBuiltInType.I16 + else: + int_type = IntegerBuiltInType.I8 + else: + if flags & NumericTypeFlags.BITS_64: + int_type = IntegerBuiltInType.U64 + elif flags & NumericTypeFlags.BITS_32: + int_type = IntegerBuiltInType.U32 + elif flags & NumericTypeFlags.BITS_16: + int_type = IntegerBuiltInType.U16 + else: + int_type = IntegerBuiltInType.U8 + + return Token( + type=TokenType.INTEGER, + integer_literal=IntegerLiteral(value=ival, type=int_type) + ) + + +def is_truthy(entry: "StackEntry") -> bool: + """Check if a stack entry is truthy""" + if entry.type == StackType.IDENTIFIER: + return False + elif entry.type in (StackType.I64, StackType.I32, StackType.I16, StackType.I8, + StackType.U64, StackType.U32, StackType.U16, StackType.U8): + return bool(entry.value) + elif entry.type in (StackType.FLOAT, StackType.DOUBLE): + return bool(entry.value) + elif entry.type == StackType.CHARACTER: + return bool(entry.value) + elif entry.type == StackType.BOOLEAN: + return bool(entry.value) + elif entry.type in (StackType.TOKEN_STRING, StackType.CALLABLE): + ts = entry.value + return len(ts.tokens) > 0 and ts.tokens[0].type != TokenType.EOF + return False + + +def get_scalar_value(entry: "StackEntry") -> Optional[int]: + """Extract a scalar (non-negative integer) value from stack entry""" + if entry.type == StackType.I64: + val = int(entry.value) + if val < 0: + return None + return val + elif entry.type == StackType.I32: + val = int(entry.value) + if val < 0: + return None + return val + elif entry.type == StackType.I16: + val = int(entry.value) + if val < 0: + return None + return val + elif entry.type == StackType.I8: + val = int(entry.value) + if val < 0: + return None + return val + elif entry.type in (StackType.U64, StackType.U32, StackType.U16, StackType.U8): + return int(entry.value) + elif entry.type == StackType.CHARACTER: + return int(entry.value) + elif entry.type == StackType.BOOLEAN: + return 1 if entry.value else 0 + else: + return None + + +# ===================================================================== +# Arithmetic Operations +# ===================================================================== + +def builtin_addition(state: "InterpreterState") -> bool: + """Add two numeric values""" + result = get_numeric_two(state) + if result is None: + return False + + fval_a, fval_b, ival_a, ival_b, flags = result + state.pop() + state.pop() + + if flags & NumericTypeFlags.FLOAT: + result_val = fval_b + fval_a + token = create_numeric_token(flags, result_val, 0) + else: + result_val = ival_b + ival_a + token = create_numeric_token(flags, 0.0, result_val) + + return state.push_token(token) + + +def builtin_subtraction(state: "InterpreterState") -> bool: + """Subtract two numeric values""" + result = get_numeric_two(state) + if result is None: + return False + + fval_a, fval_b, ival_a, ival_b, flags = result + state.pop() + state.pop() + + if flags & NumericTypeFlags.FLOAT: + result_val = fval_b - fval_a + token = create_numeric_token(flags, result_val, 0) + else: + result_val = ival_b - ival_a + token = create_numeric_token(flags, 0.0, result_val) + + return state.push_token(token) + + +def builtin_multiplication(state: "InterpreterState") -> bool: + """Multiply two numeric values""" + result = get_numeric_two(state) + if result is None: + return False + + fval_a, fval_b, ival_a, ival_b, flags = result + state.pop() + state.pop() + + if flags & NumericTypeFlags.FLOAT: + result_val = fval_b * fval_a + token = create_numeric_token(flags, result_val, 0) + else: + result_val = ival_b * ival_a + token = create_numeric_token(flags, 0.0, result_val) + + return state.push_token(token) + + +def builtin_division(state: "InterpreterState") -> bool: + """Divide two numeric values (always returns float)""" + result = get_numeric_two(state) + if result is None: + return False + + fval_a, fval_b, _, _, _ = result + + if fval_a == 0: + return False + + state.pop() + state.pop() + + result_val = fval_b / fval_a + return state.push_token(Token(type=TokenType.DOUBLE, double_literal=result_val)) + + +def builtin_modulus(state: "InterpreterState") -> bool: + """Modulo operation (integers only)""" + result = get_numeric_two(state) + if result is None: + return False + + _, _, ival_a, ival_b, flags = result + + if flags & NumericTypeFlags.FLOAT: + return False + + if ival_a == 0: + return False + + state.pop() + state.pop() + + result_val = ival_b % ival_a + token = create_numeric_token(flags, 0.0, result_val) + return state.push_token(token) + + +def builtin_exponential(state: "InterpreterState") -> bool: + """Exponentiation (always returns float)""" + result = get_numeric_two(state) + if result is None: + return False + + fval_a, fval_b, _, _, _ = result + state.pop() + state.pop() + + result_val = math.pow(fval_b, fval_a) + return state.push_token(Token(type=TokenType.DOUBLE, double_literal=result_val)) + + +# ===================================================================== +# Comparison Operations +# ===================================================================== + +def builtin_greater_than(state: "InterpreterState") -> bool: + """Greater than comparison""" + result = get_numeric_two(state) + if result is None: + return False + + fval_a, fval_b, _, _, _ = result + state.pop() + state.pop() + + return state.push_token(Token(type=TokenType.BOOLEAN, boolean_literal=fval_b > fval_a)) + + +def builtin_greater_than_or_equal_to(state: "InterpreterState") -> bool: + """Greater than or equal comparison""" + result = get_numeric_two(state) + if result is None: + return False + + fval_a, fval_b, _, _, _ = result + state.pop() + state.pop() + + return state.push_token(Token(type=TokenType.BOOLEAN, boolean_literal=fval_b >= fval_a)) + + +def builtin_less_than(state: "InterpreterState") -> bool: + """Less than comparison""" + result = get_numeric_two(state) + if result is None: + return False + + fval_a, fval_b, _, _, _ = result + state.pop() + state.pop() + + return state.push_token(Token(type=TokenType.BOOLEAN, boolean_literal=fval_b < fval_a)) + + +def builtin_less_than_or_equal_to(state: "InterpreterState") -> bool: + """Less than or equal comparison""" + result = get_numeric_two(state) + if result is None: + return False + + fval_a, fval_b, _, _, _ = result + state.pop() + state.pop() + + return state.push_token(Token(type=TokenType.BOOLEAN, boolean_literal=fval_b <= fval_a)) + + +def builtin_equal_to(state: "InterpreterState") -> bool: + """Equality comparison""" + result = get_numeric_two(state) + if result is None: + return False + + fval_a, fval_b, _, _, _ = result + state.pop() + state.pop() + + return state.push_token(Token(type=TokenType.BOOLEAN, boolean_literal=fval_b == fval_a)) + + +def builtin_not_equal_to(state: "InterpreterState") -> bool: + """Inequality comparison""" + result = get_numeric_two(state) + if result is None: + return False + + fval_a, fval_b, _, _, _ = result + state.pop() + state.pop() + + return state.push_token(Token(type=TokenType.BOOLEAN, boolean_literal=fval_b != fval_a)) + + +# ===================================================================== +# Mathematical Functions +# ===================================================================== + +def builtin_abs(state: "InterpreterState") -> bool: + """Absolute value""" + result = get_numeric_one(state) + if result is None: + return False + + fval, ival, flags = result + + # Only works on signed types or floats + if not ((flags & NumericTypeFlags.SIGNED) or (flags & NumericTypeFlags.FLOAT)): + return False + + state.pop() + + if flags & NumericTypeFlags.FLOAT: + result_val = abs(fval) + token = create_numeric_token(flags, result_val, 0) + else: + result_val = abs(ival) + token = create_numeric_token(flags, 0.0, result_val) + + return state.push_token(token) + + +def builtin_sqrt(state: "InterpreterState") -> bool: + """Square root""" + result = get_numeric_one(state) + if result is None: + return False + + fval, _, _ = result + + if fval < 0: + return False + + state.pop() + return state.push_token(Token(type=TokenType.DOUBLE, double_literal=math.sqrt(fval))) + + +def builtin_sin(state: "InterpreterState") -> bool: + """Sine function""" + result = get_numeric_one(state) + if result is None: + return False + + fval, _, _ = result + state.pop() + + return state.push_token(Token(type=TokenType.DOUBLE, double_literal=math.sin(fval))) + + +def builtin_cos(state: "InterpreterState") -> bool: + """Cosine function""" + result = get_numeric_one(state) + if result is None: + return False + + fval, _, _ = result + state.pop() + + return state.push_token(Token(type=TokenType.DOUBLE, double_literal=math.cos(fval))) + + +def builtin_tan(state: "InterpreterState") -> bool: + """Tangent function""" + result = get_numeric_one(state) + if result is None: + return False + + fval, _, _ = result + state.pop() + + return state.push_token(Token(type=TokenType.DOUBLE, double_literal=math.tan(fval))) + + +def builtin_asin(state: "InterpreterState") -> bool: + """Arc sine function""" + result = get_numeric_one(state) + if result is None: + return False + + fval, _, _ = result + + if fval < -1 or fval > 1: + return False + + state.pop() + return state.push_token(Token(type=TokenType.DOUBLE, double_literal=math.asin(fval))) + + +def builtin_acos(state: "InterpreterState") -> bool: + """Arc cosine function""" + result = get_numeric_one(state) + if result is None: + return False + + fval, _, _ = result + + if fval < -1 or fval > 1: + return False + + state.pop() + return state.push_token(Token(type=TokenType.DOUBLE, double_literal=math.acos(fval))) + + +def builtin_atan(state: "InterpreterState") -> bool: + """Arc tangent function""" + result = get_numeric_one(state) + if result is None: + return False + + fval, _, _ = result + state.pop() + + return state.push_token(Token(type=TokenType.DOUBLE, double_literal=math.atan(fval))) + + +def builtin_atan2(state: "InterpreterState") -> bool: + """Two-argument arc tangent function""" + result = get_numeric_two(state) + if result is None: + return False + + fval_a, fval_b, _, _, _ = result + state.pop() + state.pop() + + return state.push_token(Token(type=TokenType.DOUBLE, double_literal=math.atan2(fval_b, fval_a))) + + +def builtin_floor(state: "InterpreterState") -> bool: + """Floor function""" + result = get_numeric_one(state) + if result is None: + return False + + fval, _, _ = result + state.pop() + + return state.push_token(Token(type=TokenType.DOUBLE, double_literal=math.floor(fval))) + + +def builtin_ceil(state: "InterpreterState") -> bool: + """Ceiling function""" + result = get_numeric_one(state) + if result is None: + return False + + fval, _, _ = result + state.pop() + + return state.push_token(Token(type=TokenType.DOUBLE, double_literal=math.ceil(fval))) + + +def builtin_round(state: "InterpreterState") -> bool: + """Round function""" + result = get_numeric_one(state) + if result is None: + return False + + fval, _, _ = result + state.pop() + + return state.push_token(Token(type=TokenType.DOUBLE, double_literal=round(fval))) + + +def builtin_ln(state: "InterpreterState") -> bool: + """Natural logarithm""" + result = get_numeric_one(state) + if result is None: + return False + + fval, _, _ = result + + if fval <= 0: + return False + + state.pop() + return state.push_token(Token(type=TokenType.DOUBLE, double_literal=math.log(fval))) + + +def builtin_log(state: "InterpreterState") -> bool: + """Base-10 logarithm""" + result = get_numeric_one(state) + if result is None: + return False + + fval, _, _ = result + + if fval <= 0: + return False + + state.pop() + return state.push_token(Token(type=TokenType.DOUBLE, double_literal=math.log10(fval))) + + +# ===================================================================== +# Logical Operations +# ===================================================================== + +def builtin_and(state: "InterpreterState") -> bool: + """Logical AND""" + result = get_numeric_two(state) + if result is None: + return False + + fval_a, fval_b, ival_a, ival_b, flags = result + state.pop() + state.pop() + + if flags & NumericTypeFlags.FLOAT: + result_val = bool(fval_b and fval_a) + else: + result_val = bool(ival_b and ival_a) + + return state.push_token(Token(type=TokenType.BOOLEAN, boolean_literal=result_val)) + + +def builtin_or(state: "InterpreterState") -> bool: + """Logical OR""" + result = get_numeric_two(state) + if result is None: + return False + + fval_a, fval_b, ival_a, ival_b, flags = result + state.pop() + state.pop() + + if flags & NumericTypeFlags.FLOAT: + result_val = bool(fval_b or fval_a) + else: + result_val = bool(ival_b or ival_a) + + return state.push_token(Token(type=TokenType.BOOLEAN, boolean_literal=result_val)) + + +def builtin_not(state: "InterpreterState") -> bool: + """Logical NOT""" + result = get_numeric_one(state) + if result is None: + return False + + fval, ival, flags = result + state.pop() + + if flags & NumericTypeFlags.FLOAT: + result_val = not bool(fval) + else: + result_val = not bool(ival) + + return state.push_token(Token(type=TokenType.BOOLEAN, boolean_literal=result_val)) + + +# ===================================================================== +# Bitwise Operations +# ===================================================================== + +def builtin_bitand(state: "InterpreterState") -> bool: + """Bitwise AND""" + result = get_numeric_two(state) + if result is None: + return False + + _, _, ival_a, ival_b, flags = result + + if flags & NumericTypeFlags.FLOAT: + return False + + state.pop() + state.pop() + + result_val = ival_b & ival_a + token = create_numeric_token(flags, 0.0, result_val) + return state.push_token(token) + + +def builtin_bitor(state: "InterpreterState") -> bool: + """Bitwise OR""" + result = get_numeric_two(state) + if result is None: + return False + + _, _, ival_a, ival_b, flags = result + + if flags & NumericTypeFlags.FLOAT: + return False + + state.pop() + state.pop() + + result_val = ival_b | ival_a + token = create_numeric_token(flags, 0.0, result_val) + return state.push_token(token) + + +def builtin_bitxor(state: "InterpreterState") -> bool: + """Bitwise XOR""" + result = get_numeric_two(state) + if result is None: + return False + + _, _, ival_a, ival_b, flags = result + + if flags & NumericTypeFlags.FLOAT: + return False + + state.pop() + state.pop() + + result_val = ival_b ^ ival_a + token = create_numeric_token(flags, 0.0, result_val) + return state.push_token(token) + + +def builtin_bitnot(state: "InterpreterState") -> bool: + """Bitwise NOT""" + result = get_numeric_one(state) + if result is None: + return False + + _, ival, flags = result + + if flags & NumericTypeFlags.FLOAT: + return False + + state.pop() + + result_val = ~ival + token = create_numeric_token(flags, 0.0, result_val) + return state.push_token(token) + + +def builtin_shl(state: "InterpreterState") -> bool: + """Bitwise left shift""" + result = get_numeric_two(state) + if result is None: + return False + + _, _, ival_a, ival_b, flags = result + + if flags & NumericTypeFlags.FLOAT: + return False + + state.pop() + state.pop() + + result_val = ival_b << ival_a + token = create_numeric_token(flags, 0.0, result_val) + return state.push_token(token) + + +def builtin_shr(state: "InterpreterState") -> bool: + """Bitwise right shift""" + result = get_numeric_two(state) + if result is None: + return False + + _, _, ival_a, ival_b, flags = result + + if flags & NumericTypeFlags.FLOAT: + return False + + state.pop() + state.pop() + + result_val = ival_b >> ival_a + token = create_numeric_token(flags, 0.0, result_val) + return state.push_token(token) + + +# ===================================================================== +# Stack Operations +# ===================================================================== + +def builtin_dup(state: "InterpreterState") -> bool: + """Duplicate top stack item""" + if len(state.stack) < 1: + return False + + top = state.stack[-1] + + # Deep copy for token strings + if top.type in (StackType.TOKEN_STRING, StackType.CALLABLE): + value_copy = top.value.deep_copy() + else: + value_copy = top.value + + from .interpreter import StackEntry + state.push(StackEntry(type=top.type, value=value_copy)) + return True + + +def builtin_drop(state: "InterpreterState") -> bool: + """Drop top stack item""" + if len(state.stack) < 1: + return False + + state.pop() + return True + + +def builtin_swap(state: "InterpreterState") -> bool: + """Swap top two stack items""" + if len(state.stack) < 2: + return False + + a = state.pop() + b = state.pop() + state.push(a) + state.push(b) + return True + + +def builtin_depth(state: "InterpreterState") -> bool: + """Push stack depth""" + depth = len(state.stack) + return state.push_token(Token( + type=TokenType.INTEGER, + integer_literal=IntegerLiteral(value=depth, type=IntegerBuiltInType.U64) + )) + + +def builtin_pick(state: "InterpreterState") -> bool: + """Copy nth item to top (0 = top)""" + if len(state.stack) < 1: + return False + + result = get_numeric_one(state) + if result is None: + return False + + _, ival, flags = result + + if flags & NumericTypeFlags.FLOAT: + return False + + n = int(ival) + + if n < 0 or n >= len(state.stack) - 1: + return False + + state.pop() # Remove the index + + # Pick from stack (0 = current top, 1 = one below, etc.) + picked_idx = len(state.stack) - 1 - n + if picked_idx < 0: + return False + + picked = state.stack[picked_idx] + + # Deep copy for token strings + if picked.type in (StackType.TOKEN_STRING, StackType.CALLABLE): + value_copy = picked.value.deep_copy() + else: + value_copy = picked.value + + from .interpreter import StackEntry + state.push(StackEntry(type=picked.type, value=value_copy)) + return True + + +def builtin_roll(state: "InterpreterState") -> bool: + """Rotate top n items, times times""" + if len(state.stack) < 2: + return False + + times_entry = state.stack[-1] + count_entry = state.stack[-2] + + times_val = get_scalar_value(times_entry) + count_val = get_scalar_value(count_entry) + + if times_val is None or count_val is None: + return False + + if count_val <= 0: + state.pop() + state.pop() + return True + + if count_val > len(state.stack) - 2: + return False + + state.pop() + state.pop() + + # Extract the top count_val items + items = [] + for _ in range(count_val): + if len(state.stack) < 1: + return False + items.append(state.pop()) + + items.reverse() # Reverse to get proper order + + # Rotate items by times_val + times_val = times_val % len(items) if len(items) > 0 else 0 + rotated = items[times_val:] + items[:times_val] + + # Push back in reverse order + for item in reversed(rotated): + state.push(item) + + return True + + +# ===================================================================== +# Control Flow Operations +# ===================================================================== + +def builtin_if(state: "InterpreterState") -> bool: + """Conditional execution: condition then_block else_block if""" + if len(state.stack) < 3: + return False + + else_block = state.pop() + then_block = state.pop() + condition = state.pop() + + # Check that blocks are executable + if else_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): + return False + if then_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): + return False + + # Evaluate condition + is_true = is_truthy(condition) + + # Execute appropriate block + if is_true: + block_to_execute = then_block + else: + block_to_execute = else_block + + if block_to_execute.type == StackType.IDENTIFIER: + return state.execute_func(block_to_execute.value.name) + else: + return state.execute_token_string(block_to_execute.value) + + +def builtin_while(state: "InterpreterState") -> bool: + """While loop: condition_block body_block while""" + if len(state.stack) < 2: + return False + + body_block = state.pop() + condition_block = state.pop() + + # Check that blocks are executable + if body_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): + return False + if condition_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): + return False + + while True: + # Execute condition block + if condition_block.type == StackType.IDENTIFIER: + if not state.execute_func(condition_block.value.name): + return False + else: + if not state.execute_token_string(condition_block.value): + return False + + # Check result + if len(state.stack) < 1: + return False + + condition_result = state.pop() + if not is_truthy(condition_result): + break + + # Execute body block + if body_block.type == StackType.IDENTIFIER: + if not state.execute_func(body_block.value.name): + return False + else: + if not state.execute_token_string(body_block.value): + return False + + return True + + +def builtin_for(state: "InterpreterState") -> bool: + """For loop: start end body_block for""" + if len(state.stack) < 3: + return False + + body_block = state.pop() + end_item = state.pop() + start_item = state.pop() + + # Check that block is executable + if body_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): + return False + + start_val = get_scalar_value(start_item) + end_val = get_scalar_value(end_item) + + if start_val is None or end_val is None: + return False + + # Execute loop + for i in range(start_val, end_val): + # Push counter + if not state.push_token(Token( + type=TokenType.INTEGER, + integer_literal=IntegerLiteral(value=i, type=IntegerBuiltInType.I64) + )): + return False + + # Execute body + if body_block.type == StackType.IDENTIFIER: + if not state.execute_func(body_block.value.name): + return False + else: + if not state.execute_token_string(body_block.value): + return False + + return True + + +# ===================================================================== +# Special Operations +# ===================================================================== + +def builtin_eval(state: "InterpreterState") -> bool: + """Evaluate code block or identifier""" + if len(state.stack) < 1: + return False + + code_target = state.pop() + + if code_target.type in (StackType.TOKEN_STRING, StackType.CALLABLE): + return state.execute_token_string(code_target.value) + elif code_target.type == StackType.IDENTIFIER: + return state.execute_func(code_target.value.name) + else: + return False + + +def builtin_lambda(state: "InterpreterState") -> bool: + """Convert token string to callable""" + if len(state.stack) < 1: + return False + + if state.stack[-1].type != StackType.TOKEN_STRING: + return False + + state.stack[-1].type = StackType.CALLABLE + return True + + +def builtin_const(state: "InterpreterState") -> bool: + """Define a constant: value ::name const""" + if len(state.stack) < 2: + return False + + name_entry = state.pop() + value_entry = state.pop() + + if name_entry.type != StackType.IDENTIFIER: + return False + + if value_entry.type != StackType.CALLABLE: + return False + + name = name_entry.value.name + + # Check if function already exists + if state.get_function(name) is not None: + return False + + # Create function item + func_item = FunctionItem.from_token_string(value_entry.value) + state.add_function(name, func_item) + + return True + + +def builtin_type_of(state: "InterpreterState") -> bool: + """Get the type of the top stack item""" + if len(state.stack) < 1: + return False + + item = state.pop() + + # Map stack type to type name + type_names = { + StackType.IDENTIFIER: "Identifier", + StackType.I64: "i64", + StackType.I32: "i32", + StackType.I16: "i16", + StackType.I8: "i8", + StackType.U64: "u64", + StackType.U32: "u32", + StackType.U16: "u16", + StackType.U8: "u8", + StackType.FLOAT: "f32", + StackType.DOUBLE: "f64", + StackType.CHARACTER: "char", + StackType.BOOLEAN: "bool", + StackType.TOKEN_STRING: "TokenString", + StackType.CALLABLE: "Callable", + } + + type_name = type_names.get(item.type, "Unknown") + + return state.push_token(Token( + type=TokenType.IDENTIFIER, + identifier=Identifier(name=type_name, is_literal=True) + )) + + +# ===================================================================== +# Random Number Operations +# ===================================================================== + +def builtin_rand(state: "InterpreterState") -> bool: + """Generate random number [0.0, 1.0)""" + return state.push_token(Token(type=TokenType.DOUBLE, double_literal=random.random())) + + +def builtin_seed(state: "InterpreterState") -> bool: + """Seed random number generator""" + result = get_numeric_one(state) + if result is None: + return False + + _, ival, flags = result + + if flags & NumericTypeFlags.FLOAT: + return False + + state.pop() + random.seed(ival) + return True + + +# ===================================================================== +# Load Builtins +# ===================================================================== def load_builtins(interpreter_state: "InterpreterState") -> bool: - return True + """Load all builtin functions into the interpreter state""" + + builtins = { + # Arithmetic + "+": builtin_addition, + "-": builtin_subtraction, + "*": builtin_multiplication, + "/": builtin_division, + "%": builtin_modulus, + "^": builtin_exponential, + + # Comparison + ">": builtin_greater_than, + ">=": builtin_greater_than_or_equal_to, + "<": builtin_less_than, + "<=": builtin_less_than_or_equal_to, + "==": builtin_equal_to, + "!=": builtin_not_equal_to, + + # Mathematical functions + "abs": builtin_abs, + "sqrt": builtin_sqrt, + "sin": builtin_sin, + "cos": builtin_cos, + "tan": builtin_tan, + "asin": builtin_asin, + "acos": builtin_acos, + "atan": builtin_atan, + "atan2": builtin_atan2, + "floor": builtin_floor, + "ceil": builtin_ceil, + "round": builtin_round, + "ln": builtin_ln, + "log": builtin_log, + + # Logical + "and": builtin_and, + "or": builtin_or, + "not": builtin_not, + + # Bitwise + "bitand": builtin_bitand, + "bitor": builtin_bitor, + "bitxor": builtin_bitxor, + "bitnot": builtin_bitnot, + "shl": builtin_shl, + "shr": builtin_shr, + + # Stack operations + "dup": builtin_dup, + "drop": builtin_drop, + "swap": builtin_swap, + "depth": builtin_depth, + "pick": builtin_pick, + "roll": builtin_roll, + + # Control flow + "if": builtin_if, + "while": builtin_while, + "for": builtin_for, + + # Special + "eval": builtin_eval, + "lambda": builtin_lambda, + "const": builtin_const, + "type_of": builtin_type_of, + + # Random + "rand": builtin_rand, + "seed": builtin_seed, + } + + # Register all builtins + for name, func in builtins.items(): + func_item = FunctionItem.from_builtin(func) + interpreter_state.add_function(name, func_item) + + # Load SLS-defined builtins + try: + from .lexer import LexerInfo, lexical_analysis + + builtin_code = """ +// 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 +""" + + lexer_info = LexerInfo("__builtin.sls", builtin_code) + tokens = lexical_analysis(lexer_info) + + for token in tokens: + if token.type == TokenType.EOF: + break + if not interpreter_state.execute(token): + return False + + return True + + except Exception as e: + print(f"Failed to load builtin definitions: {e}") + return False