inscript-lang 1.9.7__tar.gz → 1.9.8__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-1.9.7 → inscript_lang-1.9.8}/PKG-INFO +1 -1
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/analyzer.py +12 -4
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/inscript.py +80 -1
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/inscript_lang.egg-info/PKG-INFO +1 -1
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/pyproject.toml +1 -1
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/repl.py +1 -1
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/README.md +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/ast_nodes.py +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/compiler.py +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/environment.py +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/errors.py +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/inscript_fmt.py +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/inscript_lang.egg-info/SOURCES.txt +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/inscript_lang.egg-info/dependency_links.txt +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/inscript_lang.egg-info/entry_points.txt +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/inscript_lang.egg-info/requires.txt +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/inscript_lang.egg-info/top_level.txt +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/inscript_test.py +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/interpreter.py +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/lexer.py +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/parser.py +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/pygame_backend.py +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/setup.cfg +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/setup.py +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/stdlib.py +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/stdlib_extended.py +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/stdlib_extended_2.py +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/stdlib_game.py +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/stdlib_values.py +0 -0
- {inscript_lang-1.9.7 → inscript_lang-1.9.8}/vm.py +0 -0
|
@@ -1151,13 +1151,21 @@ class Analyzer(Visitor):
|
|
|
1151
1151
|
def visit_ArrayLiteralExpr(self, node: ArrayLiteralExpr) -> InScriptType:
|
|
1152
1152
|
if not node.elements:
|
|
1153
1153
|
return array_type(T_ANY)
|
|
1154
|
+
# v1.9.8: infer element type; fall back to Array<any> on mixed types
|
|
1154
1155
|
first_type = self.visit(node.elements[0])
|
|
1156
|
+
# Normalise literal string types to T_STRING for array inference
|
|
1157
|
+
if is_literal_type(first_type):
|
|
1158
|
+
first_type = T_STRING
|
|
1159
|
+
mixed = False
|
|
1155
1160
|
for elem in node.elements[1:]:
|
|
1156
1161
|
et = self.visit(elem)
|
|
1157
|
-
if
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1162
|
+
if is_literal_type(et):
|
|
1163
|
+
et = T_STRING
|
|
1164
|
+
if not types_compatible(first_type, et) and not types_compatible(et, first_type):
|
|
1165
|
+
mixed = True
|
|
1166
|
+
if mixed:
|
|
1167
|
+
return array_type(T_ANY) # [1, "a", true] → Array<any>
|
|
1168
|
+
return array_type(first_type) # [1, 2, 3] → Array<int>
|
|
1161
1169
|
|
|
1162
1170
|
def visit_DictLiteralExpr(self, node: DictLiteralExpr) -> InScriptType:
|
|
1163
1171
|
if not node.pairs:
|
|
@@ -24,7 +24,7 @@ from errors import (InScriptError, LexerError, ParseError,
|
|
|
24
24
|
SemanticError, InScriptRuntimeError,
|
|
25
25
|
MultiError, InScriptWarning)
|
|
26
26
|
|
|
27
|
-
VERSION = "1.9.
|
|
27
|
+
VERSION = "1.9.8"
|
|
28
28
|
LANG = "InScript"
|
|
29
29
|
PACKAGES_DIR = os.path.join(os.path.expanduser("~"), ".inscript", "packages")
|
|
30
30
|
REGISTRY_URL = "https://raw.githubusercontent.com/authorss81/inscript-packages/main/registry.json"
|
|
@@ -315,6 +315,81 @@ def _compat_files(path: str) -> int:
|
|
|
315
315
|
return 1
|
|
316
316
|
|
|
317
317
|
|
|
318
|
+
def _infer_types_file(path: str) -> int:
|
|
319
|
+
"""
|
|
320
|
+
v1.9.8: `inscript --infer-types FILE`
|
|
321
|
+
Parse and type-check FILE, then print the inferred type for every
|
|
322
|
+
let/const declaration. Useful for understanding what the analyzer infers.
|
|
323
|
+
Returns 0 on success, 1 if file not found or parse error.
|
|
324
|
+
"""
|
|
325
|
+
import os
|
|
326
|
+
if not os.path.isfile(path):
|
|
327
|
+
print(f"[InScript infer-types] File not found: '{path}'", file=sys.stderr)
|
|
328
|
+
return 1
|
|
329
|
+
try:
|
|
330
|
+
with open(path, encoding="utf-8") as f:
|
|
331
|
+
src = f.read()
|
|
332
|
+
except OSError as e:
|
|
333
|
+
print(f"[InScript infer-types] Cannot read '{path}': {e}", file=sys.stderr)
|
|
334
|
+
return 1
|
|
335
|
+
|
|
336
|
+
from lexer import Lexer
|
|
337
|
+
from parser import Parser
|
|
338
|
+
from analyzer import Analyzer
|
|
339
|
+
from ast_nodes import VarDecl
|
|
340
|
+
|
|
341
|
+
try:
|
|
342
|
+
tokens = Lexer(src).tokenize()
|
|
343
|
+
tree = Parser(tokens).parse()
|
|
344
|
+
except Exception as e:
|
|
345
|
+
print(f"[InScript infer-types] Parse error: {e}", file=sys.stderr)
|
|
346
|
+
return 1
|
|
347
|
+
|
|
348
|
+
analyzer = Analyzer()
|
|
349
|
+
try:
|
|
350
|
+
analyzer.analyze(tree)
|
|
351
|
+
except Exception:
|
|
352
|
+
pass # best-effort — show what we have even if there are errors
|
|
353
|
+
|
|
354
|
+
# Walk all VarDecl / ConstDecl nodes and report inferred types
|
|
355
|
+
results = []
|
|
356
|
+
def _walk(node):
|
|
357
|
+
if node is None:
|
|
358
|
+
return
|
|
359
|
+
if isinstance(node, (VarDecl,)):
|
|
360
|
+
sym = analyzer._scope.lookup(node.name) if hasattr(analyzer, '_scope') else None
|
|
361
|
+
typ = sym.type_ if sym else None
|
|
362
|
+
type_str = str(typ) if typ else "any"
|
|
363
|
+
results.append((node.line, "let" if not node.is_const else "const",
|
|
364
|
+
node.name, type_str))
|
|
365
|
+
# Recurse into body of blocks, fns etc.
|
|
366
|
+
for attr in ("body", "then_branch", "else_branch", "value",
|
|
367
|
+
"initializer", "statements"):
|
|
368
|
+
child = getattr(node, attr, None)
|
|
369
|
+
if child is None:
|
|
370
|
+
continue
|
|
371
|
+
if hasattr(child, "__iter__") and not isinstance(child, str):
|
|
372
|
+
for c in child:
|
|
373
|
+
if hasattr(c, "__class__") and hasattr(c, "line"):
|
|
374
|
+
_walk(c)
|
|
375
|
+
elif hasattr(child, "line"):
|
|
376
|
+
_walk(child)
|
|
377
|
+
|
|
378
|
+
if hasattr(tree, "body"):
|
|
379
|
+
for stmt in tree.body:
|
|
380
|
+
_walk(stmt)
|
|
381
|
+
|
|
382
|
+
if not results:
|
|
383
|
+
print(f"[InScript infer-types] No let/const declarations found in '{path}'")
|
|
384
|
+
return 0
|
|
385
|
+
|
|
386
|
+
print(f"[InScript infer-types] Inferred types in '{path}':\n")
|
|
387
|
+
for line, kw, name, typ in results:
|
|
388
|
+
print(f" Line {line:3d}: {kw} {name:<20s} → {typ}")
|
|
389
|
+
print()
|
|
390
|
+
return 0
|
|
391
|
+
|
|
392
|
+
|
|
318
393
|
def _migrate_files(path: str) -> int:
|
|
319
394
|
"""v1.7.4: Auto-migrate deprecated InScript syntax in-place."""
|
|
320
395
|
import re, os
|
|
@@ -1573,6 +1648,8 @@ Examples:
|
|
|
1573
1648
|
parser.add_argument("--check", action="store_true", help="Type-check only, don't run")
|
|
1574
1649
|
parser.add_argument("--check-all", metavar="DIR",
|
|
1575
1650
|
help="v1.6.0: Check all .ins files in DIR recursively, exit 1 if any errors")
|
|
1651
|
+
parser.add_argument("--infer-types", metavar="FILE",
|
|
1652
|
+
help="v1.9.8: Print inferred type for every let/const declaration in FILE")
|
|
1576
1653
|
parser.add_argument("--migrate", metavar="DIR_OR_FILE",
|
|
1577
1654
|
help="v1.7.4: Auto-migrate deprecated syntax (null→nil, div→//)")
|
|
1578
1655
|
parser.add_argument("--compat", metavar="DIR_OR_FILE",
|
|
@@ -1754,6 +1831,8 @@ Examples:
|
|
|
1754
1831
|
return _fmt_all_files(args.fmt_all)
|
|
1755
1832
|
if getattr(args, 'migrate', None):
|
|
1756
1833
|
return _migrate_files(args.migrate)
|
|
1834
|
+
if getattr(args, 'infer_types', None):
|
|
1835
|
+
return _infer_types_file(args.infer_types)
|
|
1757
1836
|
if getattr(args, 'compat', None):
|
|
1758
1837
|
return _compat_files(args.compat)
|
|
1759
1838
|
if getattr(args, 'init', None) is not None:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "inscript-lang"
|
|
7
|
-
version = "1.9.
|
|
7
|
+
version = "1.9.8"
|
|
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 = "1.9.
|
|
43
|
+
VERSION = "1.9.8"
|
|
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
|