gladlang 0.2.2__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gladlang-0.2.2/src/gladlang.egg-info → gladlang-0.2.4}/PKG-INFO +2 -2
- {gladlang-0.2.2 → gladlang-0.2.4}/README.md +1 -1
- {gladlang-0.2.2 → gladlang-0.2.4}/pyproject.toml +1 -1
- {gladlang-0.2.2 → gladlang-0.2.4}/src/gladlang/__main__.py +53 -5
- {gladlang-0.2.2 → gladlang-0.2.4}/src/gladlang/errors.py +2 -0
- {gladlang-0.2.2 → gladlang-0.2.4}/src/gladlang/interpreter.py +88 -56
- {gladlang-0.2.2 → gladlang-0.2.4}/src/gladlang/lexer.py +29 -25
- {gladlang-0.2.2 → gladlang-0.2.4}/src/gladlang/runtime.py +68 -9
- {gladlang-0.2.2 → gladlang-0.2.4}/src/gladlang/values.py +295 -70
- {gladlang-0.2.2 → gladlang-0.2.4/src/gladlang.egg-info}/PKG-INFO +2 -2
- {gladlang-0.2.2 → gladlang-0.2.4}/LICENSE +0 -0
- {gladlang-0.2.2 → gladlang-0.2.4}/setup.cfg +0 -0
- {gladlang-0.2.2 → gladlang-0.2.4}/src/gladlang/__init__.py +0 -0
- {gladlang-0.2.2 → gladlang-0.2.4}/src/gladlang/constants.py +0 -0
- {gladlang-0.2.2 → gladlang-0.2.4}/src/gladlang/nodes.py +0 -0
- {gladlang-0.2.2 → gladlang-0.2.4}/src/gladlang/parser.py +0 -0
- {gladlang-0.2.2 → gladlang-0.2.4}/src/gladlang.egg-info/SOURCES.txt +0 -0
- {gladlang-0.2.2 → gladlang-0.2.4}/src/gladlang.egg-info/dependency_links.txt +0 -0
- {gladlang-0.2.2 → gladlang-0.2.4}/src/gladlang.egg-info/entry_points.txt +0 -0
- {gladlang-0.2.2 → gladlang-0.2.4}/src/gladlang.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gladlang
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: The GladLang Interpreter
|
|
5
5
|
Author: Glad432
|
|
6
6
|
License: Copyright (c) 2025 - present GLAD432
|
|
@@ -465,7 +465,7 @@ LET b = 3 # Binary 011
|
|
|
465
465
|
PRINTLN a & b # 1 (AND)
|
|
466
466
|
PRINTLN a | b # 7 (OR)
|
|
467
467
|
PRINTLN a ^ b # 6 (XOR)
|
|
468
|
-
PRINTLN ~a #
|
|
468
|
+
PRINTLN ~a # 4294967290 (bitwise NOT as unsigned 32‑bit integer)
|
|
469
469
|
PRINTLN 1 << 2 # 4 (Left Shift)
|
|
470
470
|
PRINTLN 8 >> 2 # 2 (Right Shift)
|
|
471
471
|
|
|
@@ -437,7 +437,7 @@ LET b = 3 # Binary 011
|
|
|
437
437
|
PRINTLN a & b # 1 (AND)
|
|
438
438
|
PRINTLN a | b # 7 (OR)
|
|
439
439
|
PRINTLN a ^ b # 6 (XOR)
|
|
440
|
-
PRINTLN ~a #
|
|
440
|
+
PRINTLN ~a # 4294967290 (bitwise NOT as unsigned 32‑bit integer)
|
|
441
441
|
PRINTLN 1 << 2 # 4 (Left Shift)
|
|
442
442
|
PRINTLN 8 >> 2 # 2 (Right Shift)
|
|
443
443
|
|
|
@@ -140,8 +140,10 @@ def is_complete(text):
|
|
|
140
140
|
return False
|
|
141
141
|
|
|
142
142
|
depth = 0
|
|
143
|
+
bracket_depth = 0
|
|
144
|
+
brace_depth = 0
|
|
143
145
|
|
|
144
|
-
pattern = r"(\[|\]|\b(DEF|CLASS|ENUM|IF|ELSE\s+IF|ELSE|WHILE|FOR|TRY|SWITCH|ENDDEF|ENDCLASS|ENDENUM|ENDIF|ENDWHILE|ENDFOR|ENDTRY|ENDSWITCH)\b)"
|
|
146
|
+
pattern = r"(\[|\]|\{|\}|\b(DEF|CLASS|ENUM|IF|ELSE\s+IF|ELSE|WHILE|FOR|TRY|SWITCH|ENDDEF|ENDCLASS|ENDENUM|ENDIF|ENDWHILE|ENDFOR|ENDTRY|ENDSWITCH)\b)"
|
|
145
147
|
|
|
146
148
|
tokens = re.finditer(pattern, temp_text)
|
|
147
149
|
|
|
@@ -161,9 +163,25 @@ def is_complete(text):
|
|
|
161
163
|
for match in tokens:
|
|
162
164
|
token = match.group()
|
|
163
165
|
|
|
166
|
+
if token == "[":
|
|
167
|
+
bracket_depth += 1
|
|
168
|
+
continue
|
|
169
|
+
elif token == "]":
|
|
170
|
+
bracket_depth -= 1
|
|
171
|
+
continue
|
|
172
|
+
elif token == "{":
|
|
173
|
+
brace_depth += 1
|
|
174
|
+
continue
|
|
175
|
+
elif token == "}":
|
|
176
|
+
brace_depth -= 1
|
|
177
|
+
continue
|
|
178
|
+
|
|
164
179
|
if token in ("ELSE", "ELSE IF"):
|
|
165
180
|
continue
|
|
166
181
|
|
|
182
|
+
if token == "FOR" and (bracket_depth > 0 or brace_depth > 0):
|
|
183
|
+
continue
|
|
184
|
+
|
|
167
185
|
if token in start_keys:
|
|
168
186
|
depth += 1
|
|
169
187
|
elif token in end_keys:
|
|
@@ -174,11 +192,13 @@ def is_complete(text):
|
|
|
174
192
|
|
|
175
193
|
def main():
|
|
176
194
|
MAX_MEMORY_MB = 512
|
|
177
|
-
MAX_INSTRUCTIONS =
|
|
195
|
+
MAX_INSTRUCTIONS = 1_000_000
|
|
196
|
+
MAX_SOURCE_BYTES = 1_000_000
|
|
197
|
+
MAX_REPL_BUFFER = 100_000
|
|
178
198
|
|
|
179
199
|
set_memory_limit(MAX_MEMORY_MB)
|
|
180
200
|
|
|
181
|
-
GLADLANG_VERSION = "0.2.
|
|
201
|
+
GLADLANG_VERSION = "0.2.4"
|
|
182
202
|
GLADLANG_HELP = f"""
|
|
183
203
|
Usage: gladlang [command] [filename/code] [args...]
|
|
184
204
|
|
|
@@ -221,6 +241,13 @@ Commands:
|
|
|
221
241
|
|
|
222
242
|
full_text += line + "\n"
|
|
223
243
|
|
|
244
|
+
if len(full_text) > MAX_REPL_BUFFER:
|
|
245
|
+
sys.stdout.write(
|
|
246
|
+
"Error: Input buffer limit exceeded. Clearing buffer.\n"
|
|
247
|
+
)
|
|
248
|
+
full_text = ""
|
|
249
|
+
continue
|
|
250
|
+
|
|
224
251
|
if is_complete(full_text):
|
|
225
252
|
if full_text.strip() == "":
|
|
226
253
|
full_text = ""
|
|
@@ -308,8 +335,9 @@ Commands:
|
|
|
308
335
|
try:
|
|
309
336
|
candidate = Path(arg_input).resolve()
|
|
310
337
|
allowed_root = Path.cwd().resolve()
|
|
311
|
-
if not
|
|
338
|
+
if not candidate.is_relative_to(allowed_root):
|
|
312
339
|
raise PermissionError(f"Access denied: '{arg_input}'")
|
|
340
|
+
|
|
313
341
|
if candidate.is_file():
|
|
314
342
|
is_file = True
|
|
315
343
|
resolved = candidate
|
|
@@ -326,7 +354,27 @@ Commands:
|
|
|
326
354
|
f"File must have .glad extension: '{arg_input}'\n"
|
|
327
355
|
)
|
|
328
356
|
sys.exit(1)
|
|
329
|
-
|
|
357
|
+
|
|
358
|
+
file_size = path_to_read.stat().st_size
|
|
359
|
+
if file_size > MAX_SOURCE_BYTES:
|
|
360
|
+
sys.stderr.write(
|
|
361
|
+
f"File too large: '{arg_input}' ({file_size:,} bytes). "
|
|
362
|
+
f"Maximum allowed: {MAX_SOURCE_BYTES:,} bytes.\n"
|
|
363
|
+
)
|
|
364
|
+
sys.exit(1)
|
|
365
|
+
|
|
366
|
+
try:
|
|
367
|
+
text = path_to_read.read_text(encoding="utf-8")
|
|
368
|
+
except UnicodeDecodeError:
|
|
369
|
+
sys.stderr.write(
|
|
370
|
+
f"Encoding error: '{arg_input}' is not valid UTF-8. "
|
|
371
|
+
"Save the file as UTF-8 and try again.\n"
|
|
372
|
+
)
|
|
373
|
+
sys.exit(1)
|
|
374
|
+
except Exception as e:
|
|
375
|
+
sys.stderr.write(f"An unexpected error occurred: {e}\n")
|
|
376
|
+
sys.exit(1)
|
|
377
|
+
|
|
330
378
|
source_name = str(path_to_read)
|
|
331
379
|
else:
|
|
332
380
|
text = arg_input
|
|
@@ -12,6 +12,8 @@ from .values import (
|
|
|
12
12
|
Instance,
|
|
13
13
|
Enum,
|
|
14
14
|
Value,
|
|
15
|
+
TailCall,
|
|
16
|
+
BoundMethod,
|
|
15
17
|
)
|
|
16
18
|
from .nodes import *
|
|
17
19
|
from .errors import RTError
|
|
@@ -20,10 +22,15 @@ from .constants import *
|
|
|
20
22
|
|
|
21
23
|
def is_final_anywhere(table, name):
|
|
22
24
|
while table:
|
|
25
|
+
if table._finals_count == 0:
|
|
26
|
+
table = table.parent
|
|
27
|
+
continue
|
|
28
|
+
|
|
23
29
|
with table._lock:
|
|
24
30
|
if name in table.finals:
|
|
25
31
|
return True
|
|
26
32
|
table = table.parent
|
|
33
|
+
|
|
27
34
|
return False
|
|
28
35
|
|
|
29
36
|
|
|
@@ -32,6 +39,27 @@ class Interpreter:
|
|
|
32
39
|
self.dispatch_cache = {}
|
|
33
40
|
self.instruction_limit = instruction_limit
|
|
34
41
|
|
|
42
|
+
self._binop_dispatch = {
|
|
43
|
+
GL_PLUS: lambda l, r: l.added_to(r),
|
|
44
|
+
GL_MINUS: lambda l, r: l.subbed_by(r),
|
|
45
|
+
GL_MUL: lambda l, r: l.multed_by(r),
|
|
46
|
+
GL_DIV: lambda l, r: l.dived_by(r),
|
|
47
|
+
GL_MOD: lambda l, r: l.modded_by(r),
|
|
48
|
+
GL_FLOORDIV: lambda l, r: l.floordived_by(r),
|
|
49
|
+
GL_POW: lambda l, r: l.powed_by(r),
|
|
50
|
+
GL_EE: lambda l, r: l.get_comparison_eq(r),
|
|
51
|
+
GL_NE: lambda l, r: l.get_comparison_ne(r),
|
|
52
|
+
GL_LT: lambda l, r: l.get_comparison_lt(r),
|
|
53
|
+
GL_GT: lambda l, r: l.get_comparison_gt(r),
|
|
54
|
+
GL_LTE: lambda l, r: l.get_comparison_lte(r),
|
|
55
|
+
GL_GTE: lambda l, r: l.get_comparison_gte(r),
|
|
56
|
+
GL_BIT_AND: lambda l, r: l.bitted_and_by(r),
|
|
57
|
+
GL_BIT_OR: lambda l, r: l.bitted_or_by(r),
|
|
58
|
+
GL_BIT_XOR: lambda l, r: l.bitted_xor_by(r),
|
|
59
|
+
GL_LSHIFT: lambda l, r: l.lshifted_by(r),
|
|
60
|
+
GL_RSHIFT: lambda l, r: l.rshifted_by(r),
|
|
61
|
+
}
|
|
62
|
+
|
|
35
63
|
def visit(self, node, context):
|
|
36
64
|
if self.instruction_limit is not None:
|
|
37
65
|
self.instruction_limit -= 1
|
|
@@ -204,7 +232,11 @@ class Interpreter:
|
|
|
204
232
|
comp_context = Context("COMPREHENSION", context, node.pos_start)
|
|
205
233
|
comp_context.symbol_table = SymbolTable(context.symbol_table)
|
|
206
234
|
|
|
235
|
+
had_error = False
|
|
236
|
+
|
|
207
237
|
def evaluate_loops(spec_index):
|
|
238
|
+
nonlocal had_error
|
|
239
|
+
|
|
208
240
|
if spec_index >= len(node.iteration_specs):
|
|
209
241
|
val = res.register(self.visit(node.output_expr_node, comp_context))
|
|
210
242
|
if not res.error:
|
|
@@ -222,6 +254,7 @@ class Interpreter:
|
|
|
222
254
|
)
|
|
223
255
|
if error:
|
|
224
256
|
res.failure(error)
|
|
257
|
+
had_error = True
|
|
225
258
|
return
|
|
226
259
|
|
|
227
260
|
for element in iterator:
|
|
@@ -244,7 +277,7 @@ class Interpreter:
|
|
|
244
277
|
|
|
245
278
|
evaluate_loops(0)
|
|
246
279
|
|
|
247
|
-
if res.error:
|
|
280
|
+
if res.error or had_error:
|
|
248
281
|
return res
|
|
249
282
|
|
|
250
283
|
return res.success(
|
|
@@ -388,16 +421,17 @@ class Interpreter:
|
|
|
388
421
|
|
|
389
422
|
visibility = getattr(node, "target_visibility", "PUBLIC")
|
|
390
423
|
|
|
391
|
-
if
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
context,
|
|
399
|
-
)
|
|
424
|
+
if is_final_anywhere(context.symbol_table, var_name):
|
|
425
|
+
return res.failure(
|
|
426
|
+
RTError(
|
|
427
|
+
node.var_name_tok.pos_start,
|
|
428
|
+
node.var_name_tok.pos_end,
|
|
429
|
+
f"Cannot reassign constant '{var_name}'",
|
|
430
|
+
context,
|
|
400
431
|
)
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
if node.is_declaration:
|
|
401
435
|
context.symbol_table.set(var_name, value, visibility=visibility)
|
|
402
436
|
else:
|
|
403
437
|
err = context.symbol_table.update(var_name, value)
|
|
@@ -556,7 +590,11 @@ class Interpreter:
|
|
|
556
590
|
comp_context = Context("DICT_COMPREHENSION", context, node.pos_start)
|
|
557
591
|
comp_context.symbol_table = SymbolTable(context.symbol_table)
|
|
558
592
|
|
|
593
|
+
had_error = False
|
|
594
|
+
|
|
559
595
|
def evaluate_loops(spec_index):
|
|
596
|
+
nonlocal had_error
|
|
597
|
+
|
|
560
598
|
if spec_index >= len(node.iteration_specs):
|
|
561
599
|
key_val = res.register(self.visit(node.key_expr_node, comp_context))
|
|
562
600
|
if res.error:
|
|
@@ -577,6 +615,7 @@ class Interpreter:
|
|
|
577
615
|
comp_context,
|
|
578
616
|
)
|
|
579
617
|
)
|
|
618
|
+
had_error = True
|
|
580
619
|
return
|
|
581
620
|
return
|
|
582
621
|
|
|
@@ -591,6 +630,7 @@ class Interpreter:
|
|
|
591
630
|
)
|
|
592
631
|
if error:
|
|
593
632
|
res.failure(error)
|
|
633
|
+
had_error = True
|
|
594
634
|
return
|
|
595
635
|
|
|
596
636
|
for element in iterator:
|
|
@@ -613,7 +653,7 @@ class Interpreter:
|
|
|
613
653
|
|
|
614
654
|
evaluate_loops(0)
|
|
615
655
|
|
|
616
|
-
if res.error:
|
|
656
|
+
if res.error or had_error:
|
|
617
657
|
return res
|
|
618
658
|
|
|
619
659
|
return res.success(
|
|
@@ -797,7 +837,7 @@ class Interpreter:
|
|
|
797
837
|
if res.error:
|
|
798
838
|
return res
|
|
799
839
|
|
|
800
|
-
value_to_call = value_to_call.
|
|
840
|
+
value_to_call = value_to_call.set_pos(node.pos_start, node.pos_end)
|
|
801
841
|
|
|
802
842
|
for arg_node in node.arg_nodes:
|
|
803
843
|
args.append(res.register(self.visit(arg_node, context)))
|
|
@@ -813,10 +853,31 @@ class Interpreter:
|
|
|
813
853
|
def visit_ReturnNode(self, node, context):
|
|
814
854
|
res = RTResult()
|
|
815
855
|
|
|
856
|
+
tco_func = getattr(context, "_tco_func", None)
|
|
857
|
+
if tco_func is not None and isinstance(node.node_to_return, CallNode):
|
|
858
|
+
ret_node = node.node_to_return
|
|
859
|
+
|
|
860
|
+
callee = res.register(self.visit(ret_node.node_to_call, context))
|
|
861
|
+
if res.error:
|
|
862
|
+
return res
|
|
863
|
+
|
|
864
|
+
if isinstance(callee, BoundMethod):
|
|
865
|
+
underlying = callee.function_to_bind
|
|
866
|
+
else:
|
|
867
|
+
underlying = callee
|
|
868
|
+
|
|
869
|
+
if underlying is tco_func or callee is tco_func:
|
|
870
|
+
tc_args = []
|
|
871
|
+
for arg_node in ret_node.arg_nodes:
|
|
872
|
+
arg_val = res.register(self.visit(arg_node, context))
|
|
873
|
+
if res.error:
|
|
874
|
+
return res
|
|
875
|
+
tc_args.append(arg_val)
|
|
876
|
+
return res.success_return(TailCall(callee, tc_args))
|
|
877
|
+
|
|
816
878
|
value = res.register(self.visit(node.node_to_return, context))
|
|
817
879
|
if res.error:
|
|
818
880
|
return res
|
|
819
|
-
|
|
820
881
|
return res.success_return(value)
|
|
821
882
|
|
|
822
883
|
def visit_ClassNode(self, node, context):
|
|
@@ -1217,49 +1278,20 @@ class Interpreter:
|
|
|
1217
1278
|
if res.error:
|
|
1218
1279
|
return res
|
|
1219
1280
|
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
if node.op_tok.type == GL_PLUS:
|
|
1223
|
-
result, error = left.added_to(right)
|
|
1224
|
-
elif node.op_tok.type == GL_MINUS:
|
|
1225
|
-
result, error = left.subbed_by(right)
|
|
1226
|
-
elif node.op_tok.type == GL_MUL:
|
|
1227
|
-
result, error = left.multed_by(right)
|
|
1228
|
-
elif node.op_tok.type == GL_DIV:
|
|
1229
|
-
result, error = left.dived_by(right)
|
|
1230
|
-
elif node.op_tok.type == GL_MOD:
|
|
1231
|
-
result, error = left.modded_by(right)
|
|
1232
|
-
elif node.op_tok.type == GL_FLOORDIV:
|
|
1233
|
-
result, error = left.floordived_by(right)
|
|
1234
|
-
elif node.op_tok.type == GL_POW:
|
|
1235
|
-
result, error = left.powed_by(right)
|
|
1236
|
-
elif node.op_tok.type == GL_EE:
|
|
1237
|
-
result, error = left.get_comparison_eq(right)
|
|
1238
|
-
elif node.op_tok.type == GL_NE:
|
|
1239
|
-
result, error = left.get_comparison_ne(right)
|
|
1240
|
-
elif node.op_tok.type == GL_LT:
|
|
1241
|
-
result, error = left.get_comparison_lt(right)
|
|
1242
|
-
elif node.op_tok.type == GL_GT:
|
|
1243
|
-
result, error = left.get_comparison_gt(right)
|
|
1244
|
-
elif node.op_tok.type == GL_LTE:
|
|
1245
|
-
result, error = left.get_comparison_lte(right)
|
|
1246
|
-
elif node.op_tok.type == GL_GTE:
|
|
1247
|
-
result, error = left.get_comparison_gte(right)
|
|
1248
|
-
elif node.op_tok.matches(GL_KEYWORD, "IS"):
|
|
1281
|
+
if node.op_tok.matches(GL_KEYWORD, "IS"):
|
|
1249
1282
|
result, error = left.get_comparison_is(right)
|
|
1283
|
+
if error:
|
|
1284
|
+
return res.failure(error)
|
|
1285
|
+
return res.success(result.set_pos(node.pos_start, node.pos_end))
|
|
1286
|
+
|
|
1250
1287
|
elif node.op_tok.matches(GL_KEYWORD, "INSTANCEOF"):
|
|
1251
1288
|
result, error = left.get_comparison_instanceof(right)
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
elif node.op_tok.type == GL_LSHIFT:
|
|
1259
|
-
result, error = left.lshifted_by(right)
|
|
1260
|
-
elif node.op_tok.type == GL_RSHIFT:
|
|
1261
|
-
result, error = left.rshifted_by(right)
|
|
1262
|
-
else:
|
|
1289
|
+
if error:
|
|
1290
|
+
return res.failure(error)
|
|
1291
|
+
return res.success(result.set_pos(node.pos_start, node.pos_end))
|
|
1292
|
+
|
|
1293
|
+
op = self._binop_dispatch.get(node.op_tok.type)
|
|
1294
|
+
if op is None:
|
|
1263
1295
|
return res.failure(
|
|
1264
1296
|
RTError(
|
|
1265
1297
|
node.op_tok.pos_start,
|
|
@@ -1268,11 +1300,11 @@ class Interpreter:
|
|
|
1268
1300
|
context,
|
|
1269
1301
|
)
|
|
1270
1302
|
)
|
|
1271
|
-
|
|
1303
|
+
result, error = op(left, right)
|
|
1272
1304
|
if error:
|
|
1273
1305
|
return res.failure(error)
|
|
1274
|
-
|
|
1275
|
-
|
|
1306
|
+
|
|
1307
|
+
return res.success(result.set_pos(node.pos_start, node.pos_end))
|
|
1276
1308
|
|
|
1277
1309
|
def visit_TernaryOpNode(self, node, context):
|
|
1278
1310
|
res = RTResult()
|
|
@@ -3,6 +3,8 @@ from .errors import Position, IllegalCharError, InvalidSyntaxError
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class Token:
|
|
6
|
+
__slots__ = ("type", "value", "pos_start", "pos_end")
|
|
7
|
+
|
|
6
8
|
def __init__(self, type_, value=None, pos_start=None, pos_end=None):
|
|
7
9
|
self.type = type_
|
|
8
10
|
self.value = value
|
|
@@ -386,16 +388,17 @@ class Lexer:
|
|
|
386
388
|
|
|
387
389
|
tokens.append(Token(GL_LPAREN, pos_start=pos_start))
|
|
388
390
|
|
|
389
|
-
|
|
391
|
+
chars = []
|
|
390
392
|
escape_character = False
|
|
391
393
|
|
|
392
|
-
while self.current_char
|
|
394
|
+
while self.current_char is not None and (
|
|
393
395
|
self.current_char != "`" or escape_character
|
|
394
396
|
):
|
|
395
397
|
|
|
396
398
|
if not escape_character and self.current_char == "$" and self.peek() == "{":
|
|
399
|
+
string_part = "".join(chars)
|
|
397
400
|
tokens.append(Token(GL_STRING, string_part, pos_start=pos_start))
|
|
398
|
-
|
|
401
|
+
chars = []
|
|
399
402
|
|
|
400
403
|
tokens.append(Token(GL_PLUS, pos_start=self.pos))
|
|
401
404
|
tokens.append(Token(GL_IDENTIFIER, "STR", pos_start=self.pos))
|
|
@@ -450,24 +453,23 @@ class Lexer:
|
|
|
450
453
|
|
|
451
454
|
elif escape_character:
|
|
452
455
|
if self.current_char == "n":
|
|
453
|
-
|
|
456
|
+
chars.append("\n")
|
|
454
457
|
elif self.current_char == "t":
|
|
455
|
-
|
|
458
|
+
chars.append("\t")
|
|
456
459
|
elif self.current_char == "r":
|
|
457
|
-
|
|
460
|
+
chars.append("\r")
|
|
458
461
|
elif self.current_char == "`":
|
|
459
|
-
|
|
462
|
+
chars.append("`")
|
|
460
463
|
elif self.current_char == "\\":
|
|
461
|
-
|
|
464
|
+
chars.append("\\")
|
|
462
465
|
elif self.current_char == '"':
|
|
463
|
-
|
|
466
|
+
chars.append('"')
|
|
464
467
|
elif self.current_char == "'":
|
|
465
|
-
|
|
468
|
+
chars.append("'")
|
|
466
469
|
elif self.current_char == "$":
|
|
467
|
-
|
|
470
|
+
chars.append("$")
|
|
468
471
|
else:
|
|
469
|
-
|
|
470
|
-
|
|
472
|
+
chars.append(self.current_char)
|
|
471
473
|
escape_character = False
|
|
472
474
|
self.advance()
|
|
473
475
|
|
|
@@ -476,9 +478,10 @@ class Lexer:
|
|
|
476
478
|
self.advance()
|
|
477
479
|
|
|
478
480
|
else:
|
|
479
|
-
|
|
481
|
+
chars.append(self.current_char)
|
|
480
482
|
self.advance()
|
|
481
483
|
|
|
484
|
+
string_part = "".join(chars)
|
|
482
485
|
tokens.append(Token(GL_STRING, string_part, pos_start=pos_start))
|
|
483
486
|
tokens.append(Token(GL_RPAREN, pos_start=self.pos))
|
|
484
487
|
|
|
@@ -486,7 +489,7 @@ class Lexer:
|
|
|
486
489
|
return tokens
|
|
487
490
|
|
|
488
491
|
def make_string(self):
|
|
489
|
-
|
|
492
|
+
chars = []
|
|
490
493
|
pos_start = self.pos.copy()
|
|
491
494
|
|
|
492
495
|
is_multiline = False
|
|
@@ -500,20 +503,20 @@ class Lexer:
|
|
|
500
503
|
|
|
501
504
|
escape_character = False
|
|
502
505
|
|
|
503
|
-
while self.current_char
|
|
506
|
+
while self.current_char is not None:
|
|
504
507
|
if escape_character:
|
|
505
508
|
if self.current_char == "n":
|
|
506
|
-
|
|
509
|
+
chars.append("\n")
|
|
507
510
|
elif self.current_char == "t":
|
|
508
|
-
|
|
511
|
+
chars.append("\t")
|
|
509
512
|
elif self.current_char == "r":
|
|
510
|
-
|
|
513
|
+
chars.append("\r")
|
|
511
514
|
elif self.current_char == '"':
|
|
512
|
-
|
|
515
|
+
chars.append('"')
|
|
513
516
|
elif self.current_char == "\\":
|
|
514
|
-
|
|
517
|
+
chars.append("\\")
|
|
515
518
|
else:
|
|
516
|
-
|
|
519
|
+
chars.append(self.current_char)
|
|
517
520
|
escape_character = False
|
|
518
521
|
elif self.current_char == "\\":
|
|
519
522
|
escape_character = True
|
|
@@ -525,13 +528,13 @@ class Lexer:
|
|
|
525
528
|
self.advance()
|
|
526
529
|
break
|
|
527
530
|
else:
|
|
528
|
-
|
|
531
|
+
chars.append('""')
|
|
529
532
|
else:
|
|
530
|
-
|
|
533
|
+
chars.append('"')
|
|
531
534
|
else:
|
|
532
535
|
break
|
|
533
536
|
else:
|
|
534
|
-
|
|
537
|
+
chars.append(self.current_char)
|
|
535
538
|
|
|
536
539
|
self.advance()
|
|
537
540
|
|
|
@@ -540,5 +543,6 @@ class Lexer:
|
|
|
540
543
|
pos_start, self.pos, "Unterminated string literal"
|
|
541
544
|
)
|
|
542
545
|
|
|
546
|
+
string = "".join(chars)
|
|
543
547
|
self.advance()
|
|
544
548
|
return Token(GL_STRING, string, pos_start, self.pos)
|
|
@@ -1,23 +1,40 @@
|
|
|
1
1
|
from threading import Lock
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
class _NoLock:
|
|
5
|
+
__slots__ = ()
|
|
6
|
+
|
|
7
|
+
def __enter__(self):
|
|
8
|
+
return self
|
|
9
|
+
|
|
10
|
+
def __exit__(self, *args):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
4
14
|
class SymbolTable:
|
|
15
|
+
_THREADING_ENABLED = False
|
|
16
|
+
|
|
5
17
|
def __init__(self, parent=None):
|
|
6
18
|
self.symbols = {}
|
|
7
19
|
self.parent = parent
|
|
8
20
|
self.finals = set()
|
|
9
21
|
self.visibilities = {}
|
|
10
22
|
self.defining_classes = {}
|
|
11
|
-
self._lock = Lock()
|
|
23
|
+
self._lock = Lock() if SymbolTable._THREADING_ENABLED else _NoLock()
|
|
24
|
+
self._finals_count = 0
|
|
12
25
|
|
|
13
26
|
def set(
|
|
14
27
|
self, name, value, visibility="PUBLIC", as_final=False, defining_class=None
|
|
15
28
|
):
|
|
16
29
|
with self._lock:
|
|
17
30
|
self.symbols[name] = value
|
|
18
|
-
|
|
31
|
+
if visibility != "PUBLIC":
|
|
32
|
+
self.visibilities[name] = visibility
|
|
33
|
+
|
|
19
34
|
if as_final:
|
|
20
35
|
self.finals.add(name)
|
|
36
|
+
self._finals_count += 1
|
|
37
|
+
|
|
21
38
|
if defining_class:
|
|
22
39
|
self.defining_classes[name] = defining_class
|
|
23
40
|
|
|
@@ -34,20 +51,28 @@ class SymbolTable:
|
|
|
34
51
|
with self._lock:
|
|
35
52
|
if name in self.symbols:
|
|
36
53
|
return f"Variable '{name}' is already defined"
|
|
54
|
+
|
|
37
55
|
if as_final and self.is_final_in_ancestors(name):
|
|
38
56
|
return f"Cannot declare constant '{name}' because it is already defined as constant in outer scope"
|
|
57
|
+
|
|
39
58
|
self.symbols[name] = value
|
|
40
|
-
|
|
59
|
+
if visibility != "PUBLIC":
|
|
60
|
+
self.visibilities[name] = visibility
|
|
61
|
+
|
|
41
62
|
if as_final:
|
|
42
63
|
self.finals.add(name)
|
|
64
|
+
self._finals_count += 1
|
|
65
|
+
|
|
43
66
|
return None
|
|
44
67
|
|
|
45
68
|
def get(self, name):
|
|
46
69
|
with self._lock:
|
|
47
70
|
value = self.symbols.get(name)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
71
|
+
has_parent = self.parent is not None
|
|
72
|
+
|
|
73
|
+
if value is None and has_parent:
|
|
74
|
+
return self.parent.get(name)
|
|
75
|
+
return value
|
|
51
76
|
|
|
52
77
|
def update(self, name, value):
|
|
53
78
|
with self._lock:
|
|
@@ -56,9 +81,11 @@ class SymbolTable:
|
|
|
56
81
|
if name in self.symbols:
|
|
57
82
|
self.symbols[name] = value
|
|
58
83
|
return None
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
84
|
+
has_parent = self.parent is not None
|
|
85
|
+
|
|
86
|
+
if has_parent:
|
|
87
|
+
return self.parent.update(name, value)
|
|
88
|
+
return f"'{name}' is not defined"
|
|
62
89
|
|
|
63
90
|
def remove(self, name):
|
|
64
91
|
with self._lock:
|
|
@@ -78,10 +105,22 @@ class SymbolTable:
|
|
|
78
105
|
new_table.visibilities = self.visibilities.copy()
|
|
79
106
|
new_table.finals = self.finals.copy()
|
|
80
107
|
new_table.defining_classes = self.defining_classes.copy()
|
|
108
|
+
new_table._finals_count = len(new_table.finals)
|
|
81
109
|
return new_table
|
|
82
110
|
|
|
83
111
|
|
|
84
112
|
class Context:
|
|
113
|
+
__slots__ = (
|
|
114
|
+
"display_name",
|
|
115
|
+
"parent",
|
|
116
|
+
"parent_entry_pos",
|
|
117
|
+
"symbol_table",
|
|
118
|
+
"depth",
|
|
119
|
+
"active_class",
|
|
120
|
+
"is_static",
|
|
121
|
+
"_tco_func",
|
|
122
|
+
)
|
|
123
|
+
|
|
85
124
|
def __init__(self, display_name, parent=None, parent_entry_pos=None):
|
|
86
125
|
self.display_name = display_name
|
|
87
126
|
self.parent = parent
|
|
@@ -93,7 +132,19 @@ class Context:
|
|
|
93
132
|
|
|
94
133
|
|
|
95
134
|
class RTResult:
|
|
135
|
+
__slots__ = (
|
|
136
|
+
"value",
|
|
137
|
+
"error",
|
|
138
|
+
"return_value",
|
|
139
|
+
"should_return",
|
|
140
|
+
"should_break",
|
|
141
|
+
"should_continue",
|
|
142
|
+
)
|
|
143
|
+
|
|
96
144
|
def __init__(self):
|
|
145
|
+
self.reset()
|
|
146
|
+
|
|
147
|
+
def reset(self):
|
|
97
148
|
self.value = None
|
|
98
149
|
self.error = None
|
|
99
150
|
self.return_value = None
|
|
@@ -101,7 +152,14 @@ class RTResult:
|
|
|
101
152
|
self.should_break = False
|
|
102
153
|
self.should_continue = False
|
|
103
154
|
|
|
155
|
+
return self
|
|
156
|
+
|
|
104
157
|
def register(self, res):
|
|
158
|
+
if res.error is None and not (
|
|
159
|
+
res.should_return or res.should_break or res.should_continue
|
|
160
|
+
):
|
|
161
|
+
return res.value
|
|
162
|
+
|
|
105
163
|
if res.error:
|
|
106
164
|
self.error = res.error
|
|
107
165
|
if res.should_return:
|
|
@@ -111,6 +169,7 @@ class RTResult:
|
|
|
111
169
|
self.should_break = True
|
|
112
170
|
if res.should_continue:
|
|
113
171
|
self.should_continue = True
|
|
172
|
+
|
|
114
173
|
return res.value
|
|
115
174
|
|
|
116
175
|
def success(self, value):
|
|
@@ -7,10 +7,21 @@ from .lexer import Token
|
|
|
7
7
|
from .nodes import *
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
class TailCall:
|
|
11
|
+
__slots__ = ("function", "args")
|
|
12
|
+
|
|
13
|
+
def __init__(self, function, args):
|
|
14
|
+
self.function = function
|
|
15
|
+
self.args = args
|
|
16
|
+
|
|
17
|
+
|
|
10
18
|
class Value:
|
|
19
|
+
__slots__ = ("pos_start", "pos_end", "context")
|
|
20
|
+
|
|
11
21
|
def __init__(self):
|
|
12
|
-
self.
|
|
13
|
-
self.
|
|
22
|
+
self.pos_start = None
|
|
23
|
+
self.pos_end = None
|
|
24
|
+
self.context = None
|
|
14
25
|
|
|
15
26
|
def set_pos(self, pos_start=None, pos_end=None):
|
|
16
27
|
self.pos_start = pos_start
|
|
@@ -152,13 +163,32 @@ class Value:
|
|
|
152
163
|
|
|
153
164
|
|
|
154
165
|
class Number(Value):
|
|
166
|
+
MAX_INT_BITS = 100_000
|
|
167
|
+
|
|
168
|
+
__slots__ = ("value",)
|
|
169
|
+
|
|
155
170
|
def __init__(self, value):
|
|
156
171
|
super().__init__()
|
|
157
172
|
self.value = value
|
|
158
173
|
|
|
159
174
|
def added_to(self, other):
|
|
160
175
|
if isinstance(other, Number):
|
|
161
|
-
|
|
176
|
+
result = self.value + other.value
|
|
177
|
+
if isinstance(result, int) and result.bit_length() > Number.MAX_INT_BITS:
|
|
178
|
+
return None, RTError(
|
|
179
|
+
other.pos_start,
|
|
180
|
+
other.pos_end,
|
|
181
|
+
"Arithmetic result too large (exceeds integer size limit)",
|
|
182
|
+
self.context,
|
|
183
|
+
)
|
|
184
|
+
if isinstance(result, float) and math.isinf(result):
|
|
185
|
+
return None, RTError(
|
|
186
|
+
other.pos_start,
|
|
187
|
+
other.pos_end,
|
|
188
|
+
"Arithmetic result is infinite (float overflow)",
|
|
189
|
+
self.context,
|
|
190
|
+
)
|
|
191
|
+
return Number(result).set_context(self.context), None
|
|
162
192
|
elif isinstance(other, String):
|
|
163
193
|
return String(str(self.value) + other.value).set_context(self.context), None
|
|
164
194
|
else:
|
|
@@ -166,13 +196,43 @@ class Number(Value):
|
|
|
166
196
|
|
|
167
197
|
def subbed_by(self, other):
|
|
168
198
|
if isinstance(other, Number):
|
|
169
|
-
|
|
199
|
+
result = self.value - other.value
|
|
200
|
+
if isinstance(result, int) and result.bit_length() > Number.MAX_INT_BITS:
|
|
201
|
+
return None, RTError(
|
|
202
|
+
other.pos_start,
|
|
203
|
+
other.pos_end,
|
|
204
|
+
"Arithmetic result too large (exceeds integer size limit)",
|
|
205
|
+
self.context,
|
|
206
|
+
)
|
|
207
|
+
if isinstance(result, float) and math.isinf(result):
|
|
208
|
+
return None, RTError(
|
|
209
|
+
other.pos_start,
|
|
210
|
+
other.pos_end,
|
|
211
|
+
"Arithmetic result is infinite (float overflow)",
|
|
212
|
+
self.context,
|
|
213
|
+
)
|
|
214
|
+
return Number(result).set_context(self.context), None
|
|
170
215
|
else:
|
|
171
216
|
return None, Value.illegal_operation(self, other)
|
|
172
217
|
|
|
173
218
|
def multed_by(self, other):
|
|
174
219
|
if isinstance(other, Number):
|
|
175
|
-
|
|
220
|
+
result = self.value * other.value
|
|
221
|
+
if isinstance(result, int) and result.bit_length() > Number.MAX_INT_BITS:
|
|
222
|
+
return None, RTError(
|
|
223
|
+
other.pos_start,
|
|
224
|
+
other.pos_end,
|
|
225
|
+
"Arithmetic result too large (exceeds integer size limit)",
|
|
226
|
+
self.context,
|
|
227
|
+
)
|
|
228
|
+
if isinstance(result, float) and math.isinf(result):
|
|
229
|
+
return None, RTError(
|
|
230
|
+
other.pos_start,
|
|
231
|
+
other.pos_end,
|
|
232
|
+
"Arithmetic result is infinite (float overflow)",
|
|
233
|
+
self.context,
|
|
234
|
+
)
|
|
235
|
+
return Number(result).set_context(self.context), None
|
|
176
236
|
else:
|
|
177
237
|
return None, Value.illegal_operation(self, other)
|
|
178
238
|
|
|
@@ -220,7 +280,7 @@ class Number(Value):
|
|
|
220
280
|
)
|
|
221
281
|
try:
|
|
222
282
|
result = self.value**other.value
|
|
223
|
-
except (ValueError, ZeroDivisionError) as e:
|
|
283
|
+
except (ValueError, ZeroDivisionError, OverflowError) as e:
|
|
224
284
|
return None, RTError(
|
|
225
285
|
other.pos_start, other.pos_end, str(e), self.context
|
|
226
286
|
)
|
|
@@ -240,6 +300,13 @@ class Number(Value):
|
|
|
240
300
|
"Math domain error: result is NaN",
|
|
241
301
|
self.context,
|
|
242
302
|
)
|
|
303
|
+
if isinstance(result, float) and math.isinf(result):
|
|
304
|
+
return None, RTError(
|
|
305
|
+
other.pos_start,
|
|
306
|
+
other.pos_end,
|
|
307
|
+
f"Arithmetic result is infinite (float overflow)",
|
|
308
|
+
self.context,
|
|
309
|
+
)
|
|
243
310
|
return Number(result).set_context(self.context), None
|
|
244
311
|
else:
|
|
245
312
|
return None, Value.illegal_operation(self, other)
|
|
@@ -294,24 +361,27 @@ class Number(Value):
|
|
|
294
361
|
|
|
295
362
|
def anded_by(self, other):
|
|
296
363
|
if isinstance(other, Number):
|
|
297
|
-
|
|
298
|
-
Number(
|
|
299
|
-
|
|
300
|
-
|
|
364
|
+
if self.is_true() and other.is_true():
|
|
365
|
+
return Number(1), None
|
|
366
|
+
else:
|
|
367
|
+
return Number(0), None
|
|
301
368
|
else:
|
|
302
|
-
return None,
|
|
369
|
+
return None, self.illegal_operation(other)
|
|
303
370
|
|
|
304
371
|
def ored_by(self, other):
|
|
305
372
|
if isinstance(other, Number):
|
|
306
|
-
|
|
307
|
-
Number(
|
|
308
|
-
|
|
309
|
-
|
|
373
|
+
if self.is_true() or other.is_true():
|
|
374
|
+
return Number(1), None
|
|
375
|
+
else:
|
|
376
|
+
return Number(0), None
|
|
310
377
|
else:
|
|
311
|
-
return None,
|
|
378
|
+
return None, self.illegal_operation(other)
|
|
312
379
|
|
|
313
380
|
def notted(self):
|
|
314
|
-
|
|
381
|
+
if self.is_true():
|
|
382
|
+
return Number(0), None
|
|
383
|
+
else:
|
|
384
|
+
return Number(1), None
|
|
315
385
|
|
|
316
386
|
def bitted_and_by(self, other):
|
|
317
387
|
if isinstance(other, Number):
|
|
@@ -369,21 +439,55 @@ class Number(Value):
|
|
|
369
439
|
return str(self.value)
|
|
370
440
|
|
|
371
441
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
442
|
+
class _FrozenNull(Number):
|
|
443
|
+
__slots__ = ()
|
|
444
|
+
|
|
445
|
+
def set_pos(self, *args):
|
|
446
|
+
return self
|
|
447
|
+
|
|
448
|
+
def set_context(self, *args):
|
|
449
|
+
return self
|
|
450
|
+
|
|
451
|
+
def copy(self):
|
|
452
|
+
return Number(self.value)
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
Number.false = _FrozenNull(0)
|
|
456
|
+
Number.true = _FrozenNull(1)
|
|
457
|
+
Number.null = _FrozenNull(0)
|
|
375
458
|
|
|
376
459
|
|
|
377
460
|
class String(Value):
|
|
461
|
+
MAX_STRING_SIZE = 10_000_000
|
|
462
|
+
|
|
463
|
+
__slots__ = ("value",)
|
|
464
|
+
|
|
378
465
|
def __init__(self, value):
|
|
379
466
|
super().__init__()
|
|
380
467
|
self.value = value
|
|
381
468
|
|
|
382
469
|
def added_to(self, other):
|
|
383
470
|
if isinstance(other, String):
|
|
471
|
+
new_len = len(self.value) + len(other.value)
|
|
472
|
+
if new_len > String.MAX_STRING_SIZE:
|
|
473
|
+
return None, RTError(
|
|
474
|
+
other.pos_start,
|
|
475
|
+
other.pos_end,
|
|
476
|
+
f"String concatenation result ({new_len:,} chars) exceeds maximum allowed size ({String.MAX_STRING_SIZE:,} chars)",
|
|
477
|
+
self.context,
|
|
478
|
+
)
|
|
384
479
|
return String(self.value + other.value).set_context(self.context), None
|
|
385
480
|
elif isinstance(other, Number):
|
|
386
|
-
|
|
481
|
+
suffix = str(other.value)
|
|
482
|
+
new_len = len(self.value) + len(suffix)
|
|
483
|
+
if new_len > String.MAX_STRING_SIZE:
|
|
484
|
+
return None, RTError(
|
|
485
|
+
other.pos_start,
|
|
486
|
+
other.pos_end,
|
|
487
|
+
f"String concatenation result exceeds maximum allowed size ({String.MAX_STRING_SIZE:,} chars)",
|
|
488
|
+
self.context,
|
|
489
|
+
)
|
|
490
|
+
return String(self.value + suffix).set_context(self.context), None
|
|
387
491
|
else:
|
|
388
492
|
return None, self.illegal_operation(other)
|
|
389
493
|
|
|
@@ -471,6 +575,8 @@ class String(Value):
|
|
|
471
575
|
class List(Value):
|
|
472
576
|
MAX_LIST_SIZE = 1_000_000
|
|
473
577
|
|
|
578
|
+
__slots__ = ("elements",)
|
|
579
|
+
|
|
474
580
|
def __init__(self, elements):
|
|
475
581
|
super().__init__()
|
|
476
582
|
self.elements = elements
|
|
@@ -480,6 +586,15 @@ class List(Value):
|
|
|
480
586
|
|
|
481
587
|
def added_to(self, other):
|
|
482
588
|
if isinstance(other, List):
|
|
589
|
+
new_len = len(self.elements) + len(other.elements)
|
|
590
|
+
if new_len > List.MAX_LIST_SIZE:
|
|
591
|
+
return None, RTError(
|
|
592
|
+
other.pos_start,
|
|
593
|
+
other.pos_end,
|
|
594
|
+
f"List concatenation result ({new_len}) exceeds maximum "
|
|
595
|
+
f"allowed size ({List.MAX_LIST_SIZE})",
|
|
596
|
+
self.context,
|
|
597
|
+
)
|
|
483
598
|
new_list = List(self.elements + other.elements)
|
|
484
599
|
new_list.set_context(self.context)
|
|
485
600
|
return new_list, None
|
|
@@ -605,6 +720,8 @@ class List(Value):
|
|
|
605
720
|
class Dict(Value):
|
|
606
721
|
MAX_DICT_SIZE = 1_000_000
|
|
607
722
|
|
|
723
|
+
__slots__ = ("elements",)
|
|
724
|
+
|
|
608
725
|
def __init__(self, elements):
|
|
609
726
|
super().__init__()
|
|
610
727
|
self.elements = elements
|
|
@@ -661,6 +778,14 @@ class Dict(Value):
|
|
|
661
778
|
self.context,
|
|
662
779
|
)
|
|
663
780
|
|
|
781
|
+
if key.value not in self.elements and len(self.elements) >= Dict.MAX_DICT_SIZE:
|
|
782
|
+
return None, RTError(
|
|
783
|
+
self.pos_start,
|
|
784
|
+
self.pos_end,
|
|
785
|
+
f"Dict size limit ({Dict.MAX_DICT_SIZE:,} entries) reached. Cannot insert more keys.",
|
|
786
|
+
self.context,
|
|
787
|
+
)
|
|
788
|
+
|
|
664
789
|
self.elements[key.value] = value
|
|
665
790
|
return value, None
|
|
666
791
|
|
|
@@ -731,6 +856,8 @@ class Dict(Value):
|
|
|
731
856
|
|
|
732
857
|
|
|
733
858
|
class BaseFunction(Value):
|
|
859
|
+
__slots__ = ("name",)
|
|
860
|
+
|
|
734
861
|
def __init__(self, name):
|
|
735
862
|
super().__init__()
|
|
736
863
|
self.name = name or "<anonymous>"
|
|
@@ -793,6 +920,16 @@ class BaseFunction(Value):
|
|
|
793
920
|
|
|
794
921
|
|
|
795
922
|
class Function(BaseFunction):
|
|
923
|
+
__slots__ = (
|
|
924
|
+
"body_node",
|
|
925
|
+
"arg_name_toks",
|
|
926
|
+
"arg_names",
|
|
927
|
+
"context",
|
|
928
|
+
"visibility",
|
|
929
|
+
"defining_class",
|
|
930
|
+
"is_static",
|
|
931
|
+
)
|
|
932
|
+
|
|
796
933
|
def __init__(
|
|
797
934
|
self,
|
|
798
935
|
name,
|
|
@@ -814,35 +951,60 @@ class Function(BaseFunction):
|
|
|
814
951
|
|
|
815
952
|
def execute(self, args, interpreter):
|
|
816
953
|
res = RTResult()
|
|
954
|
+
current_func = self
|
|
955
|
+
current_args = args
|
|
956
|
+
base_depth = None
|
|
957
|
+
|
|
958
|
+
while True:
|
|
959
|
+
new_context = current_func.generate_new_context()
|
|
960
|
+
new_context.active_class = current_func.defining_class
|
|
961
|
+
new_context.is_static = current_func.is_static
|
|
962
|
+
|
|
963
|
+
if base_depth is None:
|
|
964
|
+
base_depth = new_context.depth
|
|
965
|
+
if base_depth > 2000:
|
|
966
|
+
return res.failure(
|
|
967
|
+
RTError(
|
|
968
|
+
current_func.pos_start,
|
|
969
|
+
current_func.pos_end,
|
|
970
|
+
"Recursion limit exceeded",
|
|
971
|
+
current_func.context,
|
|
972
|
+
)
|
|
973
|
+
)
|
|
974
|
+
else:
|
|
975
|
+
new_context.depth = base_depth
|
|
817
976
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
new_context.active_class = self.defining_class
|
|
821
|
-
new_context.is_static = self.is_static
|
|
977
|
+
new_context._tco_func = current_func
|
|
822
978
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
self.pos_start,
|
|
827
|
-
self.pos_end,
|
|
828
|
-
"Recursion limit exceeded",
|
|
829
|
-
self.context,
|
|
979
|
+
res.register(
|
|
980
|
+
current_func.check_and_populate_args(
|
|
981
|
+
current_func.arg_names, current_args, new_context
|
|
830
982
|
)
|
|
831
983
|
)
|
|
832
984
|
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
985
|
+
if res.error:
|
|
986
|
+
return res
|
|
987
|
+
|
|
988
|
+
value_result = interpreter.visit(current_func.body_node, new_context)
|
|
989
|
+
if value_result.error:
|
|
990
|
+
return value_result
|
|
836
991
|
|
|
837
|
-
|
|
992
|
+
if value_result.should_return:
|
|
993
|
+
ret_val = value_result.return_value
|
|
994
|
+
if isinstance(ret_val, TailCall):
|
|
995
|
+
callee = ret_val.function
|
|
838
996
|
|
|
839
|
-
|
|
840
|
-
|
|
997
|
+
if isinstance(callee, BoundMethod):
|
|
998
|
+
current_func = callee.function_to_bind
|
|
999
|
+
else:
|
|
1000
|
+
current_func = callee
|
|
841
1001
|
|
|
842
|
-
|
|
843
|
-
|
|
1002
|
+
current_args = ret_val.args
|
|
1003
|
+
res = RTResult()
|
|
1004
|
+
continue
|
|
1005
|
+
return res.success(ret_val)
|
|
844
1006
|
|
|
845
|
-
|
|
1007
|
+
return res.success(value_result.value or Number.null.copy())
|
|
846
1008
|
|
|
847
1009
|
def copy(self):
|
|
848
1010
|
copy = Function(
|
|
@@ -861,6 +1023,8 @@ class Function(BaseFunction):
|
|
|
861
1023
|
|
|
862
1024
|
|
|
863
1025
|
class FunctionGroup(BaseFunction):
|
|
1026
|
+
__slots__ = ("functions", "visibility", "is_static", "defining_class")
|
|
1027
|
+
|
|
864
1028
|
def __init__(self, name):
|
|
865
1029
|
super().__init__(name)
|
|
866
1030
|
self.functions = {}
|
|
@@ -934,6 +1098,8 @@ class FunctionGroup(BaseFunction):
|
|
|
934
1098
|
|
|
935
1099
|
|
|
936
1100
|
class Class(BaseFunction):
|
|
1101
|
+
__slots__ = ("superclasses", "methods", "static_symbol_table", "mro")
|
|
1102
|
+
|
|
937
1103
|
def __init__(self, name, superclasses, methods, static_symbol_table=None, mro=None):
|
|
938
1104
|
super().__init__(name)
|
|
939
1105
|
self.superclasses = superclasses
|
|
@@ -1135,6 +1301,8 @@ class Class(BaseFunction):
|
|
|
1135
1301
|
|
|
1136
1302
|
|
|
1137
1303
|
class Instance(Value):
|
|
1304
|
+
__slots__ = ("class_ref", "symbol_table")
|
|
1305
|
+
|
|
1138
1306
|
def __init__(self, class_ref):
|
|
1139
1307
|
super().__init__()
|
|
1140
1308
|
self.class_ref = class_ref
|
|
@@ -1337,6 +1505,8 @@ class Instance(Value):
|
|
|
1337
1505
|
|
|
1338
1506
|
|
|
1339
1507
|
class Super(Value):
|
|
1508
|
+
__slots__ = ("instance", "start_class")
|
|
1509
|
+
|
|
1340
1510
|
def __init__(self, instance, start_class):
|
|
1341
1511
|
super().__init__()
|
|
1342
1512
|
self.instance = instance
|
|
@@ -1418,6 +1588,8 @@ class Super(Value):
|
|
|
1418
1588
|
|
|
1419
1589
|
|
|
1420
1590
|
class Type(Value):
|
|
1591
|
+
__slots__ = ("name",)
|
|
1592
|
+
|
|
1421
1593
|
def __init__(self, name):
|
|
1422
1594
|
super().__init__()
|
|
1423
1595
|
self.name = name
|
|
@@ -1434,6 +1606,8 @@ class Type(Value):
|
|
|
1434
1606
|
|
|
1435
1607
|
|
|
1436
1608
|
class Enum(Value):
|
|
1609
|
+
__slots__ = ("name", "elements_dict")
|
|
1610
|
+
|
|
1437
1611
|
def __init__(self, name, elements_dict):
|
|
1438
1612
|
super().__init__()
|
|
1439
1613
|
self.name = name
|
|
@@ -1480,13 +1654,21 @@ class Enum(Value):
|
|
|
1480
1654
|
|
|
1481
1655
|
|
|
1482
1656
|
class BoundMethod(BaseFunction):
|
|
1657
|
+
__slots__ = (
|
|
1658
|
+
"function_to_bind",
|
|
1659
|
+
"instance",
|
|
1660
|
+
"context",
|
|
1661
|
+
"visibility",
|
|
1662
|
+
"defining_class",
|
|
1663
|
+
"is_static",
|
|
1664
|
+
)
|
|
1665
|
+
|
|
1483
1666
|
def __init__(self, name, function_to_bind, instance):
|
|
1484
1667
|
super().__init__(name)
|
|
1485
1668
|
self.function_to_bind = function_to_bind
|
|
1486
1669
|
self.instance = instance
|
|
1487
1670
|
self.context = function_to_bind.context
|
|
1488
1671
|
self.set_pos(function_to_bind.pos_start, function_to_bind.pos_end)
|
|
1489
|
-
|
|
1490
1672
|
self.visibility = getattr(function_to_bind, "visibility", "PUBLIC")
|
|
1491
1673
|
self.defining_class = getattr(function_to_bind, "defining_class", None)
|
|
1492
1674
|
self.is_static = getattr(function_to_bind, "is_static", False)
|
|
@@ -1501,43 +1683,74 @@ class BoundMethod(BaseFunction):
|
|
|
1501
1683
|
full_args = [self.instance] + args
|
|
1502
1684
|
return self.function_to_bind.execute(full_args, interpreter)
|
|
1503
1685
|
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1686
|
+
current_func = self.function_to_bind
|
|
1687
|
+
current_instance = self.instance
|
|
1688
|
+
current_args = args
|
|
1689
|
+
base_depth = None
|
|
1690
|
+
|
|
1691
|
+
while True:
|
|
1692
|
+
new_context = current_func.generate_new_context()
|
|
1693
|
+
new_context.active_class = current_func.defining_class
|
|
1694
|
+
new_context.is_static = current_func.is_static
|
|
1695
|
+
|
|
1696
|
+
if base_depth is None:
|
|
1697
|
+
base_depth = new_context.depth
|
|
1698
|
+
if base_depth > 2000:
|
|
1699
|
+
return res.failure(
|
|
1700
|
+
RTError(
|
|
1701
|
+
current_func.pos_start,
|
|
1702
|
+
current_func.pos_end,
|
|
1703
|
+
"Recursion limit exceeded",
|
|
1704
|
+
current_func.context,
|
|
1705
|
+
)
|
|
1706
|
+
)
|
|
1707
|
+
else:
|
|
1708
|
+
new_context.depth = base_depth
|
|
1509
1709
|
|
|
1510
|
-
|
|
1710
|
+
new_context.symbol_table.set("THIS", current_instance)
|
|
1711
|
+
new_context._tco_func = current_func
|
|
1511
1712
|
|
|
1512
|
-
|
|
1713
|
+
original_arg_names = current_func.arg_names
|
|
1714
|
+
actual_args = current_args
|
|
1513
1715
|
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
actual_args = args[1:]
|
|
1716
|
+
if len(actual_args) > 0 and actual_args[0] is current_instance:
|
|
1717
|
+
actual_args = actual_args[1:]
|
|
1517
1718
|
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1719
|
+
if len(original_arg_names) > 0 and original_arg_names[0] == "THIS":
|
|
1720
|
+
expected_arg_names = original_arg_names[1:]
|
|
1721
|
+
else:
|
|
1722
|
+
expected_arg_names = original_arg_names
|
|
1522
1723
|
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1724
|
+
res.register(
|
|
1725
|
+
current_func.check_and_populate_args(
|
|
1726
|
+
expected_arg_names, actual_args, new_context
|
|
1727
|
+
)
|
|
1526
1728
|
)
|
|
1527
|
-
)
|
|
1528
1729
|
|
|
1529
|
-
|
|
1530
|
-
|
|
1730
|
+
if res.error:
|
|
1731
|
+
return res
|
|
1531
1732
|
|
|
1532
|
-
|
|
1733
|
+
value_result = interpreter.visit(current_func.body_node, new_context)
|
|
1734
|
+
if value_result.error:
|
|
1735
|
+
return value_result
|
|
1533
1736
|
|
|
1534
|
-
|
|
1535
|
-
|
|
1737
|
+
if value_result.should_return:
|
|
1738
|
+
ret_val = value_result.return_value
|
|
1739
|
+
if isinstance(ret_val, TailCall):
|
|
1740
|
+
callee = ret_val.function
|
|
1536
1741
|
|
|
1537
|
-
|
|
1538
|
-
|
|
1742
|
+
if isinstance(callee, BoundMethod):
|
|
1743
|
+
current_func = callee.function_to_bind
|
|
1744
|
+
current_instance = callee.instance
|
|
1745
|
+
else:
|
|
1746
|
+
current_func = callee
|
|
1539
1747
|
|
|
1540
|
-
|
|
1748
|
+
current_args = ret_val.args
|
|
1749
|
+
res = RTResult()
|
|
1750
|
+
continue
|
|
1751
|
+
return res.success(ret_val)
|
|
1752
|
+
|
|
1753
|
+
return res.success(value_result.value or Number.null.copy())
|
|
1541
1754
|
|
|
1542
1755
|
def copy(self):
|
|
1543
1756
|
return (
|
|
@@ -1548,6 +1761,8 @@ class BoundMethod(BaseFunction):
|
|
|
1548
1761
|
|
|
1549
1762
|
|
|
1550
1763
|
class BuiltInFunction(BaseFunction):
|
|
1764
|
+
__slots__ = ()
|
|
1765
|
+
|
|
1551
1766
|
def __init__(self, name):
|
|
1552
1767
|
super().__init__(name)
|
|
1553
1768
|
|
|
@@ -1672,8 +1887,10 @@ class BuiltInFunction(BaseFunction):
|
|
|
1672
1887
|
if res.error:
|
|
1673
1888
|
return res
|
|
1674
1889
|
|
|
1675
|
-
|
|
1676
|
-
|
|
1890
|
+
if args[0].is_true():
|
|
1891
|
+
return res.success(Number(1))
|
|
1892
|
+
else:
|
|
1893
|
+
return res.success(Number(0))
|
|
1677
1894
|
|
|
1678
1895
|
elif self.name == "LEN":
|
|
1679
1896
|
res.register(self.check_args(["value"], args))
|
|
@@ -1703,6 +1920,14 @@ class BuiltInFunction(BaseFunction):
|
|
|
1703
1920
|
self.context,
|
|
1704
1921
|
)
|
|
1705
1922
|
)
|
|
1923
|
+
return res.failure(
|
|
1924
|
+
RTError(
|
|
1925
|
+
self.pos_start,
|
|
1926
|
+
self.pos_end,
|
|
1927
|
+
f"Unknown built-in function '{self.name}'",
|
|
1928
|
+
self.context,
|
|
1929
|
+
)
|
|
1930
|
+
)
|
|
1706
1931
|
|
|
1707
1932
|
def copy(self):
|
|
1708
1933
|
copy = BuiltInFunction(self.name)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gladlang
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: The GladLang Interpreter
|
|
5
5
|
Author: Glad432
|
|
6
6
|
License: Copyright (c) 2025 - present GLAD432
|
|
@@ -465,7 +465,7 @@ LET b = 3 # Binary 011
|
|
|
465
465
|
PRINTLN a & b # 1 (AND)
|
|
466
466
|
PRINTLN a | b # 7 (OR)
|
|
467
467
|
PRINTLN a ^ b # 6 (XOR)
|
|
468
|
-
PRINTLN ~a #
|
|
468
|
+
PRINTLN ~a # 4294967290 (bitwise NOT as unsigned 32‑bit integer)
|
|
469
469
|
PRINTLN 1 << 2 # 4 (Left Shift)
|
|
470
470
|
PRINTLN 8 >> 2 # 2 (Right Shift)
|
|
471
471
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|