inscript-lang 1.9.8__tar.gz → 1.9.9__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.8 → inscript_lang-1.9.9}/PKG-INFO +1 -1
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/inscript.py +239 -14
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/inscript_lang.egg-info/PKG-INFO +1 -1
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/pyproject.toml +1 -1
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/repl.py +1 -1
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/README.md +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/analyzer.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/ast_nodes.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/compiler.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/environment.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/errors.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/inscript_fmt.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/inscript_lang.egg-info/SOURCES.txt +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/inscript_lang.egg-info/dependency_links.txt +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/inscript_lang.egg-info/entry_points.txt +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/inscript_lang.egg-info/requires.txt +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/inscript_lang.egg-info/top_level.txt +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/inscript_test.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/interpreter.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/lexer.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/parser.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/pygame_backend.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/setup.cfg +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/setup.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/stdlib.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/stdlib_extended.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/stdlib_extended_2.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/stdlib_game.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/stdlib_values.py +0 -0
- {inscript_lang-1.9.8 → inscript_lang-1.9.9}/vm.py +0 -0
|
@@ -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.9"
|
|
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"
|
|
@@ -34,24 +34,117 @@ REGISTRY_URL = "https://raw.githubusercontent.com/authorss81/inscript-packages/m
|
|
|
34
34
|
# RUN A FILE
|
|
35
35
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
36
36
|
|
|
37
|
-
def
|
|
38
|
-
"""
|
|
37
|
+
def _parse_pkg_spec(spec: str):
|
|
38
|
+
"""
|
|
39
|
+
v1.9.9: Parse 'PKG@version' or just 'PKG'.
|
|
40
|
+
Returns (name, version_or_None).
|
|
41
|
+
"""
|
|
42
|
+
if "@" in spec:
|
|
43
|
+
idx = spec.index("@")
|
|
44
|
+
return spec[:idx].strip(), spec[idx+1:].strip()
|
|
45
|
+
return spec.strip(), None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _read_lock(lock_path: str) -> dict:
|
|
49
|
+
"""
|
|
50
|
+
v1.9.9: Read inscript.lock and return {pkg_name: version} mapping.
|
|
51
|
+
Returns empty dict if file doesn't exist or can't be parsed.
|
|
52
|
+
"""
|
|
53
|
+
if not os.path.isfile(lock_path):
|
|
54
|
+
return {}
|
|
55
|
+
import re as _re
|
|
56
|
+
result = {}
|
|
57
|
+
current_pkg = None
|
|
58
|
+
for line in open(lock_path, encoding="utf-8"):
|
|
59
|
+
m = _re.match(r'^\[package\.(.+)\]', line.strip())
|
|
60
|
+
if m:
|
|
61
|
+
current_pkg = m.group(1)
|
|
62
|
+
elif current_pkg:
|
|
63
|
+
m2 = _re.match(r'^version\s*=\s*"([^"]+)"', line.strip())
|
|
64
|
+
if m2:
|
|
65
|
+
result[current_pkg] = m2.group(1)
|
|
66
|
+
return result
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _write_lock_entry(lock_path: str, pkg_name: str, version: str) -> None:
|
|
70
|
+
"""
|
|
71
|
+
v1.9.9: Add or update a single package entry in inscript.lock.
|
|
72
|
+
Creates the file if it doesn't exist.
|
|
73
|
+
"""
|
|
74
|
+
import hashlib, re as _re, datetime
|
|
75
|
+
# Read existing content
|
|
76
|
+
if os.path.isfile(lock_path):
|
|
77
|
+
content = open(lock_path, encoding="utf-8").read()
|
|
78
|
+
else:
|
|
79
|
+
content = (
|
|
80
|
+
"# InScript lockfile — do not edit manually\n"
|
|
81
|
+
f"# Generated by InScript {VERSION}\n\n"
|
|
82
|
+
"[metadata]\n"
|
|
83
|
+
f'inscript = "{VERSION}"\n'
|
|
84
|
+
"generated = \"" + datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") + "\"\n\n"
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
sha256 = hashlib.sha256(f"{pkg_name}@{version}".encode()).hexdigest()
|
|
88
|
+
entry = "[package." + pkg_name + "]\nversion = \"" + version + "\"\nsha256 = \"" + sha256 + "\"\n\n"
|
|
89
|
+
|
|
90
|
+
# Remove old entry if present
|
|
91
|
+
content = _re.sub(
|
|
92
|
+
rf'\[package\.{_re.escape(pkg_name)}\][^\[]*', '', content
|
|
93
|
+
)
|
|
94
|
+
content = content.rstrip() + "\n\n" + entry
|
|
95
|
+
with open(lock_path, "w", encoding="utf-8") as f:
|
|
96
|
+
f.write(content)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _remove_lock_entry(lock_path: str, pkg_name: str) -> None:
|
|
100
|
+
"""v1.9.9: Remove a package entry from inscript.lock."""
|
|
101
|
+
import re as _re
|
|
102
|
+
if not os.path.isfile(lock_path):
|
|
103
|
+
return
|
|
104
|
+
content = open(lock_path, encoding="utf-8").read()
|
|
105
|
+
content = _re.sub(
|
|
106
|
+
rf'\[package\.{_re.escape(pkg_name)}\][^\[]*', '', content
|
|
107
|
+
)
|
|
108
|
+
with open(lock_path, "w", encoding="utf-8") as f:
|
|
109
|
+
f.write(content)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def install_package(pkg_spec: str, lock_path: str = None) -> int:
|
|
113
|
+
"""
|
|
114
|
+
v1.9.9: Download and install an InScript package to ~/.inscript/packages/
|
|
115
|
+
|
|
116
|
+
Supports 'PKG' and 'PKG@version' specs.
|
|
117
|
+
Writes the installed version to inscript.lock if lock_path is given.
|
|
118
|
+
Falls back to lock file version info on network failure.
|
|
119
|
+
"""
|
|
39
120
|
import urllib.request, json as _json, zipfile, io
|
|
40
121
|
|
|
122
|
+
pkg_name, requested_version = _parse_pkg_spec(pkg_spec)
|
|
41
123
|
os.makedirs(PACKAGES_DIR, exist_ok=True)
|
|
42
124
|
pkg_dir = os.path.join(PACKAGES_DIR, pkg_name)
|
|
43
125
|
|
|
44
|
-
if
|
|
126
|
+
# Check if already installed at requested version
|
|
127
|
+
if os.path.exists(pkg_dir) and not requested_version:
|
|
45
128
|
print(f"[InScript] Package '{pkg_name}' is already installed at {pkg_dir}")
|
|
46
129
|
return 0
|
|
47
130
|
|
|
48
|
-
|
|
131
|
+
# Try fetching registry
|
|
132
|
+
registry = None
|
|
49
133
|
try:
|
|
134
|
+
print(f"[InScript] Fetching registry...")
|
|
50
135
|
with urllib.request.urlopen(REGISTRY_URL, timeout=10) as resp:
|
|
51
136
|
registry = _json.loads(resp.read().decode())
|
|
52
137
|
except Exception as e:
|
|
138
|
+
# v1.9.9: Offline fallback — if lock file has this package, report it
|
|
139
|
+
if lock_path:
|
|
140
|
+
locked = _read_lock(lock_path)
|
|
141
|
+
if pkg_name in locked:
|
|
142
|
+
print(f"[InScript] Registry unreachable ({e})")
|
|
143
|
+
print(f"[InScript] Offline: '{pkg_name}' is pinned at v{locked[pkg_name]} in lock file.")
|
|
144
|
+
print(f"[InScript] Tip: manually place .ins files in {PACKAGES_DIR}/{pkg_name}/ to install offline.")
|
|
145
|
+
return 0
|
|
53
146
|
print(f"[InScript] Could not reach package registry: {e}", file=sys.stderr)
|
|
54
|
-
print(f"[InScript] Tip:
|
|
147
|
+
print(f"[InScript] Tip: place .ins files in {PACKAGES_DIR}/ or run 'inscript lock' first.",
|
|
55
148
|
file=sys.stderr)
|
|
56
149
|
return 1
|
|
57
150
|
|
|
@@ -62,22 +155,139 @@ def install_package(pkg_name: str) -> int:
|
|
|
62
155
|
return 1
|
|
63
156
|
|
|
64
157
|
pkg_info = registry[pkg_name]
|
|
65
|
-
|
|
66
|
-
|
|
158
|
+
latest_version = pkg_info.get("version", "?")
|
|
159
|
+
install_version = requested_version or latest_version
|
|
160
|
+
zip_url = pkg_info.get("url")
|
|
67
161
|
|
|
68
|
-
print(f"[InScript] Installing {pkg_name}@{
|
|
162
|
+
print(f"[InScript] Installing {pkg_name}@{install_version}...")
|
|
69
163
|
try:
|
|
70
164
|
with urllib.request.urlopen(zip_url, timeout=30) as resp:
|
|
71
165
|
data = resp.read()
|
|
72
166
|
with zipfile.ZipFile(io.BytesIO(data)) as zf:
|
|
73
167
|
zf.extractall(PACKAGES_DIR)
|
|
74
|
-
print(f"[InScript] ✅ {pkg_name}@{
|
|
168
|
+
print(f"[InScript] ✅ {pkg_name}@{install_version} installed to {pkg_dir}")
|
|
169
|
+
# v1.9.9: Write to lock file
|
|
170
|
+
if lock_path:
|
|
171
|
+
_write_lock_entry(lock_path, pkg_name, install_version)
|
|
172
|
+
print(f"[InScript] Pinned {pkg_name}@{install_version} in lock file.")
|
|
75
173
|
return 0
|
|
76
174
|
except Exception as e:
|
|
77
175
|
print(f"[InScript] Install failed: {e}", file=sys.stderr)
|
|
78
176
|
return 1
|
|
79
177
|
|
|
80
178
|
|
|
179
|
+
def install_all_from_toml(project_dir: str = ".") -> int:
|
|
180
|
+
"""
|
|
181
|
+
v1.9.9: `inscript install` (no args) — read inscript.toml [dependencies]
|
|
182
|
+
and install every listed package, respecting inscript.lock if present.
|
|
183
|
+
"""
|
|
184
|
+
manifest_path = os.path.join(project_dir, MANIFEST_FILENAME)
|
|
185
|
+
lock_path = os.path.join(project_dir, LOCK_FILENAME)
|
|
186
|
+
|
|
187
|
+
if not os.path.isfile(manifest_path):
|
|
188
|
+
print(f"[InScript install] No '{MANIFEST_FILENAME}' found in '{project_dir}'.", file=sys.stderr)
|
|
189
|
+
print(f"[InScript install] Run 'inscript init' to create one.", file=sys.stderr)
|
|
190
|
+
return 1
|
|
191
|
+
|
|
192
|
+
try:
|
|
193
|
+
with open(manifest_path, encoding="utf-8") as f:
|
|
194
|
+
content = f.read()
|
|
195
|
+
data = _parse_toml_simple(content)
|
|
196
|
+
except Exception as e:
|
|
197
|
+
print(f"[InScript install] Cannot parse '{manifest_path}': {e}", file=sys.stderr)
|
|
198
|
+
return 1
|
|
199
|
+
|
|
200
|
+
deps = data.get("dependencies", {})
|
|
201
|
+
if not deps:
|
|
202
|
+
print(f"[InScript install] No dependencies listed in '{manifest_path}'.")
|
|
203
|
+
return 0
|
|
204
|
+
|
|
205
|
+
# v1.9.9: If lock file exists, use its pinned versions
|
|
206
|
+
locked = _read_lock(lock_path) if os.path.isfile(lock_path) else {}
|
|
207
|
+
|
|
208
|
+
print(f"[InScript install] Installing {len(deps)} dependenc{'y' if len(deps)==1 else 'ies'}...")
|
|
209
|
+
failed = 0
|
|
210
|
+
for pkg_name, constraint in sorted(deps.items()):
|
|
211
|
+
# Prefer locked version over constraint range
|
|
212
|
+
pinned = locked.get(pkg_name)
|
|
213
|
+
spec = f"{pkg_name}@{pinned}" if pinned else pkg_name
|
|
214
|
+
ret = install_package(spec, lock_path=lock_path)
|
|
215
|
+
if ret != 0:
|
|
216
|
+
failed += 1
|
|
217
|
+
|
|
218
|
+
if failed:
|
|
219
|
+
print(f"[InScript install] {failed} package(s) failed to install.", file=sys.stderr)
|
|
220
|
+
return 1
|
|
221
|
+
print(f"[InScript install] ✅ All dependencies installed.")
|
|
222
|
+
return 0
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def outdated_packages(project_dir: str = ".") -> int:
|
|
226
|
+
"""
|
|
227
|
+
v1.9.9: `inscript outdated` — compare inscript.lock versions against
|
|
228
|
+
the latest available in the registry. Reports which packages have updates.
|
|
229
|
+
"""
|
|
230
|
+
import urllib.request, json as _json
|
|
231
|
+
lock_path = os.path.join(project_dir, LOCK_FILENAME)
|
|
232
|
+
locked = _read_lock(lock_path)
|
|
233
|
+
|
|
234
|
+
if not locked:
|
|
235
|
+
print("[InScript outdated] No inscript.lock found or no packages locked.")
|
|
236
|
+
print("[InScript outdated] Run 'inscript lock' to generate one.")
|
|
237
|
+
return 0
|
|
238
|
+
|
|
239
|
+
try:
|
|
240
|
+
with urllib.request.urlopen(REGISTRY_URL, timeout=10) as resp:
|
|
241
|
+
registry = _json.loads(resp.read().decode())
|
|
242
|
+
except Exception as e:
|
|
243
|
+
print(f"[InScript outdated] Cannot reach registry: {e}", file=sys.stderr)
|
|
244
|
+
print("[InScript outdated] Showing locked versions (cannot check for updates):")
|
|
245
|
+
for pkg, ver in sorted(locked.items()):
|
|
246
|
+
print(f" • {pkg}@{ver} (locked)")
|
|
247
|
+
return 1
|
|
248
|
+
|
|
249
|
+
any_outdated = False
|
|
250
|
+
for pkg_name, current_ver in sorted(locked.items()):
|
|
251
|
+
if pkg_name not in registry:
|
|
252
|
+
print(f" ? {pkg_name}@{current_ver} — not found in registry")
|
|
253
|
+
continue
|
|
254
|
+
latest = registry[pkg_name].get("version", "?")
|
|
255
|
+
if latest != current_ver:
|
|
256
|
+
print(f" ↑ {pkg_name} {current_ver} → {latest}")
|
|
257
|
+
any_outdated = True
|
|
258
|
+
else:
|
|
259
|
+
print(f" ✓ {pkg_name}@{current_ver} (up to date)")
|
|
260
|
+
|
|
261
|
+
if not any_outdated:
|
|
262
|
+
print("[InScript outdated] All packages are up to date.")
|
|
263
|
+
return 0
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def update_package(pkg_spec: str, project_dir: str = ".") -> int:
|
|
267
|
+
"""
|
|
268
|
+
v1.9.9: `inscript update PKG` or `inscript update PKG@version` —
|
|
269
|
+
remove the existing installation and reinstall at the specified (or latest) version.
|
|
270
|
+
Updates inscript.lock with the new pinned version.
|
|
271
|
+
"""
|
|
272
|
+
import shutil
|
|
273
|
+
pkg_name, new_version = _parse_pkg_spec(pkg_spec)
|
|
274
|
+
lock_path = os.path.join(project_dir, LOCK_FILENAME)
|
|
275
|
+
pkg_dir = os.path.join(PACKAGES_DIR, pkg_name)
|
|
276
|
+
|
|
277
|
+
# Remove existing installation
|
|
278
|
+
if os.path.exists(pkg_dir):
|
|
279
|
+
shutil.rmtree(pkg_dir)
|
|
280
|
+
print(f"[InScript update] Removed existing {pkg_name} installation.")
|
|
281
|
+
|
|
282
|
+
spec = f"{pkg_name}@{new_version}" if new_version else pkg_name
|
|
283
|
+
ret = install_package(spec, lock_path=lock_path)
|
|
284
|
+
if ret == 0:
|
|
285
|
+
print(f"[InScript update] ✅ {pkg_name} updated.")
|
|
286
|
+
return ret
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
81
291
|
def list_packages() -> int:
|
|
82
292
|
"""List installed packages."""
|
|
83
293
|
if not os.path.exists(PACKAGES_DIR):
|
|
@@ -1707,8 +1917,12 @@ Examples:
|
|
|
1707
1917
|
parser.add_argument("--watch", action="store_true",
|
|
1708
1918
|
help="Watch file for changes and rerun: inscript --watch game.ins")
|
|
1709
1919
|
parser.add_argument("--version", action="store_true", help="Print version and exit")
|
|
1710
|
-
parser.add_argument("--install", metavar="PKG",
|
|
1711
|
-
help="Install a package
|
|
1920
|
+
parser.add_argument("--install", metavar="PKG", nargs="?", const="",
|
|
1921
|
+
help="v1.9.9: Install a package (PKG or PKG@version); no arg = install all from inscript.toml")
|
|
1922
|
+
parser.add_argument("--update", metavar="PKG",
|
|
1923
|
+
help="v1.9.9: Update a package to latest (or PKG@version)")
|
|
1924
|
+
parser.add_argument("--outdated", action="store_true",
|
|
1925
|
+
help="v1.9.9: Show packages with newer versions available")
|
|
1712
1926
|
parser.add_argument("--remove", metavar="PKG",
|
|
1713
1927
|
help="Remove a package: inscript --remove math-utils")
|
|
1714
1928
|
parser.add_argument("--packages", action="store_true",
|
|
@@ -1787,8 +2001,19 @@ Examples:
|
|
|
1787
2001
|
if args.packages:
|
|
1788
2002
|
return list_packages()
|
|
1789
2003
|
|
|
1790
|
-
if args
|
|
1791
|
-
|
|
2004
|
+
if getattr(args, 'install', None) is not None:
|
|
2005
|
+
# v1.9.9: `inscript install` (no args) → install from toml
|
|
2006
|
+
# `inscript install PKG[@version]` → install specific pkg
|
|
2007
|
+
lock_path = os.path.join(".", LOCK_FILENAME)
|
|
2008
|
+
if args.install == "":
|
|
2009
|
+
return install_all_from_toml(".")
|
|
2010
|
+
return install_package(args.install, lock_path=lock_path)
|
|
2011
|
+
|
|
2012
|
+
if getattr(args, 'update', None):
|
|
2013
|
+
return update_package(args.update, project_dir=".")
|
|
2014
|
+
|
|
2015
|
+
if getattr(args, 'outdated', False):
|
|
2016
|
+
return outdated_packages(project_dir=".")
|
|
1792
2017
|
|
|
1793
2018
|
if args.remove:
|
|
1794
2019
|
return remove_package(args.remove)
|
|
@@ -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.9"
|
|
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.9"
|
|
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
|
|
File without changes
|