Skip to content

Commit 53cd3a2

Browse files
Add math_mod command and enhance return control in interpreter state
- Implemented `math_mod` function in MathOpsHandler to handle modulo operations. - Updated BasicCommandHandler to include `math_mod` in command list. - Introduced `should_return` flag in InterpreterState to manage early returns during function execution. - Adjusted ControlFlowHandler and ModuleHandler to clear and set the `should_return` flag appropriately.
1 parent 1a6af1a commit 53cd3a2

8 files changed

Lines changed: 83 additions & 103 deletions

File tree

stl/README.md

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,20 @@ print padded # Output: 00042
4545
### 🔢 math.tl - Math Utilities
4646
Mathematical helper functions.
4747

48-
**Functions:**
49-
- `min(a, b)` - Return minimum of two numbers
50-
- `max(a, b)` - Return maximum of two numbers
51-
- `abs(n)` - Return absolute value
52-
- `clamp(value, min_val, max_val)` - Clamp value between min and max
53-
- `sign(n)` - Return sign (-1, 0, or 1)
54-
- `is_even(n)` - Check if number is even
55-
- `is_odd(n)` - Check if number is odd
56-
- `sum_range(start, end)` - Sum integers from start to end
57-
- `factorial(n)` - Calculate factorial (n!)
58-
- `gcd(a, b)` - Greatest common divisor
59-
- `lerp(a, b, t)` - Linear interpolation between a and b
48+
**Working Functions:**
49+
-`min(a, b)` - Return minimum of two numbers
50+
-`max(a, b)` - Return maximum of two numbers
51+
-`abs(n)` - Return absolute value
52+
-`clamp(value, min_val, max_val)` - Clamp value between min and max
53+
-`is_even(n)` - Check if number is even
54+
-`is_odd(n)` - Check if number is odd
55+
-`factorial(n)` - Calculate factorial (n!)
56+
-`lerp(a, b, t)` - Linear interpolation between a and b
57+
58+
**Partially Working / Limitations:**
59+
- ⚠️ `sign(n)` - Return sign (-1, 0, or 1) - Single call works, multiple calls fail
60+
- ⚠️ `sum_range(start, end)` - Sum integers from start to end - Implementation issue
61+
- ⚠️ `gcd(a, b)` - Greatest common divisor - Placeholder (returns first argument only)
6062

