inscript-lang 1.9.13__tar.gz → 2.0.0__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.13 → inscript_lang-2.0.0}/PKG-INFO +1 -1
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/analyzer.py +31 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/inscript.py +12 -10
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/inscript_lang.egg-info/PKG-INFO +1 -1
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/lexer.py +7 -1
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/pyproject.toml +1 -1
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/repl.py +1 -1
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/README.md +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/ast_nodes.py +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/compiler.py +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/environment.py +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/errors.py +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/inscript_fmt.py +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/inscript_lang.egg-info/SOURCES.txt +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/inscript_lang.egg-info/dependency_links.txt +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/inscript_lang.egg-info/entry_points.txt +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/inscript_lang.egg-info/requires.txt +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/inscript_lang.egg-info/top_level.txt +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/inscript_test.py +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/interpreter.py +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/parser.py +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/pygame_backend.py +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/setup.cfg +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/setup.py +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/stdlib.py +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/stdlib_extended.py +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/stdlib_extended_2.py +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/stdlib_game.py +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/stdlib_values.py +0 -0
- {inscript_lang-1.9.13 → inscript_lang-2.0.0}/vm.py +0 -0
|
@@ -1160,6 +1160,37 @@ class Analyzer(Visitor):
|
|
|
1160
1160
|
def visit_BoolLiteralExpr(self, node: BoolLiteralExpr) -> InScriptType: return T_BOOL
|
|
1161
1161
|
def visit_NullLiteralExpr(self, node: NullLiteralExpr) -> InScriptType: return T_NULL
|
|
1162
1162
|
|
|
1163
|
+
def visit_FStringExpr(self, node) -> InScriptType:
|
|
1164
|
+
"""v1.9.15: $"..." and f"..." interpolated strings always produce T_STRING.
|
|
1165
|
+
Type-check each {expr} segment by re-parsing and visiting it.
|
|
1166
|
+
"""
|
|
1167
|
+
import re
|
|
1168
|
+
template = node.template
|
|
1169
|
+
for m in re.finditer(r'(?<!\x00)\{([^}\x00][^}]*)\}', template):
|
|
1170
|
+
inner = m.group(1).strip()
|
|
1171
|
+
# Strip optional format spec :spec
|
|
1172
|
+
depth = 0; split_at = -1; ternary_depth = 0
|
|
1173
|
+
for i, ch in enumerate(inner):
|
|
1174
|
+
if ch in '([{': depth += 1
|
|
1175
|
+
elif ch in ')]}': depth -= 1
|
|
1176
|
+
elif ch == '?' and depth == 0: ternary_depth += 1
|
|
1177
|
+
elif ch == ':' and depth == 0:
|
|
1178
|
+
if ternary_depth > 0: ternary_depth -= 1
|
|
1179
|
+
else: split_at = i; break
|
|
1180
|
+
expr_src = inner[:split_at].strip() if split_at > 0 else inner
|
|
1181
|
+
try:
|
|
1182
|
+
from parser import parse
|
|
1183
|
+
prog = parse(expr_src)
|
|
1184
|
+
# visit each stmt in a suppressed-error sub-context
|
|
1185
|
+
saved = self._errors; self._errors = []
|
|
1186
|
+
try:
|
|
1187
|
+
for stmt in prog.body: self.visit(stmt)
|
|
1188
|
+
finally:
|
|
1189
|
+
self._errors = saved
|
|
1190
|
+
except Exception:
|
|
1191
|
+
pass # parse errors in sub-expr are caught at runtime
|
|
1192
|
+
return T_STRING
|
|
1193
|
+
|
|
1163
1194
|
def visit_IdentExpr(self, node: IdentExpr) -> InScriptType:
|
|
1164
1195
|
sym = self._lookup(node.name, node.line, node.col)
|
|
1165
1196
|
return sym.type_
|
|
@@ -24,7 +24,7 @@ from errors import (InScriptError, LexerError, ParseError,
|
|
|
24
24
|
SemanticError, InScriptRuntimeError,
|
|
25
25
|
MultiError, InScriptWarning)
|
|
26
26
|
|
|
27
|
-
VERSION = "
|
|
27
|
+
VERSION = "2.0.0"
|
|
28
28
|
|
|
29
29
|
MANIFEST_FILENAME = "inscript.toml"
|
|
30
30
|
LOCK_FILENAME = "inscript.lock"
|
|
@@ -703,9 +703,9 @@ def _check_v2_readiness(project_dir: str = ".") -> int:
|
|
|
703
703
|
for fpath in ins_files:
|
|
704
704
|
try:
|
|
705
705
|
src = open(fpath, encoding="utf-8").read()
|
|
706
|
-
#
|
|
706
|
+
# Only flag STANDALONE // lines — inline // is always floor division in v1.9.6+
|
|
707
707
|
bad = [i+1 for i, l in enumerate(src.splitlines())
|
|
708
|
-
if _re.match(r'^\s*//', l)
|
|
708
|
+
if _re.match(r'^\s*//', l)]
|
|
709
709
|
if bad:
|
|
710
710
|
comment_hits.append((fpath, bad))
|
|
711
711
|
except OSError:
|
|
@@ -785,9 +785,11 @@ def _migrate_files(path: str) -> int:
|
|
|
785
785
|
# v1.9.6: // line comments → # line comments (MUST run before div→// rewrite)
|
|
786
786
|
# Rule 1: standalone comment lines — optional whitespace then //
|
|
787
787
|
src = re.sub(r'^(\s*)//', r'\1#', src, flags=re.MULTILINE)
|
|
788
|
-
# Rule 2: inline
|
|
789
|
-
#
|
|
790
|
-
|
|
788
|
+
# Rule 2: inline trailing comment — `; // word` or `} // word` → `; # word`
|
|
789
|
+
# v1.9.15: ONLY fires after statement terminators (;, {, }),
|
|
790
|
+
# NOT after expression-ending chars like ), ], identifiers, digits.
|
|
791
|
+
# This prevents floor-division like `(a*b) // gcd(a,b)` being mangled.
|
|
792
|
+
src = re.sub(r'([;{}])( *)//(\s+[A-Za-z_])', r'\1\2#\3', src)
|
|
791
793
|
# Rule 3: warn about ambiguous ` // <digit>` patterns (may be comment or floor-div)
|
|
792
794
|
ambiguous = re.findall(r'(\s)//(\s+\d)', src)
|
|
793
795
|
if ambiguous:
|
|
@@ -2335,10 +2337,6 @@ Examples:
|
|
|
2335
2337
|
profile=profile)
|
|
2336
2338
|
|
|
2337
2339
|
|
|
2338
|
-
if __name__ == "__main__":
|
|
2339
|
-
sys.exit(main())
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
2340
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
2343
2341
|
# v1.9.2 — Package Manifest Foundation
|
|
2344
2342
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -2690,3 +2688,7 @@ def _generate_lockfile(directory: str = ".") -> int:
|
|
|
2690
2688
|
except OSError as e:
|
|
2691
2689
|
print(f"[InScript lock] Cannot write lockfile: {e}", file=sys.stderr)
|
|
2692
2690
|
return 1
|
|
2691
|
+
|
|
2692
|
+
|
|
2693
|
+
if __name__ == "__main__":
|
|
2694
|
+
sys.exit(main())
|
|
@@ -365,7 +365,7 @@ class Lexer:
|
|
|
365
365
|
self._error("Unterminated triple-quoted string", sl, sc)
|
|
366
366
|
|
|
367
367
|
def _scan_fstring(self, quote: str, sl: int, sc: int):
|
|
368
|
-
"""Scan f"...{expr}..." — store the raw template as FSTRING token.
|
|
368
|
+
"""Scan f"...{expr}..." or $"...{expr}..." — store the raw template as FSTRING token. v1.9.15: $"..." is the new preferred syntax; both prefixes share this scanner.
|
|
369
369
|
{{ and }} are literal brace escapes.
|
|
370
370
|
Inside {}, quote characters are allowed (e.g. d["key"])."""
|
|
371
371
|
chars = []
|
|
@@ -580,6 +580,12 @@ class Lexer:
|
|
|
580
580
|
elif ch == "#":
|
|
581
581
|
# v1.9.6: # is the line-comment character (was: HASH annotation token)
|
|
582
582
|
self._skip_line_comment(); return
|
|
583
|
+
elif ch == "$":
|
|
584
|
+
# v1.9.15: $"..." interpolated string (preferred over f"...")
|
|
585
|
+
if self.current in ('"', "'"):
|
|
586
|
+
self._scan_fstring(self.advance(), sl, sc)
|
|
587
|
+
return
|
|
588
|
+
# bare $ not followed by quote — skip (not used otherwise)
|
|
583
589
|
elif ch == "@": emit(TT.AT, "@")
|
|
584
590
|
elif ch == "(": emit(TT.LPAREN)
|
|
585
591
|
elif ch == ")": emit(TT.RPAREN)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "inscript-lang"
|
|
7
|
-
version = "
|
|
7
|
+
version = "2.0.0"
|
|
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 = "
|
|
43
|
+
VERSION = "2.0.0"
|
|
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
|