Fixed circular imports
This commit is contained in:
parent
dc5d75cf75
commit
d7164599f0
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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():
|
||||
|
|
|
|||
Loading…
Reference in New Issue