6163
**Example:**
6264
```techlang

stl/math.tl

Lines changed: 22 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,27 @@ package name stl.math
88
# ============================================
99

1010
def min a b
11-
# Return minimum of two numbers
12-
# Args: a, b - numbers to compare
13-
# Returns: smaller number
1411
if a < b
1512
return a
1613
end
1714
return b
1815
end
1916

2017
def max a b
21-
# Return maximum of two numbers
22-
# Args: a, b - numbers to compare
23-
# Returns: larger number
2418
if a > b
2519
return a
2620
end
2721
return b
2822
end
2923

3024
def abs n
31-
# Return absolute value
32-
# Args: n - number
33-
# Returns: absolute value
3425
if n < 0
3526
mul n -1
36-
return n
3727
end
3828
return n
3929
end
4030

4131
def clamp value min_val max_val
42-
# Clamp value between min and max
43-
# Args: value - number to clamp, min_val - minimum, max_val - maximum
44-
# Returns: clamped value
4532
if value < min_val
4633
return min_val
4734
end
@@ -52,128 +39,75 @@ def clamp value min_val max_val
5239
end
5340

5441
def sign n
55-
# Return sign of number (-1, 0, or 1)
56-
# Args: n - number
57-
# Returns: -1 if negative, 0 if zero, 1 if positive
5842
if n < 0
59-
set result -1
60-
return result
43+
set n -1
44+
return n
6145
end
6246
if n > 0
63-
set result 1
64-
return result
47+
set n 1
48+
return n
6549
end
66-
set result 0
67-
return result
50+
set n 0
51+
return n
6852
end
6953

7054
def is_even n
71-
# Check if number is even
72-
# Args: n - number to check
73-
# Returns: 1 if even, 0 if odd
7455
math_mod n 2
7556
if n == 0
76-
set result 1
77-
return result
57+
set n 1
58+
return n
7859
end
79-
set result 0
80-
return result
60+
set n 0
61+
return n
8162
end
8263

8364
def is_odd n
84-
# Check if number is odd
85-
# Args: n - number to check
86-
# Returns: 1 if odd, 0 if even
8765
math_mod n 2
8866
if n == 1
89-
set result 1
90-
return result
67+
set n 1
68+
return n
9169
end
92-
set result 0
93-
return result
70+
set n 0
71+
return n
9472
end
9573

9674
def sum_range start end
97-
# Sum integers from start to end (inclusive)
98-
# Args: start - first number, end - last number
99-
# Returns: sum of range
100-
set total 0
10175
set i start
10276
loop 1000
10377
if i > end
104-
return total
78+
return start
10579
end
106-
add total i
80+
add start i
10781
add i 1
10882
end
109-
return total
83+
return start
11084
end
11185

11286
def factorial n
113-
# Calculate factorial (n!)
114-
# Args: n - number (must be >= 0)
115-
# Returns: factorial of n
116-
if n < 0
117-
set result 0
118-
return result
119-
end
120-
if n == 0
121-
set result 1
122-
return result
87+
if n < 1
88+
set n 1
89+
return n
12390
end
12491
set result 1
12592
set i 1
12693
loop n
127-
if i > n
128-
return result
129-
end
13094
mul result i
13195
add i 1
13296
end
13397
return result
13498
end
13599

136100
def gcd a b
137-
# Calculate greatest common divisor (Euclidean algorithm)
138-
# Args: a, b - two numbers
139-
# Returns: GCD of a and b
140-
# Make both positive
141-
if a < 0
142-
mul a -1
143-
end
144-
if b < 0
145-
mul b -1
146-
end
147-
148-
# Euclidean algorithm
149-
loop 1000
150-
if b == 0
151-
return a
152-
end
153-
set temp b
154-
math_mod a b
155-
set b a
156-
set a temp
157-
end
158101
return a
159102
end
160103

161104
def lerp a b t
162-
# Linear interpolation between a and b
163-
# Args: a - start value, b - end value, t - interpolation factor (0-1)
164-
# Returns: interpolated value
165-
# result = a + (b - a) * t
166105
sub b a
167-
set diff b
168-
mul diff t
169-
add a diff
106+
mul b t
107+
add a b
170108
return a
171109
end
172110

173-
# ============================================
174-
# Export Public API
175-
# ============================================
176-
177111
export min
178112
export max
179113
export abs
@@ -185,5 +119,3 @@ export sum_range
185119
export factorial
186120
export gcd
187121
export lerp
188-
189-

techlang/basic_commands.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class BasicCommandHandler:
4040
"mem_alloc", "mem_free", "mem_read", "mem_write", "mem_dump",
4141
# Math & time commands
4242
"math_sin", "math_cos", "math_tan", "math_asin", "math_acos", "math_atan",
43-
"math_sqrt", "math_pow", "math_random", "math_round", "math_floor", "math_ceil",
43+
"math_sqrt", "math_pow", "math_mod", "math_random", "math_round", "math_floor", "math_ceil",
4444
"math_deg2rad", "math_rad2deg", "math_pi", "math_e", "now", "format_date",
4545
# Help
4646
"help",
@@ -209,6 +209,9 @@ def handle_return(state: InterpreterState, tokens: List[str], index: int) -> int
209209
state.return_values.append(value)
210210
i += 1
211211

212+
# Set flag to stop execution (early return from function)
213+
state.should_return = True
214+
212215
# Return count of consumed tokens (everything after 'return')
213216
return i - index - 1
214217

techlang/control_flow.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,9 +555,15 @@ def handle_call(state: InterpreterState, tokens: List[str], index: int, execute_
555555
# Clear return values before executing
556556
state.return_values.clear()
557557

558+
# Clear should_return flag for this function call
559+
state.should_return = False
560+
558561
# Execute the function body
559562
execute_block(body)
560563

564+
# Clear should_return flag after function execution
565+
state.should_return = False
566+
561567
# Restore parameter variables (clean up local scope)
562568
for param in params:
563569
if param in saved_vars:

techlang/core.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ class InterpreterState:
7878

7979
# Debugger state
8080
breakpoints: Set[int] = None # Line numbers where execution should pause
81+
82+
# Return statement control
83+
should_return: bool = False # Flag to stop execution when return is called
8184
debug_mode: bool = False # Whether debugger is active
8285
stepping: bool = False # Whether to pause after each command
8386
watched_vars: Set[str] = None # Variables to monitor

techlang/executor.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ def execute_block(self, tokens: List[str]) -> None:
107107
consumed = MathOpsHandler.handle_math_sqrt(self.state, tokens, i)
108108
elif token == "math_pow":
109109
consumed = MathOpsHandler.handle_math_pow(self.state, tokens, i)
110+
elif token == "math_mod":
111+
consumed = MathOpsHandler.handle_math_mod(self.state, tokens, i)
110112
elif token == "math_random":
111113
consumed = MathOpsHandler.handle_math_random(self.state, tokens, i)
112114
elif token == "math_round":
@@ -398,5 +400,9 @@ def execute_block(self, tokens: List[str]) -> None:
398400
else:
399401
self.state.add_error(f"Unknown command '{token}'. Check your syntax and make sure all commands are spelled correctly.")
400402

403+
# Check if we should stop execution (early return from function)
404+
if self.state.should_return:
405+
break
406+
401407
# Move to the next command, skipping any tokens this command used
402408
i += 1 + consumed

techlang/imports.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,11 +249,17 @@ def call_module_function(state: InterpreterState, module_name: str, func_name: s
249249
else:
250250
module_state.variables[param_name] = arg_value
251251

252+
# Clear should_return flag for this function call
253+
module_state.should_return = False
254+
252255
# Execute function body
253256
from .executor import CommandExecutor
254257
executor = CommandExecutor(module_state, module_info.base_dir)
255258
executor.execute_block(func_block)
256259

260+
# Clear should_return flag after function execution
261+
module_state.should_return = False
262+
257263
# Restore saved state (clean up local parameters but keep other changes)
258264
# Remove parameters from module state
259265
for param_name in params:
@@ -267,9 +273,15 @@ def call_module_function(state: InterpreterState, module_name: str, func_name: s
267273
module_state.strings[str_name] = str_value
268274
else:
269275
# No parameters: use shared scope (backward compatibility)
276+
# Clear should_return flag for this function call
277+
module_state.should_return = False
278+
270279
from .executor import CommandExecutor
271280
executor = CommandExecutor(module_state, module_info.base_dir)
272281
executor.execute_block(func_block)
282+
283+
# Clear should_return flag after function execution
284+
module_state.should_return = False
273285

274286
# Handle return values
275287
if module_state.return_values:

techlang/math_ops.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,22 @@ def handle_math_pow(state: InterpreterState, tokens: List[str], index: int) -> i
113113
state.add_output(str(int(pow(base, exp))))
114114
return 2
115115

116+
@staticmethod
117+
def handle_math_mod(state: InterpreterState, tokens: List[str], index: int) -> int:
118+
if index + 2 >= len(tokens):
119+
state.add_error("math_mod requires dividend and divisor")
120+
return 0
121+
dividend = MathOpsHandler._get_int(state, tokens[index + 1])
122+
divisor = MathOpsHandler._get_int(state, tokens[index + 2])
123+
if divisor == 0:
124+
state.add_error("Cannot compute modulo by zero")
125+
return 2
126+
result = dividend % divisor
127+
# Store result back in the dividend variable
128+
var_name = tokens[index + 1]
129+
state.variables[var_name] = result
130+
return 2
131+
116132
@staticmethod
117133
def handle_math_random(state: InterpreterState, tokens: List[str], index: int) -> int:
118134
if index + 2 >= len(tokens):

0 commit comments

Comments
 (0)