inscript-lang 2.1.0__tar.gz → 2.1.1__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.1.0 → inscript_lang-2.1.1}/PKG-INFO +1 -1
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/inscript.py +1 -1
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/inscript_fmt.py +138 -14
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/inscript_lang.egg-info/PKG-INFO +1 -1
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/pyproject.toml +1 -1
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/repl.py +1 -1
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/README.md +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/analyzer.py +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/ast_nodes.py +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/compiler.py +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/environment.py +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/errors.py +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/inscript_lang.egg-info/SOURCES.txt +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/inscript_lang.egg-info/dependency_links.txt +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/inscript_lang.egg-info/entry_points.txt +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/inscript_lang.egg-info/requires.txt +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/inscript_lang.egg-info/top_level.txt +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/inscript_test.py +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/interpreter.py +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/lexer.py +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/parser.py +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/pygame_backend.py +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/setup.cfg +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/setup.py +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/stdlib.py +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/stdlib_extended.py +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/stdlib_extended_2.py +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/stdlib_game.py +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/stdlib_values.py +0 -0
- {inscript_lang-2.1.0 → inscript_lang-2.1.1}/vm.py +0 -0
|
@@ -29,7 +29,7 @@ from lexer import Lexer, TT, Token
|
|
|
29
29
|
|
|
30
30
|
# ── Token categories ─────────────────────────────────────────────────────────
|
|
31
31
|
_BINARY_OPS = {
|
|
32
|
-
TT.PLUS, TT.MINUS, TT.STAR, TT.SLASH, TT.PERCENT, TT.POWER, TT.EQ, TT.NEQ, TT.LT, TT.GT, TT.LTE, TT.GTE, TT.AND, TT.OR, TT.BIT_AND, TT.BIT_OR, TT.BIT_XOR, TT.LSHIFT, TT.RSHIFT, TT.ASSIGN, TT.PLUS_EQ, TT.MINUS_EQ, TT.STAR_EQ, TT.SLASH_EQ, TT.PERCENT_EQ, TT.POWER_EQ, TT.LSHIFT_EQ, TT.RSHIFT_EQ, TT.AMP_EQ, TT.PIPE_EQ, TT.CARET_EQ, TT.PIPE_GT, TT.PLUSPLUS, TT.
|
|
32
|
+
TT.PLUS, TT.MINUS, TT.STAR, TT.SLASH, TT.PERCENT, TT.POWER, TT.EQ, TT.NEQ, TT.LT, TT.GT, TT.LTE, TT.GTE, TT.AND, TT.OR, TT.BIT_AND, TT.BIT_OR, TT.BIT_XOR, TT.LSHIFT, TT.RSHIFT, TT.ASSIGN, TT.PLUS_EQ, TT.MINUS_EQ, TT.STAR_EQ, TT.SLASH_EQ, TT.PERCENT_EQ, TT.POWER_EQ, TT.LSHIFT_EQ, TT.RSHIFT_EQ, TT.AMP_EQ, TT.PIPE_EQ, TT.CARET_EQ, TT.PIPE_GT, TT.PLUSPLUS, TT.FAT_ARROW
|
|
33
33
|
}
|
|
34
34
|
_OPEN_DELIM = {TT.LBRACE, TT.LBRACKET, TT.LPAREN}
|
|
35
35
|
_CLOSE_DELIM = {TT.RBRACE, TT.RBRACKET, TT.RPAREN}
|
|
@@ -87,6 +87,11 @@ class Formatter:
|
|
|
87
87
|
indent_level = 0
|
|
88
88
|
prev: Token | None = None
|
|
89
89
|
prev2: Token | None = None
|
|
90
|
+
# v2.1.1: context tracking for inline case arms and struct fields
|
|
91
|
+
_in_case = False # True after 'case <pat>' — next { stays inline
|
|
92
|
+
_struct_depths = [] # indent_levels at which struct bodies were opened
|
|
93
|
+
_brace_stack = [] # 'dict' or 'block' for each open brace
|
|
94
|
+
_in_generic = 0 # v2.1.1: depth counter for Array<T> generics
|
|
90
95
|
|
|
91
96
|
def cur_indent():
|
|
92
97
|
return ' ' * (indent_level * self.indent)
|
|
@@ -120,27 +125,87 @@ class Formatter:
|
|
|
120
125
|
|
|
121
126
|
# ── opening brace → same line, then newline ──────────────────
|
|
122
127
|
if tt == TT.LBRACE:
|
|
128
|
+
# v2.1.1: dict/object literal { stays inline when preceded by
|
|
129
|
+
# an assignment, operator, (, [, or , — not a block opener
|
|
130
|
+
_dict_ctx_types = {
|
|
131
|
+
TT.ASSIGN, TT.PLUS_EQ, TT.MINUS_EQ,
|
|
132
|
+
TT.LPAREN, TT.LBRACKET, TT.COMMA, TT.COLON,
|
|
133
|
+
TT.PLUS, TT.MINUS, TT.STAR, TT.SLASH, TT.PERCENT,
|
|
134
|
+
TT.RETURN, TT.FAT_ARROW,
|
|
135
|
+
}
|
|
136
|
+
_is_dict_literal = prev and prev.type in _dict_ctx_types
|
|
123
137
|
# Put { on same line with a space
|
|
124
138
|
if current_line and current_line[-1] not in ('', ' ', '\t'):
|
|
125
139
|
current_line.append(' ')
|
|
126
140
|
current_line.append('{')
|
|
127
141
|
indent_level += 1
|
|
142
|
+
# v2.1.1: track struct/interface bodies for field-separator newlines
|
|
143
|
+
# prev is the struct NAME (e.g. 'Player'), prev2 is the 'struct' keyword
|
|
144
|
+
if prev2 and _get_attr(prev2) in ('struct', 'interface', 'mixin'):
|
|
145
|
+
_struct_depths.append(indent_level)
|
|
146
|
+
# v2.1.1: dict literal — keep contents on same line, don't flush
|
|
147
|
+
_brace_stack.append('dict' if _is_dict_literal else 'block')
|
|
148
|
+
if _is_dict_literal:
|
|
149
|
+
prev = tok; i += 1
|
|
150
|
+
continue
|
|
151
|
+
# v2.1.1: case arm inline — if _in_case, keep { expr } on same line
|
|
152
|
+
if _in_case:
|
|
153
|
+
_in_case = False
|
|
154
|
+
# Collect tokens until matching } into same line
|
|
155
|
+
depth2 = 1; j = i + 1
|
|
156
|
+
inline_toks = []
|
|
157
|
+
while j < n and depth2 > 0:
|
|
158
|
+
t2 = toks[j]
|
|
159
|
+
if t2.type == TT.LBRACE: depth2 += 1
|
|
160
|
+
elif t2.type == TT.RBRACE: depth2 -= 1
|
|
161
|
+
if depth2 > 0: inline_toks.append(t2)
|
|
162
|
+
j += 1
|
|
163
|
+
# Only inline if content is simple (no newlines, single expr)
|
|
164
|
+
has_nested = any(t2.type == TT.LBRACE for t2 in inline_toks)
|
|
165
|
+
if not has_nested and len(inline_toks) <= 8:
|
|
166
|
+
# Emit inline
|
|
167
|
+
current_line.append(' ')
|
|
168
|
+
for t2 in inline_toks:
|
|
169
|
+
v2 = _get_attr(t2)
|
|
170
|
+
if t2.type == TT.STRING: current_line.append('"'+v2+'"')
|
|
171
|
+
elif t2.type == TT.FSTRING: current_line.append('$"'+v2+'"')
|
|
172
|
+
else: current_line.append(str(v2) if v2 else t2.type.name.lower())
|
|
173
|
+
current_line.append(' ')
|
|
174
|
+
current_line.append('}')
|
|
175
|
+
indent_level -= 1
|
|
176
|
+
if _struct_depths and indent_level < _struct_depths[-1]:
|
|
177
|
+
_struct_depths.pop()
|
|
178
|
+
flush()
|
|
179
|
+
prev = toks[j-1]; i = j
|
|
180
|
+
continue
|
|
128
181
|
flush()
|
|
129
182
|
prev = tok; i += 1
|
|
130
183
|
continue
|
|
131
184
|
|
|
132
185
|
# ── closing brace → dedent then } ────────────────────────────
|
|
133
186
|
if tt == TT.RBRACE:
|
|
134
|
-
|
|
187
|
+
_brace_kind = _brace_stack.pop() if _brace_stack else 'block'
|
|
135
188
|
indent_level = max(0, indent_level - 1)
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
189
|
+
# v2.1.1: pop struct depth tracking
|
|
190
|
+
if _struct_depths and indent_level < _struct_depths[-1]:
|
|
191
|
+
_struct_depths.pop()
|
|
192
|
+
if _brace_kind == 'dict':
|
|
193
|
+
# Dict literal: emit } inline, no flush (keeps content on same line)
|
|
194
|
+
current_line.append('}')
|
|
195
|
+
prev = tok; i += 1
|
|
196
|
+
continue
|
|
140
197
|
else:
|
|
141
|
-
flush
|
|
142
|
-
|
|
143
|
-
|
|
198
|
+
# Block: flush pending content then emit } at correct indent
|
|
199
|
+
if current_line and ''.join(current_line).strip():
|
|
200
|
+
flush()
|
|
201
|
+
current_line.append(cur_indent() + '}')
|
|
202
|
+
# If next token is 'else', 'catch', 'finally' — stay on same line
|
|
203
|
+
if nxt and _get_attr(nxt) in ('else', 'catch', 'finally'):
|
|
204
|
+
current_line.append(' ')
|
|
205
|
+
else:
|
|
206
|
+
flush()
|
|
207
|
+
prev = tok; i += 1
|
|
208
|
+
continue
|
|
144
209
|
|
|
145
210
|
# ── semicolons → newline ──────────────────────────────────────
|
|
146
211
|
if tt == TT.SEMICOLON:
|
|
@@ -149,6 +214,14 @@ class Formatter:
|
|
|
149
214
|
continue
|
|
150
215
|
|
|
151
216
|
# ── start of a new token on a new line ───────────────────────
|
|
217
|
+
# v2.1.1: struct field separator — flush before next field
|
|
218
|
+
# Must come BEFORE `if not current_line` so indent isn't doubled
|
|
219
|
+
if _struct_depths and indent_level == _struct_depths[-1]:
|
|
220
|
+
if (tt == TT.IDENT and nxt and nxt.type == TT.COLON and
|
|
221
|
+
current_line and ''.join(current_line).strip()):
|
|
222
|
+
flush() # let `if not current_line` add the indent
|
|
223
|
+
prev = None # reset spacing context — fresh line
|
|
224
|
+
|
|
152
225
|
if not current_line:
|
|
153
226
|
# blank line before top-level declarations (except first)
|
|
154
227
|
if needs_blank_before(tok) and result_lines and result_lines[-1] != '':
|
|
@@ -157,20 +230,24 @@ class Formatter:
|
|
|
157
230
|
|
|
158
231
|
# ── spacing logic ─────────────────────────────────────────────
|
|
159
232
|
needs_space = False
|
|
160
|
-
|
|
233
|
+
_line_is_indent_only = current_line and ''.join(current_line).strip() == ''
|
|
234
|
+
if prev is not None and not _line_is_indent_only:
|
|
161
235
|
ptt = prev.type
|
|
162
236
|
pv = _get_attr(prev)
|
|
237
|
+
# v2.1.1: always space after colon (type annotations, dict literals)
|
|
238
|
+
if ptt == TT.COLON and tt not in _CLOSE_DELIM and tt != TT.COLON:
|
|
239
|
+
needs_space = True
|
|
163
240
|
# Always space after comma
|
|
164
241
|
if ptt == TT.COMMA:
|
|
165
242
|
needs_space = True
|
|
166
243
|
# Space around binary ops
|
|
167
|
-
elif tt in _BINARY_OPS and pv not in ('', ' '):
|
|
244
|
+
elif tt in _BINARY_OPS and pv not in ('', ' ') and _in_generic == 0:
|
|
168
245
|
# Check it's actually binary (not unary minus after operator/open)
|
|
169
246
|
if ptt not in _OPEN_DELIM and ptt not in _BINARY_OPS:
|
|
170
247
|
needs_space = True
|
|
171
248
|
elif tt == TT.ASSIGN:
|
|
172
249
|
needs_space = True
|
|
173
|
-
elif ptt in _BINARY_OPS:
|
|
250
|
+
elif ptt in _BINARY_OPS and _in_generic == 0:
|
|
174
251
|
needs_space = True
|
|
175
252
|
# No space before these
|
|
176
253
|
elif tt in _NO_SPACE_BEFORE:
|
|
@@ -201,12 +278,42 @@ class Formatter:
|
|
|
201
278
|
|
|
202
279
|
# ── emit token ────────────────────────────────────────────────
|
|
203
280
|
if tt == TT.FSTRING:
|
|
204
|
-
|
|
281
|
+
# v2.1.1: always emit $"..." (preferred syntax since v1.9.15)
|
|
282
|
+
current_line.append('$"' + v + '"')
|
|
205
283
|
elif tt == TT.STRING:
|
|
206
284
|
# Preserve original quotes
|
|
207
285
|
current_line.append('"' + v.replace('"', '\\"') + '"')
|
|
286
|
+
elif tt == TT.LT and prev and prev.type == TT.IDENT and _get_attr(prev) and _get_attr(prev)[0].isupper():
|
|
287
|
+
# v2.1.1: Array<T> — enter generic mode, suppress spaces around <>
|
|
288
|
+
if current_line and current_line[-1] == ' ':
|
|
289
|
+
current_line.pop()
|
|
290
|
+
_in_generic += 1
|
|
291
|
+
current_line.append('<')
|
|
292
|
+
prev = tok; i += 1
|
|
293
|
+
continue
|
|
294
|
+
elif tt == TT.GT and _in_generic > 0:
|
|
295
|
+
# v2.1.1: closing generic >
|
|
296
|
+
_in_generic -= 1
|
|
297
|
+
current_line.append('>')
|
|
298
|
+
prev = tok; i += 1
|
|
299
|
+
continue
|
|
300
|
+
elif tt == TT.GTE and _in_generic > 0:
|
|
301
|
+
# v2.1.1: lexer fused '>=' — split into > (close generic) + = (assign)
|
|
302
|
+
_in_generic -= 1
|
|
303
|
+
current_line.append('>')
|
|
304
|
+
current_line.append(' ')
|
|
305
|
+
current_line.append('=')
|
|
306
|
+
current_line.append(' ')
|
|
307
|
+
prev = tok; i += 1
|
|
308
|
+
continue
|
|
208
309
|
elif tt == TT.ARROW:
|
|
310
|
+
# v2.1.1: spaces around -> (return type annotation)
|
|
311
|
+
if current_line and current_line[-1] not in (' ', ''):
|
|
312
|
+
current_line.append(' ')
|
|
209
313
|
current_line.append('->')
|
|
314
|
+
current_line.append(' ')
|
|
315
|
+
prev = tok; i += 1
|
|
316
|
+
continue
|
|
210
317
|
elif tt == TT.FAT_ARROW:
|
|
211
318
|
current_line.append('=>')
|
|
212
319
|
elif tt == TT.PLUSPLUS:
|
|
@@ -219,11 +326,28 @@ class Formatter:
|
|
|
219
326
|
current_line.append('?.')
|
|
220
327
|
elif tt == TT.PIPE_GT:
|
|
221
328
|
current_line.append('|>')
|
|
222
|
-
elif v
|
|
329
|
+
elif v:
|
|
223
330
|
current_line.append(str(v))
|
|
224
331
|
else:
|
|
225
332
|
current_line.append(tok.type.name.lower())
|
|
226
333
|
|
|
334
|
+
# v2.1.1: track CASE keyword for inline arm formatting
|
|
335
|
+
if tt == TT.CASE:
|
|
336
|
+
_in_case = True
|
|
337
|
+
elif _in_case and tt == TT.LBRACE:
|
|
338
|
+
pass # handled above
|
|
339
|
+
elif _in_case and tt not in (
|
|
340
|
+
TT.IDENT, TT.INT, TT.FLOAT, TT.STRING,
|
|
341
|
+
TT.INT_TYPE, TT.FLOAT_TYPE, TT.STRING_TYPE, TT.BOOL_TYPE,
|
|
342
|
+
TT.PIPE, TT.IF, TT.CASE, TT.NOT,
|
|
343
|
+
TT.NIL, TT.BOOL,
|
|
344
|
+
TT.DOTDOT, TT.DOTDOT_EQ,
|
|
345
|
+
# guard expression operators: case h if h > 5
|
|
346
|
+
TT.EQ, TT.NEQ, TT.LT, TT.GT, TT.LTE, TT.GTE,
|
|
347
|
+
TT.AND, TT.OR, TT.PLUS, TT.MINUS, TT.STAR, TT.SLASH,
|
|
348
|
+
TT.PERCENT, TT.LPAREN, TT.RPAREN):
|
|
349
|
+
_in_case = False
|
|
350
|
+
prev2 = prev
|
|
227
351
|
prev = tok
|
|
228
352
|
i += 1
|
|
229
353
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "inscript-lang"
|
|
7
|
-
version = "2.1.
|
|
7
|
+
version = "2.1.1"
|
|
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.1.
|
|
43
|
+
VERSION = "2.1.1"
|
|
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
|