inscript-lang 1.1.0__tar.gz → 1.6.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.1.0 → inscript_lang-1.6.0}/PKG-INFO +210 -210
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/analyzer.py +32 -11
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/ast_nodes.py +25 -2
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/compiler.py +113 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/errors.py +6 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/inscript.py +178 -8
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/inscript_lang.egg-info/PKG-INFO +210 -210
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/interpreter.py +331 -78
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/lexer.py +6 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/parser.py +85 -24
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/pyproject.toml +1 -1
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/repl.py +32 -1
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/setup.cfg +4 -4
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/setup.py +1 -1
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/stdlib.py +147 -61
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/stdlib_game.py +276 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/README.md +0 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/environment.py +0 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/inscript_fmt.py +0 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/inscript_lang.egg-info/SOURCES.txt +0 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/inscript_lang.egg-info/dependency_links.txt +0 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/inscript_lang.egg-info/entry_points.txt +0 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/inscript_lang.egg-info/requires.txt +0 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/inscript_lang.egg-info/top_level.txt +0 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/inscript_test.py +0 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/pygame_backend.py +0 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/stdlib_extended.py +0 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/stdlib_extended_2.py +0 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/stdlib_values.py +0 -0
- {inscript_lang-1.1.0 → inscript_lang-1.6.0}/vm.py +0 -0
|
@@ -1,210 +1,210 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: inscript-lang
|
|
3
|
-
Version: 1.
|
|
4
|
-
Summary: InScript — a game-focused scripting language with 59 game modules and a bytecode VM
|
|
5
|
-
Author: Shreyasi Sarkar
|
|
6
|
-
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/authorss81/inscript
|
|
8
|
-
Project-URL: Repository, https://github.com/authorss81/inscript
|
|
9
|
-
Project-URL: Bug Tracker, https://github.com/authorss81/inscript/issues
|
|
10
|
-
Project-URL: Documentation, https://authorss81.github.io/inscript/docs/
|
|
11
|
-
Keywords: game,scripting,language,gamedev,gdscript
|
|
12
|
-
Classifier: Development Status :: 4 - Beta
|
|
13
|
-
Classifier: Intended Audience :: Developers
|
|
14
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
-
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
-
Classifier: Topic :: Games/Entertainment
|
|
20
|
-
Classifier: Topic :: Software Development :: Interpreters
|
|
21
|
-
Requires-Python: >=3.10
|
|
22
|
-
Description-Content-Type: text/markdown
|
|
23
|
-
Provides-Extra: game
|
|
24
|
-
Requires-Dist: pygame>=2.0; extra == "game"
|
|
25
|
-
Provides-Extra: lsp
|
|
26
|
-
Requires-Dist: pygls>=1.0; extra == "lsp"
|
|
27
|
-
Provides-Extra: all
|
|
28
|
-
Requires-Dist: pygame>=2.0; extra == "all"
|
|
29
|
-
Requires-Dist: pygls>=1.0; extra == "all"
|
|
30
|
-
Dynamic: requires-python
|
|
31
|
-
|
|
32
|
-
# InScript v1.1.0 — First Stable Release
|
|
33
|
-
|
|
34
|
-
> **839 tests passing** · **59 stdlib modules** · **Python 3.10+** · **Audit 9.5/10**
|
|
35
|
-
> `pip install inscript-lang` · **v1.1.0 is the first production-ready release**
|
|
36
|
-
|
|
37
|
-
InScript is a statically-typed scripting language for 2D games — a readable, safe alternative to GDScript with 59 built-in game modules and a complete bytecode VM.
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## Install
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
pip install inscript-lang # core
|
|
45
|
-
pip install "inscript-lang[game]" # with pygame
|
|
46
|
-
pip install "inscript-lang[all]" # pygame + LSP
|
|
47
|
-
inscript --version # InScript 1.1.0
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
## Quick Start
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
inscript --repl # interactive shell
|
|
56
|
-
inscript game.ins # run a file
|
|
57
|
-
inscript --watch game.ins # auto-rerun on save
|
|
58
|
-
inscript --fmt game.ins # format code
|
|
59
|
-
inscript --test # run test_*.ins files
|
|
60
|
-
inscript --check game.ins # static analysis only
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
## Language
|
|
66
|
-
|
|
67
|
-
```inscript
|
|
68
|
-
// Arrow functions
|
|
69
|
-
let evens = [1,2,3,4,5].filter(fn(x) => x % 2 == 0)
|
|
70
|
-
let names = users.map(fn(u) => u.name).sorted()
|
|
71
|
-
|
|
72
|
-
// ADT enums + exhaustive pattern matching
|
|
73
|
-
enum Shape { Circle(r: float) Rect(w: float, h: float) }
|
|
74
|
-
|
|
75
|
-
fn area(s: Shape) -> float {
|
|
76
|
-
return match s {
|
|
77
|
-
case Shape.Circle(r) if r > 10.0 { "large" }
|
|
78
|
-
case Shape.Circle(r) { 3.14159 * r * r }
|
|
79
|
-
case Shape.Rect(w, h) { w * h }
|
|
80
|
-
case 0..=5 { 0.0 }
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Structs with priv, super, decorators
|
|
85
|
-
struct Entity {
|
|
86
|
-
priv id: int = 0
|
|
87
|
-
name: string
|
|
88
|
-
fn update(dt: float) { }
|
|
89
|
-
}
|
|
90
|
-
struct Player extends Entity {
|
|
91
|
-
fn update(dt: float) {
|
|
92
|
-
super.update(dt)
|
|
93
|
-
self.move(dt)
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Result type chaining
|
|
98
|
-
fn divide(a: float, b: float) -> Result {
|
|
99
|
-
if b == 0.0 { return Err("zero") }
|
|
100
|
-
return Ok(a / b)
|
|
101
|
-
}
|
|
102
|
-
let r = divide(10.0, 2.0)
|
|
103
|
-
.map(fn(v) => v * 3.0)
|
|
104
|
-
.unwrap_or(0.0)
|
|
105
|
-
|
|
106
|
-
// Type aliases + nullable + union
|
|
107
|
-
type PlayerID = int
|
|
108
|
-
fn find(id: PlayerID?) -> string|nil { ... }
|
|
109
|
-
|
|
110
|
-
// Rest destructuring
|
|
111
|
-
let [first, ...rest] = [1,2,3,4,5]
|
|
112
|
-
print(rest) // [2, 3, 4, 5]
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
---
|
|
116
|
-
|
|
117
|
-
## Developer Tools
|
|
118
|
-
|
|
119
|
-
| Tool | Command |
|
|
120
|
-
|------|---------|
|
|
121
|
-
| Format | `inscript --fmt file.ins` · `--fmt-check` for CI |
|
|
122
|
-
| Watch | `inscript --watch file.ins` (auto-rerun on save) |
|
|
123
|
-
| Test | `inscript --test` (discovers `test_*.ins`) |
|
|
124
|
-
| REPL | `inscript --repl` · `.doc math` for live module docs |
|
|
125
|
-
| Check | `inscript --check file.ins` (static analysis) |
|
|
126
|
-
| LSP | `inscript --lsp` (VS Code extension available) |
|
|
127
|
-
| Playground | [authorss81.github.io/inscript/playground.html](https://authorss81.github.io/inscript/playground.html) |
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## 59 Game Modules
|
|
132
|
-
|
|
133
|
-
```inscript
|
|
134
|
-
import "physics2d" as P // RigidBody, World, collision callbacks
|
|
135
|
-
import "ecs" as E // Entity-Component-System
|
|
136
|
-
import "pathfind" as N // A*, Dijkstra, flow fields
|
|
137
|
-
import "tilemap" as T // load Tiled maps
|
|
138
|
-
import "camera2d" as C // follow, shake, zoom
|
|
139
|
-
import "particle" as FX // emitter, burst, continuous
|
|
140
|
-
import "fsm" as SM // state machine with guards
|
|
141
|
-
import "save" as S // save slots
|
|
142
|
-
import "audio" as A // load/play/stop/volume
|
|
143
|
-
import "localize" as L // multi-language strings
|
|
144
|
-
// + 49 more: animation, ecs, net_game, image, atlas, shader, ...
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
## Testing Your Code
|
|
150
|
-
|
|
151
|
-
```inscript
|
|
152
|
-
// test_game.ins
|
|
153
|
-
test "player moves right" {
|
|
154
|
-
let p = Player{x: 0.0, y: 0.0}
|
|
155
|
-
p.move(1.0, 0.0)
|
|
156
|
-
assert(p.x == 5.0, "moved right")
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
test "score increases" {
|
|
160
|
-
let g = Game{}
|
|
161
|
-
g.add_score(100)
|
|
162
|
-
assert(g.score == 100, "score added")
|
|
163
|
-
}
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
```bash
|
|
167
|
-
inscript --test # ✅ 2/2 tests passed 12ms
|
|
168
|
-
inscript --test --verbose # shows each test name
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
---
|
|
172
|
-
|
|
173
|
-
## GitHub Actions (auto-publish)
|
|
174
|
-
|
|
175
|
-
The `.github/workflows/publish.yml` workflow automatically publishes to PyPI when you push a version tag:
|
|
176
|
-
|
|
177
|
-
```bash
|
|
178
|
-
git tag -a v1.2.0 -m "InScript v1.2.0"
|
|
179
|
-
git push origin v1.2.0
|
|
180
|
-
# → tests run, then auto-uploads to PyPI
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
Setup: add `PYPI_API_TOKEN` to GitHub repo secrets.
|
|
184
|
-
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
## Upgrading
|
|
188
|
-
|
|
189
|
-
```bash
|
|
190
|
-
pip install --upgrade inscript-lang # from v1.0.x
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
All v1.0.x syntax is fully backward compatible. No changes needed.
|
|
194
|
-
|
|
195
|
-
---
|
|
196
|
-
|
|
197
|
-
## Roadmap
|
|
198
|
-
|
|
199
|
-
| Version | Focus |
|
|
200
|
-
|---------|-------|
|
|
201
|
-
| **v1.1.0** ← you are here | First stable — all tooling complete |
|
|
202
|
-
| v1.2.0 | Type safety — generic enforcement, type narrowing |
|
|
203
|
-
| v1.3.0 | Performance — C extension (5-15× speedup) |
|
|
204
|
-
| v2.0.0 | Ecosystem — package registry, Studio IDE, WASM |
|
|
205
|
-
|
|
206
|
-
[ROADMAP.md](ROADMAP.md) · [Audit (9.5/10)](InScript_Language_Audit.md) · [Docs](https://authorss81.github.io/inscript/docs/)
|
|
207
|
-
|
|
208
|
-
---
|
|
209
|
-
|
|
210
|
-
MIT License · [GitHub](https://github.com/authorss81/inscript) · [PyPI](https://pypi.org/project/inscript-lang/)
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: inscript-lang
|
|
3
|
+
Version: 1.6.0
|
|
4
|
+
Summary: InScript — a game-focused scripting language with 59 game modules and a bytecode VM
|
|
5
|
+
Author: Shreyasi Sarkar
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/authorss81/inscript
|
|
8
|
+
Project-URL: Repository, https://github.com/authorss81/inscript
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/authorss81/inscript/issues
|
|
10
|
+
Project-URL: Documentation, https://authorss81.github.io/inscript/docs/
|
|
11
|
+
Keywords: game,scripting,language,gamedev,gdscript
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Games/Entertainment
|
|
20
|
+
Classifier: Topic :: Software Development :: Interpreters
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
Provides-Extra: game
|
|
24
|
+
Requires-Dist: pygame>=2.0; extra == "game"
|
|
25
|
+
Provides-Extra: lsp
|
|
26
|
+
Requires-Dist: pygls>=1.0; extra == "lsp"
|
|
27
|
+
Provides-Extra: all
|
|
28
|
+
Requires-Dist: pygame>=2.0; extra == "all"
|
|
29
|
+
Requires-Dist: pygls>=1.0; extra == "all"
|
|
30
|
+
Dynamic: requires-python
|
|
31
|
+
|
|
32
|
+
# InScript v1.1.0 — First Stable Release
|
|
33
|
+
|
|
34
|
+
> **839 tests passing** · **59 stdlib modules** · **Python 3.10+** · **Audit 9.5/10**
|
|
35
|
+
> `pip install inscript-lang` · **v1.1.0 is the first production-ready release**
|
|
36
|
+
|
|
37
|
+
InScript is a statically-typed scripting language for 2D games — a readable, safe alternative to GDScript with 59 built-in game modules and a complete bytecode VM.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Install
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install inscript-lang # core
|
|
45
|
+
pip install "inscript-lang[game]" # with pygame
|
|
46
|
+
pip install "inscript-lang[all]" # pygame + LSP
|
|
47
|
+
inscript --version # InScript 1.1.0
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Quick Start
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
inscript --repl # interactive shell
|
|
56
|
+
inscript game.ins # run a file
|
|
57
|
+
inscript --watch game.ins # auto-rerun on save
|
|
58
|
+
inscript --fmt game.ins # format code
|
|
59
|
+
inscript --test # run test_*.ins files
|
|
60
|
+
inscript --check game.ins # static analysis only
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Language
|
|
66
|
+
|
|
67
|
+
```inscript
|
|
68
|
+
// Arrow functions
|
|
69
|
+
let evens = [1,2,3,4,5].filter(fn(x) => x % 2 == 0)
|
|
70
|
+
let names = users.map(fn(u) => u.name).sorted()
|
|
71
|
+
|
|
72
|
+
// ADT enums + exhaustive pattern matching
|
|
73
|
+
enum Shape { Circle(r: float) Rect(w: float, h: float) }
|
|
74
|
+
|
|
75
|
+
fn area(s: Shape) -> float {
|
|
76
|
+
return match s {
|
|
77
|
+
case Shape.Circle(r) if r > 10.0 { "large" }
|
|
78
|
+
case Shape.Circle(r) { 3.14159 * r * r }
|
|
79
|
+
case Shape.Rect(w, h) { w * h }
|
|
80
|
+
case 0..=5 { 0.0 }
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Structs with priv, super, decorators
|
|
85
|
+
struct Entity {
|
|
86
|
+
priv id: int = 0
|
|
87
|
+
name: string
|
|
88
|
+
fn update(dt: float) { }
|
|
89
|
+
}
|
|
90
|
+
struct Player extends Entity {
|
|
91
|
+
fn update(dt: float) {
|
|
92
|
+
super.update(dt)
|
|
93
|
+
self.move(dt)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Result type chaining
|
|
98
|
+
fn divide(a: float, b: float) -> Result {
|
|
99
|
+
if b == 0.0 { return Err("zero") }
|
|
100
|
+
return Ok(a / b)
|
|
101
|
+
}
|
|
102
|
+
let r = divide(10.0, 2.0)
|
|
103
|
+
.map(fn(v) => v * 3.0)
|
|
104
|
+
.unwrap_or(0.0)
|
|
105
|
+
|
|
106
|
+
// Type aliases + nullable + union
|
|
107
|
+
type PlayerID = int
|
|
108
|
+
fn find(id: PlayerID?) -> string|nil { ... }
|
|
109
|
+
|
|
110
|
+
// Rest destructuring
|
|
111
|
+
let [first, ...rest] = [1,2,3,4,5]
|
|
112
|
+
print(rest) // [2, 3, 4, 5]
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Developer Tools
|
|
118
|
+
|
|
119
|
+
| Tool | Command |
|
|
120
|
+
|------|---------|
|
|
121
|
+
| Format | `inscript --fmt file.ins` · `--fmt-check` for CI |
|
|
122
|
+
| Watch | `inscript --watch file.ins` (auto-rerun on save) |
|
|
123
|
+
| Test | `inscript --test` (discovers `test_*.ins`) |
|
|
124
|
+
| REPL | `inscript --repl` · `.doc math` for live module docs |
|
|
125
|
+
| Check | `inscript --check file.ins` (static analysis) |
|
|
126
|
+
| LSP | `inscript --lsp` (VS Code extension available) |
|
|
127
|
+
| Playground | [authorss81.github.io/inscript/playground.html](https://authorss81.github.io/inscript/playground.html) |
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## 59 Game Modules
|
|
132
|
+
|
|
133
|
+
```inscript
|
|
134
|
+
import "physics2d" as P // RigidBody, World, collision callbacks
|
|
135
|
+
import "ecs" as E // Entity-Component-System
|
|
136
|
+
import "pathfind" as N // A*, Dijkstra, flow fields
|
|
137
|
+
import "tilemap" as T // load Tiled maps
|
|
138
|
+
import "camera2d" as C // follow, shake, zoom
|
|
139
|
+
import "particle" as FX // emitter, burst, continuous
|
|
140
|
+
import "fsm" as SM // state machine with guards
|
|
141
|
+
import "save" as S // save slots
|
|
142
|
+
import "audio" as A // load/play/stop/volume
|
|
143
|
+
import "localize" as L // multi-language strings
|
|
144
|
+
// + 49 more: animation, ecs, net_game, image, atlas, shader, ...
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Testing Your Code
|
|
150
|
+
|
|
151
|
+
```inscript
|
|
152
|
+
// test_game.ins
|
|
153
|
+
test "player moves right" {
|
|
154
|
+
let p = Player{x: 0.0, y: 0.0}
|
|
155
|
+
p.move(1.0, 0.0)
|
|
156
|
+
assert(p.x == 5.0, "moved right")
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
test "score increases" {
|
|
160
|
+
let g = Game{}
|
|
161
|
+
g.add_score(100)
|
|
162
|
+
assert(g.score == 100, "score added")
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
inscript --test # ✅ 2/2 tests passed 12ms
|
|
168
|
+
inscript --test --verbose # shows each test name
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## GitHub Actions (auto-publish)
|
|
174
|
+
|
|
175
|
+
The `.github/workflows/publish.yml` workflow automatically publishes to PyPI when you push a version tag:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
git tag -a v1.2.0 -m "InScript v1.2.0"
|
|
179
|
+
git push origin v1.2.0
|
|
180
|
+
# → tests run, then auto-uploads to PyPI
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Setup: add `PYPI_API_TOKEN` to GitHub repo secrets.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Upgrading
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
pip install --upgrade inscript-lang # from v1.0.x
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
All v1.0.x syntax is fully backward compatible. No changes needed.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Roadmap
|
|
198
|
+
|
|
199
|
+
| Version | Focus |
|
|
200
|
+
|---------|-------|
|
|
201
|
+
| **v1.1.0** ← you are here | First stable — all tooling complete |
|
|
202
|
+
| v1.2.0 | Type safety — generic enforcement, type narrowing |
|
|
203
|
+
| v1.3.0 | Performance — C extension (5-15× speedup) |
|
|
204
|
+
| v2.0.0 | Ecosystem — package registry, Studio IDE, WASM |
|
|
205
|
+
|
|
206
|
+
[ROADMAP.md](ROADMAP.md) · [Audit (9.5/10)](InScript_Language_Audit.md) · [Docs](https://authorss81.github.io/inscript/docs/)
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
MIT License · [GitHub](https://github.com/authorss81/inscript) · [PyPI](https://pypi.org/project/inscript-lang/)
|
|
@@ -133,6 +133,7 @@ class Symbol:
|
|
|
133
133
|
self.struct_node = struct_node # for structs: the AST node
|
|
134
134
|
self.line = line
|
|
135
135
|
self.col = col
|
|
136
|
+
self.used = False # v1.2.0: unused-variable tracking
|
|
136
137
|
|
|
137
138
|
|
|
138
139
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -180,7 +181,8 @@ class Analyzer(Visitor):
|
|
|
180
181
|
def __init__(self, source_lines: List[str] = None,
|
|
181
182
|
multi_error: bool = True,
|
|
182
183
|
warn_as_error: bool = False,
|
|
183
|
-
no_warn: bool = False
|
|
184
|
+
no_warn: bool = False,
|
|
185
|
+
no_warn_unused: bool = False):
|
|
184
186
|
self._src = source_lines or []
|
|
185
187
|
self._scope = Scope(kind="global")
|
|
186
188
|
self._errors: List[SemanticError] = [] # collected (multi-error)
|
|
@@ -188,6 +190,8 @@ class Analyzer(Visitor):
|
|
|
188
190
|
self._multi_error = multi_error
|
|
189
191
|
self._warn_as_error = warn_as_error
|
|
190
192
|
self._no_warn = no_warn
|
|
193
|
+
self._no_warn_unused = no_warn_unused
|
|
194
|
+
self._dispatch: dict = {} # v1.3.0: cached dispatch
|
|
191
195
|
|
|
192
196
|
# State for context-sensitive checks
|
|
193
197
|
self._current_fn_return_type: Optional[InScriptType] = None
|
|
@@ -261,6 +265,7 @@ class Analyzer(Visitor):
|
|
|
261
265
|
candidates = list(self._all_visible_names())
|
|
262
266
|
self._error(f"Undefined name: '{name}'", line, col, candidates)
|
|
263
267
|
return Symbol(name, T_ANY, kind="var") # dummy to continue analysis
|
|
268
|
+
sym.used = True # v1.2.0: mark as used
|
|
264
269
|
return sym
|
|
265
270
|
|
|
266
271
|
def _all_visible_names(self) -> List[str]:
|
|
@@ -307,6 +312,19 @@ class Analyzer(Visitor):
|
|
|
307
312
|
|
|
308
313
|
def _pop_scope(self) -> Scope:
|
|
309
314
|
old = self._scope
|
|
315
|
+
# v1.2.0: warn about unused locals in fn/block scopes
|
|
316
|
+
if (not self._no_warn and not self._no_warn_unused
|
|
317
|
+
and old.kind in ("fn", "block", "match_arm")):
|
|
318
|
+
for sym in old.symbols.values():
|
|
319
|
+
if (sym.kind in ("var", "const")
|
|
320
|
+
and not sym.used
|
|
321
|
+
and not sym.name.startswith("_")):
|
|
322
|
+
self._warn(
|
|
323
|
+
"unused",
|
|
324
|
+
f"Variable '{sym.name}' is defined but never used "
|
|
325
|
+
f"(prefix with '_' to suppress)",
|
|
326
|
+
sym.line,
|
|
327
|
+
)
|
|
310
328
|
self._scope = self._scope.parent
|
|
311
329
|
return old
|
|
312
330
|
|
|
@@ -523,13 +541,15 @@ class Analyzer(Visitor):
|
|
|
523
541
|
prev_ret = self._current_fn_return_type
|
|
524
542
|
self._current_fn_return_type = ret_type
|
|
525
543
|
|
|
526
|
-
# Register parameters
|
|
544
|
+
# Register parameters — mark used=True so we never warn about unused params
|
|
527
545
|
for param in node.params:
|
|
528
546
|
p_type = self._resolve_type_ann(param.type_ann)
|
|
529
|
-
|
|
547
|
+
sym = Symbol(
|
|
530
548
|
param.name, p_type, kind="var",
|
|
531
549
|
line=param.line, col=param.col
|
|
532
|
-
)
|
|
550
|
+
)
|
|
551
|
+
sym.used = True # params are always "used" by the caller
|
|
552
|
+
self._define(sym)
|
|
533
553
|
|
|
534
554
|
# Analyze body
|
|
535
555
|
self.visit(node.body)
|
|
@@ -657,17 +677,18 @@ class Analyzer(Visitor):
|
|
|
657
677
|
|
|
658
678
|
def visit_BlockStmt(self, node: BlockStmt) -> InScriptType:
|
|
659
679
|
self._push_scope("block")
|
|
660
|
-
|
|
680
|
+
terminated = False # True after return/break/continue/throw
|
|
661
681
|
for stmt in node.body:
|
|
662
|
-
if
|
|
663
|
-
# 3.6: warn about unreachable code after return/break/continue
|
|
682
|
+
if terminated and not self._no_warn:
|
|
664
683
|
line = getattr(stmt, "line", 0)
|
|
665
684
|
self._warn("unreachable",
|
|
666
|
-
"Unreachable code after return/break/continue",
|
|
667
|
-
|
|
685
|
+
"Unreachable code after return/break/continue/throw",
|
|
686
|
+
line)
|
|
687
|
+
# Still visit so inner undefined-name errors are caught
|
|
668
688
|
self.visit(stmt)
|
|
669
|
-
|
|
670
|
-
|
|
689
|
+
from ast_nodes import ThrowStmt as ThrowStmt_
|
|
690
|
+
if isinstance(stmt, (ReturnStmt, BreakStmt, ContinueStmt, ThrowStmt_)):
|
|
691
|
+
terminated = True
|
|
671
692
|
self._pop_scope()
|
|
672
693
|
return T_VOID
|
|
673
694
|
|
|
@@ -344,6 +344,12 @@ class MatchArm(Node):
|
|
|
344
344
|
guard: Optional[Node] = None # if condition: case x if x > 0 { ... }
|
|
345
345
|
binding: Optional[str] = None # case h if h <= 0 { ... } — 'h' bound to subject
|
|
346
346
|
|
|
347
|
+
@dataclass
|
|
348
|
+
class TypePattern(Node):
|
|
349
|
+
"""v1.4.0: type-narrowing match pattern — case int x { } or case Vec2 v { }"""
|
|
350
|
+
type_name: str # "int", "float", "string", "bool", or struct name
|
|
351
|
+
var_name: str # variable bound to the narrowed value
|
|
352
|
+
|
|
347
353
|
@dataclass
|
|
348
354
|
class MatchStmt(Node):
|
|
349
355
|
subject: Node
|
|
@@ -429,8 +435,14 @@ class Visitor:
|
|
|
429
435
|
"""
|
|
430
436
|
|
|
431
437
|
def visit(self, node: Node) -> Any:
|
|
432
|
-
|
|
433
|
-
|
|
438
|
+
# v1.3.0: cache dispatch table per visitor class to avoid getattr on every call
|
|
439
|
+
cls = type(node)
|
|
440
|
+
try:
|
|
441
|
+
return self._dispatch[cls](node)
|
|
442
|
+
except KeyError:
|
|
443
|
+
method = getattr(self, f"visit_{cls.__name__}", self.generic_visit)
|
|
444
|
+
self._dispatch[cls] = method
|
|
445
|
+
return method(node)
|
|
434
446
|
|
|
435
447
|
def generic_visit(self, node: Node) -> Any:
|
|
436
448
|
raise NotImplementedError(
|
|
@@ -447,6 +459,17 @@ class ThrowStmt(Node):
|
|
|
447
459
|
"""throw ErrorExpr"""
|
|
448
460
|
value: Node
|
|
449
461
|
|
|
462
|
+
@dataclass
|
|
463
|
+
class DeferStmt(Node):
|
|
464
|
+
"""v1.4.0: defer expr_or_call — runs at end of enclosing function/block"""
|
|
465
|
+
expr: Node
|
|
466
|
+
|
|
467
|
+
@dataclass
|
|
468
|
+
class RepeatUntilStmt(Node):
|
|
469
|
+
"""v1.4.0: repeat { body } until condition — do-while equivalent"""
|
|
470
|
+
body: "BlockStmt"
|
|
471
|
+
condition: Node
|
|
472
|
+
|
|
450
473
|
@dataclass
|
|
451
474
|
class TryCatchStmt(Node):
|
|
452
475
|
"""try { body } catch(e: T) { ... } catch e { ... } — multiple catch clauses supported"""
|