from __future__ import annotations import math import random from typing import TYPE_CHECKING, Optional, Tuple if TYPE_CHECKING: from .interpreter import InterpreterState, StackEntry from .interpreter_types import StackType 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) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_64 | NumericTypeFlags.SIGNED elif entry.type == StackType.I32: ival = int(entry.value) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_32 | NumericTypeFlags.SIGNED elif entry.type == StackType.I16: ival = int(entry.value) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_16 | NumericTypeFlags.SIGNED elif entry.type == StackType.I8: ival = int(entry.value) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_8 | NumericTypeFlags.SIGNED elif entry.type == StackType.U64: ival = int(entry.value) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_64 elif entry.type == StackType.U32: ival = int(entry.value) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_32 elif entry.type == StackType.U16: ival = int(entry.value) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_16 elif entry.type == StackType.U8: ival = int(entry.value) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_8 elif entry.type == StackType.FLOAT: fval = float(entry.value) # type: ignore flags = NumericTypeFlags.BITS_32 | NumericTypeFlags.FLOAT elif entry.type == StackType.DOUBLE: fval = float(entry.value) # type: ignore flags = NumericTypeFlags.BITS_64 | NumericTypeFlags.FLOAT elif entry.type == StackType.CHARACTER: ival = int(entry.value) # type: ignore 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 # type: ignore 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) # type: ignore if val < 0: return None return val elif entry.type == StackType.I32: val = int(entry.value) # type: ignore if val < 0: return None return val elif entry.type == StackType.I16: val = int(entry.value) # type: ignore if val < 0: return None return val elif entry.type == StackType.I8: val = int(entry.value) # type: ignore if val < 0: return None return val elif entry.type in (StackType.U64, StackType.U32, StackType.U16, StackType.U8): return int(entry.value) # type: ignore elif entry.type == StackType.CHARACTER: return int(entry.value) # type: ignore 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() # type: ignore 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) # type: ignore state.push(b) # type: ignore 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() # type: ignore 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): # type: ignore return False if then_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): # type: ignore return False # Evaluate condition is_true = is_truthy(condition) # type: ignore # Execute appropriate block if is_true: block_to_execute = then_block else: block_to_execute = else_block if block_to_execute.type == StackType.IDENTIFIER: # type: ignore return state.execute_func(block_to_execute.value.name) # type: ignore else: return state.execute_token_string(block_to_execute.value) # type: ignore 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): # type: ignore return False if condition_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): # type: ignore return False while True: # Execute condition block if condition_block.type == StackType.IDENTIFIER: # type: ignore if not state.execute_func(condition_block.value.name): # type: ignore return False else: if not state.execute_token_string(condition_block.value): # type: ignore return False # Check result if len(state.stack) < 1: return False condition_result = state.pop() if not is_truthy(condition_result): # type: ignore break # Execute body block if body_block.type == StackType.IDENTIFIER: # type: ignore if not state.execute_func(body_block.value.name): # type: ignore return False else: if not state.execute_token_string(body_block.value): # type: ignore 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): # type: ignore return False start_val = get_scalar_value(start_item) # type: ignore end_val = get_scalar_value(end_item) # type: ignore 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: # type: ignore if not state.execute_func(body_block.value.name): # type: ignore return False else: if not state.execute_token_string(body_block.value): # type: ignore 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): # type: ignore return state.execute_token_string(code_target.value) # type: ignore elif code_target.type == StackType.IDENTIFIER: # type: ignore return state.execute_func(code_target.value.name) # type: ignore 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: # type: ignore return False if value_entry.type != StackType.CALLABLE: # type: ignore return False name = name_entry.value.name # type: ignore # Check if function already exists if state.get_function(name) is not None: return False # Create function item state.add_function(name, value_entry.value) # type: ignore 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") # type: ignore 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: """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(): interpreter_state.add_function(name, func) # 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