Compare commits
2 Commits
dc5d75cf75
...
8890216457
| Author | SHA1 | Date |
|---|---|---|
|
|
8890216457 | |
|
|
d7164599f0 |
|
|
@ -12,7 +12,7 @@ class HPCalculator:
|
||||||
def __init__(self, root):
|
def __init__(self, root):
|
||||||
self.root = root
|
self.root = root
|
||||||
self.root.title("HP Stack Calculator")
|
self.root.title("HP Stack Calculator")
|
||||||
self.root.geometry("450x650")
|
# self.root.geometry("450x650")
|
||||||
self.root.resizable(False, False)
|
self.root.resizable(False, False)
|
||||||
|
|
||||||
# Initialize interpreter
|
# Initialize interpreter
|
||||||
|
|
@ -24,24 +24,8 @@ class HPCalculator:
|
||||||
self.is_new_entry = True
|
self.is_new_entry = True
|
||||||
|
|
||||||
# Set up UI
|
# Set up UI
|
||||||
self.setup_styles()
|
|
||||||
self.create_widgets()
|
self.create_widgets()
|
||||||
|
|
||||||
def setup_styles(self):
|
|
||||||
"""Configure custom styles for the calculator"""
|
|
||||||
style = ttk.Style()
|
|
||||||
style.theme_use('clam')
|
|
||||||
|
|
||||||
# Configure button styles
|
|
||||||
style.configure('Calc.TButton',
|
|
||||||
font=('Arial', 12, 'bold'),
|
|
||||||
padding=10)
|
|
||||||
style.configure('Display.TLabel',
|
|
||||||
font=('Courier', 14),
|
|
||||||
background='#f0f0f0',
|
|
||||||
relief='sunken',
|
|
||||||
padding=5)
|
|
||||||
|
|
||||||
def create_widgets(self):
|
def create_widgets(self):
|
||||||
"""Create all calculator widgets"""
|
"""Create all calculator widgets"""
|
||||||
# Main container
|
# Main container
|
||||||
|
|
@ -65,8 +49,7 @@ class HPCalculator:
|
||||||
self.stack_labels = []
|
self.stack_labels = []
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
label = ttk.Label(stack_frame,
|
label = ttk.Label(stack_frame,
|
||||||
text=f"T{3-i}: 0",
|
text=f"T{3-i}: <>",
|
||||||
style='Display.TLabel',
|
|
||||||
anchor='e',
|
anchor='e',
|
||||||
width=30)
|
width=30)
|
||||||
label.grid(row=i, column=0, sticky=(tk.W, tk.E), pady=2)
|
label.grid(row=i, column=0, sticky=(tk.W, tk.E), pady=2)
|
||||||
|
|
@ -78,46 +61,35 @@ class HPCalculator:
|
||||||
entry_frame.grid(row=1, column=0, columnspan=4, sticky=(tk.W, tk.E), pady=(0, 10))
|
entry_frame.grid(row=1, column=0, columnspan=4, sticky=(tk.W, tk.E), pady=(0, 10))
|
||||||
|
|
||||||
self.entry_label = ttk.Label(entry_frame,
|
self.entry_label = ttk.Label(entry_frame,
|
||||||
text="0",
|
text="0",
|
||||||
style='Display.TLabel',
|
anchor='e',
|
||||||
anchor='e',
|
font=('Courier', 16))
|
||||||
font=('Courier', 16, 'bold'))
|
|
||||||
self.entry_label.grid(row=0, column=0, sticky=(tk.W, tk.E))
|
self.entry_label.grid(row=0, column=0, sticky=(tk.W, tk.E))
|
||||||
|
|
||||||
def create_button_grid(self, parent):
|
def create_button_grid(self, parent):
|
||||||
"""Create the calculator button grid"""
|
"""Create the calculator button grid"""
|
||||||
buttons = [
|
buttons = [
|
||||||
# Row 1: Stack operations
|
[('√', self.sqrt), ('x²', self.square), ('1/x', self.reciprocal), ('NULL', lambda: None)],
|
||||||
[('√', self.sqrt), ('x²', self.square), ('1/x', self.reciprocal), ('÷', self.divide)],
|
[('ENTER', lambda: self.enter(True)), ('SWAP', self.swap), ('<-', self.drop), ('NULL', lambda: None)],
|
||||||
# Row 2: Numbers and operations
|
[('7', lambda: self.digit('7')), ('8', lambda: self.digit('8')), ('9', lambda: self.digit('9')), ('÷', self.divide)],
|
||||||
[('7', lambda: self.digit('7')), ('8', lambda: self.digit('8')),
|
[('4', lambda: self.digit('4')), ('5', lambda: self.digit('5')), ('6', lambda: self.digit('6')), ('×', self.multiply)],
|
||||||
('9', lambda: self.digit('9')), ('×', self.multiply)],
|
[('1', lambda: self.digit('1')), ('2', lambda: self.digit('2')), ('3', lambda: self.digit('3')), ('−', self.subtract)],
|
||||||
# Row 3
|
[('0', lambda: self.digit('0')), ('.', self.decimal), ('±', self.negate), ('+', self.add)],
|
||||||
[('4', lambda: self.digit('4')), ('5', lambda: self.digit('5')),
|
|
||||||
('6', lambda: self.digit('6')), ('−', self.subtract)],
|
|
||||||
# Row 4
|
|
||||||
[('1', lambda: self.digit('1')), ('2', lambda: self.digit('2')),
|
|
||||||
('3', lambda: self.digit('3')), ('+', self.add)],
|
|
||||||
# Row 5
|
|
||||||
[('0', lambda: self.digit('0')), ('.', self.decimal),
|
|
||||||
('±', self.negate), ('ENTER', self.enter)],
|
|
||||||
# Row 6: Special functions
|
|
||||||
[('SWAP', self.swap), ('DROP', self.drop),
|
|
||||||
('DUP', self.dup), ('CLR', self.clear)]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
for row_idx, row in enumerate(buttons, start=2):
|
for row_idx, row in enumerate(buttons, start=2):
|
||||||
for col_idx, (text, command) in enumerate(row):
|
for col_idx, (text, command) in enumerate(row):
|
||||||
btn = ttk.Button(parent,
|
if text != "NULL":
|
||||||
text=text,
|
btn = ttk.Button(parent,
|
||||||
command=command,
|
text=text,
|
||||||
style='Calc.TButton',
|
command=command,
|
||||||
width=8)
|
width=8)
|
||||||
btn.grid(row=row_idx, column=col_idx, padx=2, pady=2, sticky=(tk.W, tk.E, tk.N, tk.S))
|
btn.grid(row=row_idx, column=col_idx, padx=2, pady=2, sticky=(tk.W, tk.E, tk.N, tk.S))
|
||||||
|
|
||||||
# Keyboard bindings
|
# Keyboard bindings
|
||||||
self.root.bind('<Return>', lambda e: self.enter())
|
self.root.bind('<Delete>', lambda e: self.drop())
|
||||||
self.root.bind('<KP_Enter>', lambda e: self.enter())
|
self.root.bind('<Return>', lambda e: self.enter(True))
|
||||||
|
self.root.bind('<KP_Enter>', lambda e: self.enter(True))
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
self.root.bind(str(i), lambda e, n=str(i): self.digit(n))
|
self.root.bind(str(i), lambda e, n=str(i): self.digit(n))
|
||||||
self.root.bind('.', lambda e: self.decimal())
|
self.root.bind('.', lambda e: self.decimal())
|
||||||
|
|
@ -125,7 +97,6 @@ class HPCalculator:
|
||||||
self.root.bind('-', lambda e: self.subtract())
|
self.root.bind('-', lambda e: self.subtract())
|
||||||
self.root.bind('*', lambda e: self.multiply())
|
self.root.bind('*', lambda e: self.multiply())
|
||||||
self.root.bind('/', lambda e: self.divide())
|
self.root.bind('/', lambda e: self.divide())
|
||||||
self.root.bind('<Escape>', lambda e: self.clear())
|
|
||||||
|
|
||||||
def digit(self, d):
|
def digit(self, d):
|
||||||
"""Handle digit button press"""
|
"""Handle digit button press"""
|
||||||
|
|
@ -157,12 +128,14 @@ class HPCalculator:
|
||||||
self.entry_buffer = '-' + self.entry_buffer
|
self.entry_buffer = '-' + self.entry_buffer
|
||||||
self.update_entry_display()
|
self.update_entry_display()
|
||||||
|
|
||||||
def enter(self):
|
def enter(self, key=False):
|
||||||
"""Push current entry onto stack"""
|
"""Push current entry onto stack"""
|
||||||
if self.entry_buffer:
|
if self.entry_buffer:
|
||||||
self.execute_code(self.entry_buffer)
|
self.execute_code(self.entry_buffer)
|
||||||
self.entry_buffer = ""
|
self.entry_buffer = ""
|
||||||
self.is_new_entry = True
|
self.is_new_entry = True
|
||||||
|
elif key:
|
||||||
|
self.execute_code("dup")
|
||||||
self.update_displays()
|
self.update_displays()
|
||||||
|
|
||||||
def add(self):
|
def add(self):
|
||||||
|
|
@ -219,21 +192,6 @@ class HPCalculator:
|
||||||
self.execute_code("drop")
|
self.execute_code("drop")
|
||||||
self.update_displays()
|
self.update_displays()
|
||||||
|
|
||||||
def dup(self):
|
|
||||||
"""Duplicate top stack item"""
|
|
||||||
self.enter()
|
|
||||||
self.execute_code("dup")
|
|
||||||
self.update_displays()
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
"""Clear entry and stack"""
|
|
||||||
self.entry_buffer = ""
|
|
||||||
self.is_new_entry = True
|
|
||||||
# Clear the stack
|
|
||||||
while len(self.interp.stack) > 0:
|
|
||||||
self.interp.pop()
|
|
||||||
self.update_displays()
|
|
||||||
|
|
||||||
def execute_code(self, code):
|
def execute_code(self, code):
|
||||||
"""Execute stack language code"""
|
"""Execute stack language code"""
|
||||||
try:
|
try:
|
||||||
|
|
@ -274,7 +232,7 @@ class HPCalculator:
|
||||||
value_str = self.format_stack_entry(entry)
|
value_str = self.format_stack_entry(entry)
|
||||||
self.stack_labels[i].config(text=f"T{level}: {value_str}")
|
self.stack_labels[i].config(text=f"T{level}: {value_str}")
|
||||||
else:
|
else:
|
||||||
self.stack_labels[i].config(text=f"T{level}: 0")
|
self.stack_labels[i].config(text=f"T{level}: <>")
|
||||||
|
|
||||||
def format_stack_entry(self, entry):
|
def format_stack_entry(self, entry):
|
||||||
"""Format a stack entry for display"""
|
"""Format a stack entry for display"""
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, Optional, Tuple
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .interpreter import InterpreterState, StackEntry
|
from .interpreter import InterpreterState, StackEntry
|
||||||
|
|
||||||
from .interpreter import StackType, FunctionItem
|
from .interpreter_types import StackType
|
||||||
from .lexer import Token, TokenType, IntegerLiteral, IntegerBuiltInType, Identifier
|
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
|
ival = 0
|
||||||
|
|
||||||
if entry.type == StackType.I64:
|
if entry.type == StackType.I64:
|
||||||
ival = int(entry.value)
|
ival = int(entry.value) # type: ignore
|
||||||
fval = float(ival)
|
fval = float(ival)
|
||||||
flags = NumericTypeFlags.BITS_64 | NumericTypeFlags.SIGNED
|
flags = NumericTypeFlags.BITS_64 | NumericTypeFlags.SIGNED
|
||||||
elif entry.type == StackType.I32:
|
elif entry.type == StackType.I32:
|
||||||
ival = int(entry.value)
|
ival = int(entry.value) # type: ignore
|
||||||
fval = float(ival)
|
fval = float(ival)
|
||||||
flags = NumericTypeFlags.BITS_32 | NumericTypeFlags.SIGNED
|
flags = NumericTypeFlags.BITS_32 | NumericTypeFlags.SIGNED
|
||||||
elif entry.type == StackType.I16:
|
elif entry.type == StackType.I16:
|
||||||
ival = int(entry.value)
|
ival = int(entry.value) # type: ignore
|
||||||
fval = float(ival)
|
fval = float(ival)
|
||||||
flags = NumericTypeFlags.BITS_16 | NumericTypeFlags.SIGNED
|
flags = NumericTypeFlags.BITS_16 | NumericTypeFlags.SIGNED
|
||||||
elif entry.type == StackType.I8:
|
elif entry.type == StackType.I8:
|
||||||
ival = int(entry.value)
|
ival = int(entry.value) # type: ignore
|
||||||
fval = float(ival)
|
fval = float(ival)
|
||||||
flags = NumericTypeFlags.BITS_8 | NumericTypeFlags.SIGNED
|
flags = NumericTypeFlags.BITS_8 | NumericTypeFlags.SIGNED
|
||||||
elif entry.type == StackType.U64:
|
elif entry.type == StackType.U64:
|
||||||
ival = int(entry.value)
|
ival = int(entry.value) # type: ignore
|
||||||
fval = float(ival)
|
fval = float(ival)
|
||||||
flags = NumericTypeFlags.BITS_64
|
flags = NumericTypeFlags.BITS_64
|
||||||
elif entry.type == StackType.U32:
|
elif entry.type == StackType.U32:
|
||||||
ival = int(entry.value)
|
ival = int(entry.value) # type: ignore
|
||||||
fval = float(ival)
|
fval = float(ival)
|
||||||
flags = NumericTypeFlags.BITS_32
|
flags = NumericTypeFlags.BITS_32
|
||||||
elif entry.type == StackType.U16:
|
elif entry.type == StackType.U16:
|
||||||
ival = int(entry.value)
|
ival = int(entry.value) # type: ignore
|
||||||
fval = float(ival)
|
fval = float(ival)
|
||||||
flags = NumericTypeFlags.BITS_16
|
flags = NumericTypeFlags.BITS_16
|
||||||
elif entry.type == StackType.U8:
|
elif entry.type == StackType.U8:
|
||||||
ival = int(entry.value)
|
ival = int(entry.value) # type: ignore
|
||||||
fval = float(ival)
|
fval = float(ival)
|
||||||
flags = NumericTypeFlags.BITS_8
|
flags = NumericTypeFlags.BITS_8
|
||||||
elif entry.type == StackType.FLOAT:
|
elif entry.type == StackType.FLOAT:
|
||||||
fval = float(entry.value)
|
fval = float(entry.value) # type: ignore
|
||||||
flags = NumericTypeFlags.BITS_32 | NumericTypeFlags.FLOAT
|
flags = NumericTypeFlags.BITS_32 | NumericTypeFlags.FLOAT
|
||||||
elif entry.type == StackType.DOUBLE:
|
elif entry.type == StackType.DOUBLE:
|
||||||
fval = float(entry.value)
|
fval = float(entry.value) # type: ignore
|
||||||
flags = NumericTypeFlags.BITS_64 | NumericTypeFlags.FLOAT
|
flags = NumericTypeFlags.BITS_64 | NumericTypeFlags.FLOAT
|
||||||
elif entry.type == StackType.CHARACTER:
|
elif entry.type == StackType.CHARACTER:
|
||||||
ival = int(entry.value)
|
ival = int(entry.value) # type: ignore
|
||||||
fval = float(ival)
|
fval = float(ival)
|
||||||
flags = NumericTypeFlags.BITS_8
|
flags = NumericTypeFlags.BITS_8
|
||||||
elif entry.type == StackType.BOOLEAN:
|
elif entry.type == StackType.BOOLEAN:
|
||||||
|
|
@ -177,36 +177,36 @@ def is_truthy(entry: "StackEntry") -> bool:
|
||||||
return bool(entry.value)
|
return bool(entry.value)
|
||||||
elif entry.type in (StackType.TOKEN_STRING, StackType.CALLABLE):
|
elif entry.type in (StackType.TOKEN_STRING, StackType.CALLABLE):
|
||||||
ts = entry.value
|
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
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_scalar_value(entry: "StackEntry") -> Optional[int]:
|
def get_scalar_value(entry: "StackEntry") -> Optional[int]:
|
||||||
"""Extract a scalar (non-negative integer) value from stack entry"""
|
"""Extract a scalar (non-negative integer) value from stack entry"""
|
||||||
if entry.type == StackType.I64:
|
if entry.type == StackType.I64:
|
||||||
val = int(entry.value)
|
val = int(entry.value) # type: ignore
|
||||||
if val < 0:
|
if val < 0:
|
||||||
return None
|
return None
|
||||||
return val
|
return val
|
||||||
elif entry.type == StackType.I32:
|
elif entry.type == StackType.I32:
|
||||||
val = int(entry.value)
|
val = int(entry.value) # type: ignore
|
||||||
if val < 0:
|
if val < 0:
|
||||||
return None
|
return None
|
||||||
return val
|
return val
|
||||||
elif entry.type == StackType.I16:
|
elif entry.type == StackType.I16:
|
||||||
val = int(entry.value)
|
val = int(entry.value) # type: ignore
|
||||||
if val < 0:
|
if val < 0:
|
||||||
return None
|
return None
|
||||||
return val
|
return val
|
||||||
elif entry.type == StackType.I8:
|
elif entry.type == StackType.I8:
|
||||||
val = int(entry.value)
|
val = int(entry.value) # type: ignore
|
||||||
if val < 0:
|
if val < 0:
|
||||||
return None
|
return None
|
||||||
return val
|
return val
|
||||||
elif entry.type in (StackType.U64, StackType.U32, StackType.U16, StackType.U8):
|
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:
|
elif entry.type == StackType.CHARACTER:
|
||||||
return int(entry.value)
|
return int(entry.value) # type: ignore
|
||||||
elif entry.type == StackType.BOOLEAN:
|
elif entry.type == StackType.BOOLEAN:
|
||||||
return 1 if entry.value else 0
|
return 1 if entry.value else 0
|
||||||
else:
|
else:
|
||||||
|
|
@ -800,7 +800,7 @@ def builtin_dup(state: "InterpreterState") -> bool:
|
||||||
|
|
||||||
# Deep copy for token strings
|
# Deep copy for token strings
|
||||||
if top.type in (StackType.TOKEN_STRING, StackType.CALLABLE):
|
if top.type in (StackType.TOKEN_STRING, StackType.CALLABLE):
|
||||||
value_copy = top.value.deep_copy()
|
value_copy = top.value.deep_copy() # type: ignore
|
||||||
else:
|
else:
|
||||||
value_copy = top.value
|
value_copy = top.value
|
||||||
|
|
||||||
|
|
@ -825,8 +825,8 @@ def builtin_swap(state: "InterpreterState") -> bool:
|
||||||
|
|
||||||
a = state.pop()
|
a = state.pop()
|
||||||
b = state.pop()
|
b = state.pop()
|
||||||
state.push(a)
|
state.push(a) # type: ignore
|
||||||
state.push(b)
|
state.push(b) # type: ignore
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -869,7 +869,7 @@ def builtin_pick(state: "InterpreterState") -> bool:
|
||||||
|
|
||||||
# Deep copy for token strings
|
# Deep copy for token strings
|
||||||
if picked.type in (StackType.TOKEN_STRING, StackType.CALLABLE):
|
if picked.type in (StackType.TOKEN_STRING, StackType.CALLABLE):
|
||||||
value_copy = picked.value.deep_copy()
|
value_copy = picked.value.deep_copy() # type: ignore
|
||||||
else:
|
else:
|
||||||
value_copy = picked.value
|
value_copy = picked.value
|
||||||
|
|
||||||
|
|
@ -937,13 +937,13 @@ def builtin_if(state: "InterpreterState") -> bool:
|
||||||
condition = state.pop()
|
condition = state.pop()
|
||||||
|
|
||||||
# Check that blocks are executable
|
# 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
|
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
|
return False
|
||||||
|
|
||||||
# Evaluate condition
|
# Evaluate condition
|
||||||
is_true = is_truthy(condition)
|
is_true = is_truthy(condition) # type: ignore
|
||||||
|
|
||||||
# Execute appropriate block
|
# Execute appropriate block
|
||||||
if is_true:
|
if is_true:
|
||||||
|
|
@ -951,10 +951,10 @@ def builtin_if(state: "InterpreterState") -> bool:
|
||||||
else:
|
else:
|
||||||
block_to_execute = else_block
|
block_to_execute = else_block
|
||||||
|
|
||||||
if block_to_execute.type == StackType.IDENTIFIER:
|
if block_to_execute.type == StackType.IDENTIFIER: # type: ignore
|
||||||
return state.execute_func(block_to_execute.value.name)
|
return state.execute_func(block_to_execute.value.name) # type: ignore
|
||||||
else:
|
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:
|
def builtin_while(state: "InterpreterState") -> bool:
|
||||||
|
|
@ -966,18 +966,18 @@ def builtin_while(state: "InterpreterState") -> bool:
|
||||||
condition_block = state.pop()
|
condition_block = state.pop()
|
||||||
|
|
||||||
# Check that blocks are executable
|
# 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
|
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
|
return False
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
# Execute condition block
|
# Execute condition block
|
||||||
if condition_block.type == StackType.IDENTIFIER:
|
if condition_block.type == StackType.IDENTIFIER: # type: ignore
|
||||||
if not state.execute_func(condition_block.value.name):
|
if not state.execute_func(condition_block.value.name): # type: ignore
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
if not state.execute_token_string(condition_block.value):
|
if not state.execute_token_string(condition_block.value): # type: ignore
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Check result
|
# Check result
|
||||||
|
|
@ -985,15 +985,15 @@ def builtin_while(state: "InterpreterState") -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
condition_result = state.pop()
|
condition_result = state.pop()
|
||||||
if not is_truthy(condition_result):
|
if not is_truthy(condition_result): # type: ignore
|
||||||
break
|
break
|
||||||
|
|
||||||
# Execute body block
|
# Execute body block
|
||||||
if body_block.type == StackType.IDENTIFIER:
|
if body_block.type == StackType.IDENTIFIER: # type: ignore
|
||||||
if not state.execute_func(body_block.value.name):
|
if not state.execute_func(body_block.value.name): # type: ignore
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
if not state.execute_token_string(body_block.value):
|
if not state.execute_token_string(body_block.value): # type: ignore
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
@ -1009,11 +1009,11 @@ def builtin_for(state: "InterpreterState") -> bool:
|
||||||
start_item = state.pop()
|
start_item = state.pop()
|
||||||
|
|
||||||
# Check that block is executable
|
# 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
|
return False
|
||||||
|
|
||||||
start_val = get_scalar_value(start_item)
|
start_val = get_scalar_value(start_item) # type: ignore
|
||||||
end_val = get_scalar_value(end_item)
|
end_val = get_scalar_value(end_item) # type: ignore
|
||||||
|
|
||||||
if start_val is None or end_val is None:
|
if start_val is None or end_val is None:
|
||||||
return False
|
return False
|
||||||
|
|
@ -1028,11 +1028,11 @@ def builtin_for(state: "InterpreterState") -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Execute body
|
# Execute body
|
||||||
if body_block.type == StackType.IDENTIFIER:
|
if body_block.type == StackType.IDENTIFIER: # type: ignore
|
||||||
if not state.execute_func(body_block.value.name):
|
if not state.execute_func(body_block.value.name): # type: ignore
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
if not state.execute_token_string(body_block.value):
|
if not state.execute_token_string(body_block.value): # type: ignore
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
@ -1049,10 +1049,10 @@ def builtin_eval(state: "InterpreterState") -> bool:
|
||||||
|
|
||||||
code_target = state.pop()
|
code_target = state.pop()
|
||||||
|
|
||||||
if code_target.type in (StackType.TOKEN_STRING, StackType.CALLABLE):
|
if code_target.type in (StackType.TOKEN_STRING, StackType.CALLABLE): # type: ignore
|
||||||
return state.execute_token_string(code_target.value)
|
return state.execute_token_string(code_target.value) # type: ignore
|
||||||
elif code_target.type == StackType.IDENTIFIER:
|
elif code_target.type == StackType.IDENTIFIER: # type: ignore
|
||||||
return state.execute_func(code_target.value.name)
|
return state.execute_func(code_target.value.name) # type: ignore
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
@ -1077,21 +1077,20 @@ def builtin_const(state: "InterpreterState") -> bool:
|
||||||
name_entry = state.pop()
|
name_entry = state.pop()
|
||||||
value_entry = state.pop()
|
value_entry = state.pop()
|
||||||
|
|
||||||
if name_entry.type != StackType.IDENTIFIER:
|
if name_entry.type != StackType.IDENTIFIER: # type: ignore
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if value_entry.type != StackType.CALLABLE:
|
if value_entry.type != StackType.CALLABLE: # type: ignore
|
||||||
return False
|
return False
|
||||||
|
|
||||||
name = name_entry.value.name
|
name = name_entry.value.name # type: ignore
|
||||||
|
|
||||||
# Check if function already exists
|
# Check if function already exists
|
||||||
if state.get_function(name) is not None:
|
if state.get_function(name) is not None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Create function item
|
# Create function item
|
||||||
func_item = FunctionItem.from_token_string(value_entry.value)
|
state.add_function(name, value_entry.value) # type: ignore
|
||||||
state.add_function(name, func_item)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
@ -1122,7 +1121,7 @@ def builtin_type_of(state: "InterpreterState") -> bool:
|
||||||
StackType.CALLABLE: "Callable",
|
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(
|
return state.push_token(Token(
|
||||||
type=TokenType.IDENTIFIER,
|
type=TokenType.IDENTIFIER,
|
||||||
|
|
@ -1234,8 +1233,7 @@ def load_builtins(interpreter_state: "InterpreterState") -> bool:
|
||||||
|
|
||||||
# Register all builtins
|
# Register all builtins
|
||||||
for name, func in builtins.items():
|
for name, func in builtins.items():
|
||||||
func_item = FunctionItem.from_builtin(func)
|
interpreter_state.add_function(name, func)
|
||||||
interpreter_state.add_function(name, func_item)
|
|
||||||
|
|
||||||
# Load SLS-defined builtins
|
# Load SLS-defined builtins
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -11,27 +11,10 @@ from .lexer import (
|
||||||
IntegerBuiltInType,
|
IntegerBuiltInType,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from .interpreter_types import StackType
|
||||||
from .builtin import load_builtins
|
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
|
@dataclass
|
||||||
class StackEntry:
|
class StackEntry:
|
||||||
type: StackType
|
type: StackType
|
||||||
|
|
@ -42,6 +25,7 @@ class FunctionType(Enum):
|
||||||
TOKEN_STRING = auto()
|
TOKEN_STRING = auto()
|
||||||
BUILTIN = auto()
|
BUILTIN = auto()
|
||||||
|
|
||||||
|
type FunctionData = TokenString | Callable[["InterpreterState"], bool]
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FunctionItem:
|
class FunctionItem:
|
||||||
|
|
@ -49,6 +33,13 @@ class FunctionItem:
|
||||||
token_string: Optional[TokenString] = None
|
token_string: Optional[TokenString] = None
|
||||||
builtin: Optional[Callable[["InterpreterState"], bool]] = 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
|
@classmethod
|
||||||
def from_token_string(cls, ts: TokenString) -> "FunctionItem":
|
def from_token_string(cls, ts: TokenString) -> "FunctionItem":
|
||||||
return cls(type=FunctionType.TOKEN_STRING, token_string=ts)
|
return cls(type=FunctionType.TOKEN_STRING, token_string=ts)
|
||||||
|
|
@ -93,8 +84,8 @@ class InterpreterState:
|
||||||
# -------------------------
|
# -------------------------
|
||||||
# function table
|
# function table
|
||||||
# -------------------------
|
# -------------------------
|
||||||
def add_function(self, name: str, item: FunctionItem) -> None:
|
def add_function(self, name: str, item: FunctionData) -> None:
|
||||||
self.functions[name] = item
|
self.functions[name] = FunctionItem.from_item(item)
|
||||||
|
|
||||||
def get_function(self, name: str) -> Optional[FunctionItem]:
|
def get_function(self, name: str) -> Optional[FunctionItem]:
|
||||||
return self.functions.get(name)
|
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
|
# Skip comments
|
||||||
if (c == '/' and self.far_peek(1) == '/') or c == '#':
|
if (c == '/' and self.far_peek(1) == '/') or c == '#':
|
||||||
while self.peek() not in ('\n', '\0'):
|
while self.peek() not in ('\n', '\0'):
|
||||||
self.advance()
|
c = self.advance()
|
||||||
|
|
||||||
# Skip whitespace
|
# Skip whitespace
|
||||||
if c.isspace():
|
if c.isspace():
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue