inscript-lang 2.0.1__tar.gz → 2.0.2__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.
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/PKG-INFO +1 -1
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/inscript.py +1 -1
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/inscript_lang.egg-info/PKG-INFO +1 -1
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/interpreter.py +65 -36
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/pyproject.toml +1 -1
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/repl.py +1 -1
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/README.md +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/analyzer.py +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/ast_nodes.py +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/compiler.py +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/environment.py +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/errors.py +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/inscript_fmt.py +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/inscript_lang.egg-info/SOURCES.txt +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/inscript_lang.egg-info/dependency_links.txt +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/inscript_lang.egg-info/entry_points.txt +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/inscript_lang.egg-info/requires.txt +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/inscript_lang.egg-info/top_level.txt +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/inscript_test.py +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/lexer.py +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/parser.py +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/pygame_backend.py +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/setup.cfg +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/setup.py +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/stdlib.py +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/stdlib_extended.py +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/stdlib_extended_2.py +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/stdlib_game.py +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/stdlib_values.py +0 -0
- {inscript_lang-2.0.1 → inscript_lang-2.0.2}/vm.py +0 -0
|
@@ -2516,41 +2516,76 @@ class Interpreter(Visitor):
|
|
|
2516
2516
|
cond = self.visit(node.condition)
|
|
2517
2517
|
return self.visit(node.then_expr) if cond else self.visit(node.else_expr)
|
|
2518
2518
|
|
|
2519
|
+
@staticmethod
|
|
2520
|
+
def _fstring_segments(template: str):
|
|
2521
|
+
"""v2.0.2: brace-depth-aware f-string segment splitter.
|
|
2522
|
+
Returns list of (kind, text) where kind is "lit" or "expr".
|
|
2523
|
+
Handles nested braces (match, for, object literals) correctly.
|
|
2524
|
+
{{ and }} in source are stored as sentinel \x00{ and }\x00.
|
|
2525
|
+
"""
|
|
2526
|
+
segments = []
|
|
2527
|
+
i = 0
|
|
2528
|
+
n = len(template)
|
|
2529
|
+
lit_buf = []
|
|
2530
|
+
while i < n:
|
|
2531
|
+
ch = template[i]
|
|
2532
|
+
# Sentinel escaped braces: \x00{ = literal {, }\x00 = literal }
|
|
2533
|
+
if ch == "\x00" and i + 1 < n and template[i + 1] == "{":
|
|
2534
|
+
lit_buf.append("{"); i += 2
|
|
2535
|
+
elif ch == "}" and i + 1 < n and template[i + 1] == "\x00":
|
|
2536
|
+
lit_buf.append("}"); i += 2
|
|
2537
|
+
elif ch == "{":
|
|
2538
|
+
# Start of an expression — find matching } with depth tracking
|
|
2539
|
+
if lit_buf:
|
|
2540
|
+
segments.append(("lit", "".join(lit_buf))); lit_buf = []
|
|
2541
|
+
depth = 1; j = i + 1; in_str = None
|
|
2542
|
+
while j < n and depth > 0:
|
|
2543
|
+
c2 = template[j]
|
|
2544
|
+
if in_str:
|
|
2545
|
+
if c2 == "\\" and j + 1 < n: j += 2; continue
|
|
2546
|
+
if c2 == in_str: in_str = None
|
|
2547
|
+
elif c2 in ('"', "\'"):
|
|
2548
|
+
in_str = c2
|
|
2549
|
+
elif c2 == "{":
|
|
2550
|
+
depth += 1
|
|
2551
|
+
elif c2 == "}":
|
|
2552
|
+
depth -= 1
|
|
2553
|
+
if depth == 0: break
|
|
2554
|
+
j += 1
|
|
2555
|
+
segments.append(("expr", template[i + 1:j]))
|
|
2556
|
+
i = j + 1
|
|
2557
|
+
else:
|
|
2558
|
+
lit_buf.append(ch); i += 1
|
|
2559
|
+
if lit_buf:
|
|
2560
|
+
segments.append(("lit", "".join(lit_buf)))
|
|
2561
|
+
return segments
|
|
2562
|
+
|
|
2519
2563
|
def visit_FStringExpr(self, node: FStringExpr) -> Any:
|
|
2520
2564
|
"""f"Hello {name}, score={score:.1f}" — evaluate {expr} segments at runtime.
|
|
2565
|
+
v2.0.2: brace-depth-aware splitter handles match/for/object literals inside {}.
|
|
2521
2566
|
Supports Python-style format specs: {x:.2f}, {n:06d}, {s:>20} etc.
|
|
2522
|
-
{{ and }} in source produce literal braces
|
|
2523
|
-
import re
|
|
2567
|
+
{{ and }} in source produce literal braces."""
|
|
2524
2568
|
result = []
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
inner =
|
|
2530
|
-
|
|
2531
|
-
# Split off format spec: {expr:spec}
|
|
2532
|
-
# Key: only split on ':' that is NOT inside brackets AND NOT after '?'
|
|
2533
|
-
# (ternary x ? a : b uses ':' but it's not a format spec)
|
|
2569
|
+
for kind, text in self._fstring_segments(node.template):
|
|
2570
|
+
if kind == "lit":
|
|
2571
|
+
result.append(text)
|
|
2572
|
+
continue
|
|
2573
|
+
inner = text.strip()
|
|
2574
|
+
# Split off format spec {expr:spec}, respecting brackets and ternary
|
|
2534
2575
|
fmt_spec = None
|
|
2535
|
-
depth = 0
|
|
2536
|
-
ternary_depth = 0
|
|
2537
|
-
split_at = -1
|
|
2576
|
+
depth = 0; ternary_depth = 0; split_at = -1
|
|
2538
2577
|
for i, ch in enumerate(inner):
|
|
2539
|
-
if ch in
|
|
2540
|
-
elif ch in
|
|
2541
|
-
elif ch ==
|
|
2542
|
-
elif ch ==
|
|
2543
|
-
if ternary_depth > 0:
|
|
2544
|
-
|
|
2545
|
-
else:
|
|
2546
|
-
split_at = i
|
|
2547
|
-
break
|
|
2578
|
+
if ch in "([{": depth += 1
|
|
2579
|
+
elif ch in ")]}": depth -= 1
|
|
2580
|
+
elif ch == "?" and depth == 0: ternary_depth += 1
|
|
2581
|
+
elif ch == ":" and depth == 0:
|
|
2582
|
+
if ternary_depth > 0: ternary_depth -= 1
|
|
2583
|
+
else: split_at = i; break
|
|
2548
2584
|
if split_at > 0:
|
|
2549
|
-
expr_src
|
|
2550
|
-
fmt_spec
|
|
2585
|
+
expr_src = inner[:split_at].strip()
|
|
2586
|
+
fmt_spec = inner[split_at + 1:].strip()
|
|
2551
2587
|
else:
|
|
2552
2588
|
expr_src = inner
|
|
2553
|
-
|
|
2554
2589
|
try:
|
|
2555
2590
|
from parser import parse
|
|
2556
2591
|
prog = parse(expr_src)
|
|
@@ -2558,19 +2593,13 @@ class Interpreter(Visitor):
|
|
|
2558
2593
|
for stmt in prog.body:
|
|
2559
2594
|
val = self.visit(stmt)
|
|
2560
2595
|
if fmt_spec:
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
result.append(format(val, fmt_spec))
|
|
2564
|
-
except Exception:
|
|
2565
|
-
result.append(_inscript_str(val))
|
|
2596
|
+
try: result.append(format(val, fmt_spec))
|
|
2597
|
+
except: result.append(_inscript_str(val))
|
|
2566
2598
|
else:
|
|
2567
2599
|
result.append(_inscript_str(val))
|
|
2568
2600
|
except Exception:
|
|
2569
|
-
result.append(
|
|
2570
|
-
|
|
2571
|
-
result.append(template[pos:])
|
|
2572
|
-
final = "".join(result).replace("\x00{", "{").replace("}\x00", "}")
|
|
2573
|
-
return final
|
|
2601
|
+
result.append("{" + inner + "}")
|
|
2602
|
+
return "".join(result)
|
|
2574
2603
|
|
|
2575
2604
|
def visit_DestructureDecl(self, node: DestructureDecl) -> Any:
|
|
2576
2605
|
"""let [a, b, c] = arr | let {x, y} = point | let [[a,b],[c,d]] = nested"""
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "inscript-lang"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.2"
|
|
8
8
|
description = "InScript — a game-focused scripting language with 59 game modules and a bytecode VM"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -40,7 +40,7 @@ sys.path.insert(0, str(Path(__file__).parent))
|
|
|
40
40
|
|
|
41
41
|
HISTORY_FILE = Path.home() / ".inscript" / "history"
|
|
42
42
|
HISTORY_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
43
|
-
VERSION = "2.0.
|
|
43
|
+
VERSION = "2.0.2"
|
|
44
44
|
|
|
45
45
|
# ── ANSI colours ──────────────────────────────────────────────────────────────
|
|
46
46
|
def _c(code, text):
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|