inscript-lang 2.0.2__tar.gz → 2.0.3__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.2 → inscript_lang-2.0.3}/PKG-INFO +1 -1
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/inscript.py +1 -1
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/inscript_lang.egg-info/PKG-INFO +1 -1
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/interpreter.py +25 -3
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/parser.py +21 -3
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/pyproject.toml +1 -1
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/repl.py +1 -1
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/README.md +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/analyzer.py +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/ast_nodes.py +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/compiler.py +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/environment.py +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/errors.py +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/inscript_fmt.py +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/inscript_lang.egg-info/SOURCES.txt +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/inscript_lang.egg-info/dependency_links.txt +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/inscript_lang.egg-info/entry_points.txt +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/inscript_lang.egg-info/requires.txt +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/inscript_lang.egg-info/top_level.txt +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/inscript_test.py +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/lexer.py +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/pygame_backend.py +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/setup.cfg +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/setup.py +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/stdlib.py +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/stdlib_extended.py +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/stdlib_extended_2.py +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/stdlib_game.py +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/stdlib_values.py +0 -0
- {inscript_lang-2.0.2 → inscript_lang-2.0.3}/vm.py +0 -0
|
@@ -993,7 +993,17 @@ class Interpreter(Visitor):
|
|
|
993
993
|
return self.visit(node.expr)
|
|
994
994
|
|
|
995
995
|
def visit_PrintStmt(self, node: PrintStmt) -> Any:
|
|
996
|
-
|
|
996
|
+
# v2.0.3: spread args in print(...arr)
|
|
997
|
+
parts = []
|
|
998
|
+
for a in node.args:
|
|
999
|
+
if isinstance(a, SpreadExpr):
|
|
1000
|
+
val = self.visit(a.expr)
|
|
1001
|
+
if isinstance(val, list):
|
|
1002
|
+
parts.extend(_inscript_str(v) for v in val)
|
|
1003
|
+
else:
|
|
1004
|
+
parts.append(_inscript_str(val))
|
|
1005
|
+
else:
|
|
1006
|
+
parts.append(_inscript_str(self.visit(a)))
|
|
997
1007
|
print(" ".join(parts))
|
|
998
1008
|
return None
|
|
999
1009
|
|
|
@@ -2425,10 +2435,22 @@ class Interpreter(Visitor):
|
|
|
2425
2435
|
fields[field.name] = self.visit(field.default) if field.default else None
|
|
2426
2436
|
|
|
2427
2437
|
# Then overrides from initializer
|
|
2438
|
+
# v2.0.3: spread syntax — P{...defaults, x: 5}
|
|
2428
2439
|
provided_names = set()
|
|
2429
2440
|
for name, value_node in node.fields:
|
|
2430
|
-
|
|
2431
|
-
|
|
2441
|
+
if name == "..." and isinstance(value_node, SpreadExpr):
|
|
2442
|
+
# Spread a dict, struct instance, or dict-like object
|
|
2443
|
+
spread_val = self.visit(value_node.expr)
|
|
2444
|
+
if isinstance(spread_val, InScriptInstance):
|
|
2445
|
+
for k, v in spread_val.fields.items():
|
|
2446
|
+
fields[k] = v; provided_names.add(k)
|
|
2447
|
+
elif isinstance(spread_val, dict):
|
|
2448
|
+
for k, v in spread_val.items():
|
|
2449
|
+
if not str(k).startswith("_"):
|
|
2450
|
+
fields[k] = v; provided_names.add(k)
|
|
2451
|
+
else:
|
|
2452
|
+
fields[name] = self.visit(value_node)
|
|
2453
|
+
provided_names.add(name)
|
|
2432
2454
|
|
|
2433
2455
|
# BUG-16 fix: warn about required fields (no default) that were not provided
|
|
2434
2456
|
missing_required = [
|
|
@@ -1369,12 +1369,19 @@ class Parser:
|
|
|
1369
1369
|
|
|
1370
1370
|
self.expect(TT.LPAREN, "Expected '(' after 'print'")
|
|
1371
1371
|
args = []
|
|
1372
|
+
def _parse_print_arg():
|
|
1373
|
+
# v2.0.3: allow spread in print(...args)
|
|
1374
|
+
if self.check(TT.ELLIPSIS):
|
|
1375
|
+
sl2, sc2 = self._pos()
|
|
1376
|
+
self.advance()
|
|
1377
|
+
return SpreadExpr(expr=self.parse_expr(), line=sl2, col=sc2)
|
|
1378
|
+
return self.parse_expr()
|
|
1372
1379
|
if not self.check(TT.RPAREN):
|
|
1373
|
-
args.append(
|
|
1380
|
+
args.append(_parse_print_arg())
|
|
1374
1381
|
while self.match(TT.COMMA):
|
|
1375
1382
|
if self.check(TT.RPAREN):
|
|
1376
1383
|
break
|
|
1377
|
-
args.append(
|
|
1384
|
+
args.append(_parse_print_arg())
|
|
1378
1385
|
self.expect(TT.RPAREN, "Expected ')' after print arguments")
|
|
1379
1386
|
self.match(TT.SEMICOLON)
|
|
1380
1387
|
return PrintStmt(args=args, line=line, col=col)
|
|
@@ -2072,18 +2079,29 @@ class Parser:
|
|
|
2072
2079
|
result = (
|
|
2073
2080
|
self.check(TT.RBRACE) # empty Counter {}
|
|
2074
2081
|
or (self.current.type == TT.IDENT and self.peek.type == TT.COLON)
|
|
2082
|
+
or self.current.type == TT.ELLIPSIS # v2.0.3: spread P{...d}
|
|
2075
2083
|
)
|
|
2076
2084
|
self.pos = saved
|
|
2077
2085
|
return result
|
|
2078
2086
|
|
|
2079
2087
|
def parse_struct_init(self, name: str, line: int, col: int) -> StructInitExpr:
|
|
2080
|
-
"""Player { pos: Vec2(0,0), health: 100 }
|
|
2088
|
+
"""Player { pos: Vec2(0,0), health: 100 }
|
|
2089
|
+
v2.0.3: spread syntax: Player { ...defaults, health: 100 }
|
|
2090
|
+
"""
|
|
2081
2091
|
self.advance() # consume '{'
|
|
2082
2092
|
fields = []
|
|
2083
2093
|
|
|
2084
2094
|
while not self.check(TT.RBRACE) and not self.is_at_end():
|
|
2085
2095
|
if self.match(TT.SEMICOLON) or self.match(TT.COMMA):
|
|
2086
2096
|
continue
|
|
2097
|
+
# v2.0.3: spread field — P{...defaults, x: 5}
|
|
2098
|
+
if self.check(TT.ELLIPSIS):
|
|
2099
|
+
sl2, sc2 = self._pos()
|
|
2100
|
+
self.advance() # consume '...'
|
|
2101
|
+
spread_expr = self.parse_expr()
|
|
2102
|
+
fields.append(("...", SpreadExpr(expr=spread_expr, line=sl2, col=sc2)))
|
|
2103
|
+
self.match(TT.COMMA)
|
|
2104
|
+
continue
|
|
2087
2105
|
field_name = self.expect_ident("Expected field name in struct initializer")
|
|
2088
2106
|
self.expect(TT.COLON, f"Expected ':' after field name '{field_name}'")
|
|
2089
2107
|
value = self.parse_expr()
|
|
@@ -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.3"
|
|
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.3"
|
|
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
|