diff --git a/SLS_Python/sls_py/builtin.py b/SLS_Python/sls_py/builtin.py index 93d56ba..bf24977 100644 --- a/SLS_Python/sls_py/builtin.py +++ b/SLS_Python/sls_py/builtin.py @@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, Optional, Tuple if TYPE_CHECKING: from .interpreter import InterpreterState, StackEntry -from .interpreter import StackType, FunctionItem +from .interpreter_types import StackType from .lexer import Token, TokenType, IntegerLiteral, IntegerBuiltInType, Identifier @@ -34,45 +34,45 @@ def extract_numeric_value(entry: "StackEntry") -> Optional[Tuple[float, int, int ival = 0 if entry.type == StackType.I64: - ival = int(entry.value) + ival = int(entry.value) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_64 | NumericTypeFlags.SIGNED elif entry.type == StackType.I32: - ival = int(entry.value) + ival = int(entry.value) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_32 | NumericTypeFlags.SIGNED elif entry.type == StackType.I16: - ival = int(entry.value) + ival = int(entry.value) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_16 | NumericTypeFlags.SIGNED elif entry.type == StackType.I8: - ival = int(entry.value) + ival = int(entry.value) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_8 | NumericTypeFlags.SIGNED elif entry.type == StackType.U64: - ival = int(entry.value) + ival = int(entry.value) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_64 elif entry.type == StackType.U32: - ival = int(entry.value) + ival = int(entry.value) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_32 elif entry.type == StackType.U16: - ival = int(entry.value) + ival = int(entry.value) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_16 elif entry.type == StackType.U8: - ival = int(entry.value) + ival = int(entry.value) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_8 elif entry.type == StackType.FLOAT: - fval = float(entry.value) + fval = float(entry.value) # type: ignore flags = NumericTypeFlags.BITS_32 | NumericTypeFlags.FLOAT elif entry.type == StackType.DOUBLE: - fval = float(entry.value) + fval = float(entry.value) # type: ignore flags = NumericTypeFlags.BITS_64 | NumericTypeFlags.FLOAT elif entry.type == StackType.CHARACTER: - ival = int(entry.value) + ival = int(entry.value) # type: ignore fval = float(ival) flags = NumericTypeFlags.BITS_8 elif entry.type == StackType.BOOLEAN: @@ -177,36 +177,36 @@ def is_truthy(entry: "StackEntry") -> bool: 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 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) + val = int(entry.value) # type: ignore if val < 0: return None return val elif entry.type == StackType.I32: - val = int(entry.value) + val = int(entry.value) # type: ignore if val < 0: return None return val elif entry.type == StackType.I16: - val = int(entry.value) + val = int(entry.value) # type: ignore if val < 0: return None return val elif entry.type == StackType.I8: - val = int(entry.value) + 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) + return int(entry.value) # type: ignore elif entry.type == StackType.CHARACTER: - return int(entry.value) + return int(entry.value) # type: ignore elif entry.type == StackType.BOOLEAN: return 1 if entry.value else 0 else: @@ -800,7 +800,7 @@ def builtin_dup(state: "InterpreterState") -> bool: # Deep copy for token strings if top.type in (StackType.TOKEN_STRING, StackType.CALLABLE): - value_copy = top.value.deep_copy() + value_copy = top.value.deep_copy() # type: ignore else: value_copy = top.value @@ -825,8 +825,8 @@ def builtin_swap(state: "InterpreterState") -> bool: a = state.pop() b = state.pop() - state.push(a) - state.push(b) + state.push(a) # type: ignore + state.push(b) # type: ignore return True @@ -869,7 +869,7 @@ def builtin_pick(state: "InterpreterState") -> bool: # Deep copy for token strings if picked.type in (StackType.TOKEN_STRING, StackType.CALLABLE): - value_copy = picked.value.deep_copy() + value_copy = picked.value.deep_copy() # type: ignore else: value_copy = picked.value @@ -937,13 +937,13 @@ def builtin_if(state: "InterpreterState") -> bool: condition = state.pop() # Check that blocks are executable - if else_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): + 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): + if then_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): # type: ignore return False # Evaluate condition - is_true = is_truthy(condition) + is_true = is_truthy(condition) # type: ignore # Execute appropriate block if is_true: @@ -951,10 +951,10 @@ def builtin_if(state: "InterpreterState") -> bool: else: block_to_execute = else_block - if block_to_execute.type == StackType.IDENTIFIER: - return state.execute_func(block_to_execute.value.name) + 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) + return state.execute_token_string(block_to_execute.value) # type: ignore def builtin_while(state: "InterpreterState") -> bool: @@ -966,18 +966,18 @@ def builtin_while(state: "InterpreterState") -> bool: condition_block = state.pop() # Check that blocks are executable - if body_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): + 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): + 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: - if not state.execute_func(condition_block.value.name): + 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): + if not state.execute_token_string(condition_block.value): # type: ignore return False # Check result @@ -985,15 +985,15 @@ def builtin_while(state: "InterpreterState") -> bool: return False condition_result = state.pop() - if not is_truthy(condition_result): + if not is_truthy(condition_result): # type: ignore break # Execute body block - if body_block.type == StackType.IDENTIFIER: - if not state.execute_func(body_block.value.name): + 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): + if not state.execute_token_string(body_block.value): # type: ignore return False return True @@ -1009,11 +1009,11 @@ def builtin_for(state: "InterpreterState") -> bool: start_item = state.pop() # Check that block is executable - if body_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): + if body_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): # type: ignore return False - start_val = get_scalar_value(start_item) - end_val = get_scalar_value(end_item) + 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 @@ -1028,11 +1028,11 @@ def builtin_for(state: "InterpreterState") -> bool: return False # Execute body - if body_block.type == StackType.IDENTIFIER: - if not state.execute_func(body_block.value.name): + 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): + if not state.execute_token_string(body_block.value): # type: ignore return False return True @@ -1049,10 +1049,10 @@ def builtin_eval(state: "InterpreterState") -> bool: 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) + 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 @@ -1077,21 +1077,20 @@ def builtin_const(state: "InterpreterState") -> bool: name_entry = state.pop() value_entry = state.pop() - if name_entry.type != StackType.IDENTIFIER: + if name_entry.type != StackType.IDENTIFIER: # type: ignore return False - if value_entry.type != StackType.CALLABLE: + if value_entry.type != StackType.CALLABLE: # type: ignore return False - name = name_entry.value.name + 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 - func_item = FunctionItem.from_token_string(value_entry.value) - state.add_function(name, func_item) + state.add_function(name, value_entry.value) # type: ignore return True @@ -1122,7 +1121,7 @@ def builtin_type_of(state: "InterpreterState") -> bool: StackType.CALLABLE: "Callable", } - type_name = type_names.get(item.type, "Unknown") + type_name = type_names.get(item.type, "Unknown") # type: ignore return state.push_token(Token( type=TokenType.IDENTIFIER, @@ -1234,8 +1233,7 @@ def load_builtins(interpreter_state: "InterpreterState") -> bool: # Register all builtins for name, func in builtins.items(): - func_item = FunctionItem.from_builtin(func) - interpreter_state.add_function(name, func_item) + interpreter_state.add_function(name, func) # Load SLS-defined builtins try: diff --git a/SLS_Python/sls_py/interpreter.py b/SLS_Python/sls_py/interpreter.py index 8775f96..0fdf9dc 100644 --- a/SLS_Python/sls_py/interpreter.py +++ b/SLS_Python/sls_py/interpreter.py @@ -11,27 +11,10 @@ from .lexer import ( IntegerBuiltInType, ) +from .interpreter_types import StackType from .builtin import load_builtins -class StackType(Enum): - IDENTIFIER = auto() - I64 = auto() - I32 = auto() - I16 = auto() - I8 = auto() - U64 = auto() - U32 = auto() - U16 = auto() - U8 = auto() - FLOAT = auto() - DOUBLE = auto() - CHARACTER = auto() - BOOLEAN = auto() - TOKEN_STRING = auto() - CALLABLE = auto() - - @dataclass class StackEntry: type: StackType @@ -42,6 +25,7 @@ class FunctionType(Enum): TOKEN_STRING = auto() BUILTIN = auto() +type FunctionData = TokenString | Callable[["InterpreterState"], bool] @dataclass class FunctionItem: @@ -49,6 +33,13 @@ class FunctionItem: token_string: Optional[TokenString] = None builtin: Optional[Callable[["InterpreterState"], bool]] = None + @classmethod + def from_item(cls, item: FunctionData) -> "FunctionItem": + if isinstance(item, TokenString): + return cls.from_token_string(item) + else: + return cls.from_builtin(item) + @classmethod def from_token_string(cls, ts: TokenString) -> "FunctionItem": return cls(type=FunctionType.TOKEN_STRING, token_string=ts) @@ -93,8 +84,8 @@ class InterpreterState: # ------------------------- # function table # ------------------------- - def add_function(self, name: str, item: FunctionItem) -> None: - self.functions[name] = item + def add_function(self, name: str, item: FunctionData) -> None: + self.functions[name] = FunctionItem.from_item(item) def get_function(self, name: str) -> Optional[FunctionItem]: return self.functions.get(name) diff --git a/SLS_Python/sls_py/interpreter_types.py b/SLS_Python/sls_py/interpreter_types.py new file mode 100644 index 0000000..71c6dc1 --- /dev/null +++ b/SLS_Python/sls_py/interpreter_types.py @@ -0,0 +1,18 @@ +from enum import Enum, auto + +class StackType(Enum): + IDENTIFIER = auto() + I64 = auto() + I32 = auto() + I16 = auto() + I8 = auto() + U64 = auto() + U32 = auto() + U16 = auto() + U8 = auto() + FLOAT = auto() + DOUBLE = auto() + CHARACTER = auto() + BOOLEAN = auto() + TOKEN_STRING = auto() + CALLABLE = auto() diff --git a/SLS_Python/sls_py/lexer.py b/SLS_Python/sls_py/lexer.py index 144fc7a..83209dd 100644 --- a/SLS_Python/sls_py/lexer.py +++ b/SLS_Python/sls_py/lexer.py @@ -306,7 +306,7 @@ class Lexer: # Skip comments if (c == '/' and self.far_peek(1) == '/') or c == '#': while self.peek() not in ('\n', '\0'): - self.advance() + c = self.advance() # Skip whitespace if c.isspace():