inscript-lang 2.1.0__tar.gz → 2.1.2__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.
Files changed (30) hide show
  1. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/PKG-INFO +1 -1
  2. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/inscript.py +1 -1
  3. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/inscript_fmt.py +138 -14
  4. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/inscript_lang.egg-info/PKG-INFO +1 -1
  5. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/pyproject.toml +1 -1
  6. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/repl.py +1 -1
  7. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/README.md +0 -0
  8. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/analyzer.py +0 -0
  9. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/ast_nodes.py +0 -0
  10. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/compiler.py +0 -0
  11. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/environment.py +0 -0
  12. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/errors.py +0 -0
  13. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/inscript_lang.egg-info/SOURCES.txt +0 -0
  14. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/inscript_lang.egg-info/dependency_links.txt +0 -0
  15. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/inscript_lang.egg-info/entry_points.txt +0 -0
  16. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/inscript_lang.egg-info/requires.txt +0 -0
  17. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/inscript_lang.egg-info/top_level.txt +0 -0
  18. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/inscript_test.py +0 -0
  19. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/interpreter.py +0 -0
  20. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/lexer.py +0 -0
  21. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/parser.py +0 -0
  22. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/pygame_backend.py +0 -0
  23. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/setup.cfg +0 -0
  24. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/setup.py +0 -0
  25. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/stdlib.py +0 -0
  26. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/stdlib_extended.py +0 -0
  27. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/stdlib_extended_2.py +0 -0
  28. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/stdlib_game.py +0 -0
  29. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/stdlib_values.py +0 -0
  30. {inscript_lang-2.1.0 → inscript_lang-2.1.2}/vm.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: inscript-lang
3
- Version: 2.1.0
3
+ Version: 2.1.2
4
4
  Summary: InScript — a game-focused scripting language with 59 game modules and a bytecode VM
5
5
  Author: Shreyasi Sarkar
6
6
  License: MIT
@@ -24,7 +24,7 @@ from errors import (InScriptError, LexerError, ParseError,
24
24
  SemanticError, InScriptRuntimeError,
25
25
  MultiError, InScriptWarning)
26
26
 
27
- VERSION = "2.1.0"
27
+ VERSION = "2.1.2"
28
28
 
29
29
  MANIFEST_FILENAME = "inscript.toml"
30
30
  LOCK_FILENAME = "inscript.lock"
@@ -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.DOTDOT, TT.DOTDOT_EQ, TT.FAT_ARROW
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
- flush()
187
+ _brace_kind = _brace_stack.pop() if _brace_stack else 'block'
135
188
  indent_level = max(0, indent_level - 1)
136
- current_line.append(cur_indent() + '}')
137
- # If next token is 'else', 'catch', 'finally' — stay on same line
138
- if nxt and _get_attr(nxt) in ('else', 'catch', 'finally'):
139
- current_line.append(' ')
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
- prev = tok; i += 1
143
- continue
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
- if prev is not None:
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
- current_line.append('f"' + v + '"')
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 is not None:
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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: inscript-lang
3
- Version: 2.1.0
3
+ Version: 2.1.2
4
4
  Summary: InScript — a game-focused scripting language with 59 game modules and a bytecode VM
5
5
  Author: Shreyasi Sarkar
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "inscript-lang"
7
- version = "2.1.0"
7
+ version = "2.1.2"
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.0"
43
+ VERSION = "2.1.2"
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