inscript-lang 1.9.5__tar.gz → 1.9.7__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.5 → inscript_lang-1.9.7}/PKG-INFO +1 -1
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/analyzer.py +29 -12
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/inscript.py +16 -4
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/inscript_lang.egg-info/PKG-INFO +1 -1
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/interpreter.py +50 -3
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/lexer.py +7 -19
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/pyproject.toml +1 -1
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/repl.py +1 -1
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/stdlib_values.py +17 -1
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/README.md +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/ast_nodes.py +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/compiler.py +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/environment.py +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/errors.py +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/inscript_fmt.py +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/inscript_lang.egg-info/SOURCES.txt +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/inscript_lang.egg-info/dependency_links.txt +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/inscript_lang.egg-info/entry_points.txt +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/inscript_lang.egg-info/requires.txt +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/inscript_lang.egg-info/top_level.txt +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/inscript_test.py +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/parser.py +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/pygame_backend.py +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/setup.cfg +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/setup.py +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/stdlib.py +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/stdlib_extended.py +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/stdlib_extended_2.py +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/stdlib_game.py +0 -0
- {inscript_lang-1.9.5 → inscript_lang-1.9.7}/vm.py +0 -0
|
@@ -65,12 +65,14 @@ T_TRANSFORM3D = InScriptType("Transform3D")
|
|
|
65
65
|
T_TEXTURE = InScriptType("Texture")
|
|
66
66
|
|
|
67
67
|
T_NEVER = InScriptType("never") # v1.8.3: bottom type — function never returns normally
|
|
68
|
+
T_PROMISE = InScriptType("Promise") # v1.9.7: async fn return type
|
|
68
69
|
|
|
69
70
|
BUILTIN_TYPES: Dict[str, InScriptType] = {
|
|
70
71
|
# canonical names
|
|
71
72
|
"int": T_INT, "float": T_FLOAT, "bool": T_BOOL,
|
|
72
73
|
"string": T_STRING, "void": T_VOID, "null": T_NULL, "any": T_ANY,
|
|
73
74
|
"never": T_NEVER, # v1.8.3
|
|
75
|
+
"Promise": T_PROMISE, # v1.9.7: async fn return type
|
|
74
76
|
# common aliases
|
|
75
77
|
"str": T_STRING, "boolean": T_BOOL, "number": T_FLOAT,
|
|
76
78
|
"nil": T_NULL, "object": T_ANY, "auto": T_ANY,
|
|
@@ -648,21 +650,36 @@ class Analyzer(Visitor):
|
|
|
648
650
|
def visit_FunctionDecl(self, node: FunctionDecl) -> InScriptType:
|
|
649
651
|
ret_type = self._resolve_type_ann(node.return_type)
|
|
650
652
|
|
|
653
|
+
# v1.9.7: async fn — external return type is Promise<T>, but the body
|
|
654
|
+
# is checked against the inner type T (what the fn actually returns).
|
|
655
|
+
# E.g.: `async fn f() -> string` → body checked vs `string`, external type = Promise<string>
|
|
656
|
+
is_async = getattr(node, 'is_async', False)
|
|
657
|
+
if is_async:
|
|
658
|
+
inner_ret_type = ret_type if ret_type not in (T_ANY, T_VOID) else T_ANY
|
|
659
|
+
external_ret_type = InScriptType("Promise", [inner_ret_type])
|
|
660
|
+
else:
|
|
661
|
+
inner_ret_type = ret_type
|
|
662
|
+
external_ret_type = ret_type
|
|
663
|
+
|
|
651
664
|
# v1.8.4: return type inference — if no annotation and body has a single
|
|
652
|
-
# unambiguous return type, infer it automatically
|
|
653
|
-
if node.return_type is None and
|
|
665
|
+
# unambiguous return type, infer it automatically (use inner type for async)
|
|
666
|
+
if node.return_type is None and inner_ret_type == T_ANY and node.body:
|
|
654
667
|
inferred = self._infer_fn_return_type(node)
|
|
655
668
|
if inferred not in (T_ANY, T_VOID, T_NULL):
|
|
656
|
-
|
|
669
|
+
inner_ret_type = inferred
|
|
670
|
+
if is_async:
|
|
671
|
+
external_ret_type = InScriptType("Promise", [inner_ret_type])
|
|
672
|
+
else:
|
|
673
|
+
external_ret_type = inner_ret_type
|
|
657
674
|
# Update the hoisted symbol's type to the inferred one
|
|
658
675
|
existing = self._scope.lookup(node.name)
|
|
659
676
|
if existing and existing.kind == "fn":
|
|
660
|
-
existing.type_ =
|
|
677
|
+
existing.type_ = external_ret_type
|
|
661
678
|
|
|
662
|
-
# Register in current scope (
|
|
679
|
+
# Register in current scope using external type (Promise<T> for async)
|
|
663
680
|
if not self._scope.lookup_local(node.name):
|
|
664
681
|
self._define(Symbol(
|
|
665
|
-
node.name,
|
|
682
|
+
node.name, external_ret_type, kind="fn",
|
|
666
683
|
fn_node=node, line=node.line, col=node.col
|
|
667
684
|
))
|
|
668
685
|
|
|
@@ -676,10 +693,10 @@ class Analyzer(Visitor):
|
|
|
676
693
|
|
|
677
694
|
# Warn if function declares a non-void return type but body may not return
|
|
678
695
|
if (node.return_type is not None and
|
|
679
|
-
|
|
696
|
+
inner_ret_type.name not in ("void", "nil", "any", "") and
|
|
680
697
|
not node.is_native if hasattr(node, 'is_native') else True):
|
|
681
698
|
if node.body and not self._body_always_returns(node.body):
|
|
682
|
-
if
|
|
699
|
+
if inner_ret_type == T_NEVER:
|
|
683
700
|
# v1.8.3: `-> never` functions MUST always throw / diverge
|
|
684
701
|
self._error(
|
|
685
702
|
f"Function '{node.name}' is declared '-> never' "
|
|
@@ -689,15 +706,15 @@ class Analyzer(Visitor):
|
|
|
689
706
|
else:
|
|
690
707
|
self._warn(
|
|
691
708
|
"missing-return",
|
|
692
|
-
f"Function '{node.name}' declares return type '{
|
|
709
|
+
f"Function '{node.name}' declares return type '{inner_ret_type.name}' "
|
|
693
710
|
f"but not all code paths return a value",
|
|
694
711
|
node.line
|
|
695
712
|
)
|
|
696
713
|
|
|
697
|
-
# Analyze body in a new scope
|
|
714
|
+
# Analyze body in a new scope — body return type is inner (not Promise<T>)
|
|
698
715
|
self._push_scope("fn")
|
|
699
716
|
prev_ret = self._current_fn_return_type
|
|
700
|
-
self._current_fn_return_type =
|
|
717
|
+
self._current_fn_return_type = inner_ret_type
|
|
701
718
|
|
|
702
719
|
# Register parameters — mark used=True so we never warn about unused params
|
|
703
720
|
for param in node.params:
|
|
@@ -714,7 +731,7 @@ class Analyzer(Visitor):
|
|
|
714
731
|
|
|
715
732
|
self._current_fn_return_type = prev_ret
|
|
716
733
|
self._pop_scope()
|
|
717
|
-
return
|
|
734
|
+
return external_ret_type
|
|
718
735
|
|
|
719
736
|
def _body_always_returns(self, block) -> bool:
|
|
720
737
|
"""Return True if every code path through block ends with a return/throw."""
|
|
@@ -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.7"
|
|
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"
|
|
@@ -276,7 +276,8 @@ def _compat_files(path: str) -> int:
|
|
|
276
276
|
print(f"[InScript compat] Cannot read '{fpath}': {e}", file=sys.stderr)
|
|
277
277
|
return issues
|
|
278
278
|
for lineno, line in enumerate(src.splitlines(), 1):
|
|
279
|
-
|
|
279
|
+
stripped = line.lstrip()
|
|
280
|
+
if stripped.startswith("//") or stripped.startswith("#"):
|
|
280
281
|
continue
|
|
281
282
|
for pat, msg in CHECKS:
|
|
282
283
|
if pat.search(line):
|
|
@@ -333,9 +334,20 @@ def _migrate_files(path: str) -> int:
|
|
|
333
334
|
with open(fpath, encoding="utf-8") as f:
|
|
334
335
|
original = f.read()
|
|
335
336
|
src = original
|
|
337
|
+
# v1.9.6: // line comments → # line comments (MUST run before div→// rewrite)
|
|
338
|
+
# Rule 1: standalone comment lines — optional whitespace then //
|
|
339
|
+
src = re.sub(r'^(\s*)//', r'\1#', src, flags=re.MULTILINE)
|
|
340
|
+
# Rule 2: inline word comment — ` // word` → ` # word`
|
|
341
|
+
# Fires only when identifier/word follows, not digit (digits are floor-div)
|
|
342
|
+
src = re.sub(r'(\s)//(\s+[A-Za-z_])', r'\1#\2', src)
|
|
343
|
+
# Rule 3: warn about ambiguous ` // <digit>` patterns (may be comment or floor-div)
|
|
344
|
+
ambiguous = re.findall(r'(\s)//(\s+\d)', src)
|
|
345
|
+
if ambiguous:
|
|
346
|
+
print(f" WARNING {fpath}: {len(ambiguous)} ambiguous ' // <digit>' pattern(s) — "
|
|
347
|
+
f"check manually: floor-div or comment? Change to '#' if comment.")
|
|
336
348
|
# null → nil
|
|
337
349
|
src = re.sub(r'\bnull\b', 'nil', src)
|
|
338
|
-
# x div y → x // y (only bare `div` between expressions)
|
|
350
|
+
# x div y → x // y (only bare `div` between expressions, safe after comment rules)
|
|
339
351
|
src = re.sub(r'\bdiv\b', '//', src)
|
|
340
352
|
# bare [] type annotation → array (e.g. `: []` → `: array`)
|
|
341
353
|
src = re.sub(r':\s*\[\]', ': array', src)
|
|
@@ -1154,7 +1166,7 @@ LANGUAGE_SPEC = """# InScript Language Specification
|
|
|
1154
1166
|
## 1. Lexical Structure
|
|
1155
1167
|
|
|
1156
1168
|
### 1.1 Comments
|
|
1157
|
-
- Line comments: `// text`
|
|
1169
|
+
- Line comments: `# text` (v1.9.6: was `// text`)
|
|
1158
1170
|
- Block comments: `/* text */` (nestable)
|
|
1159
1171
|
- Doc comments: `/// text` (parsed by `inscript doc`)
|
|
1160
1172
|
|
|
@@ -5,14 +5,15 @@
|
|
|
5
5
|
# After Lexer → Parser → Analyzer pass, this is what runs InScript programs.
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
|
-
import math, random, time
|
|
8
|
+
import math, random, time, asyncio
|
|
9
9
|
from typing import Any, Dict, List, Optional
|
|
10
10
|
|
|
11
11
|
from ast_nodes import *
|
|
12
12
|
from environment import Environment
|
|
13
13
|
from stdlib_values import (
|
|
14
14
|
Vec2, Vec3, Color, Rect,
|
|
15
|
-
InScriptFunction, InScriptInstance, InScriptRange, InScriptGenerator
|
|
15
|
+
InScriptFunction, InScriptInstance, InScriptRange, InScriptGenerator,
|
|
16
|
+
InScriptCoroutine,
|
|
16
17
|
)
|
|
17
18
|
import stdlib as _stdlib # loads all built-in modules
|
|
18
19
|
from errors import (
|
|
@@ -526,6 +527,8 @@ class Interpreter(Visitor):
|
|
|
526
527
|
# v1.4.0: preserve generic metadata for constraint checking at call time
|
|
527
528
|
fn.type_params = getattr(node, 'type_params', [])
|
|
528
529
|
fn.constraints = getattr(node, 'constraints', {})
|
|
530
|
+
# v1.9.7: mark async functions
|
|
531
|
+
fn.is_async = getattr(node, 'is_async', False)
|
|
529
532
|
self._env.define(node.name, fn)
|
|
530
533
|
return fn
|
|
531
534
|
|
|
@@ -2319,6 +2322,33 @@ class Interpreter(Visitor):
|
|
|
2319
2322
|
|
|
2320
2323
|
_bind_args(call_env, arg_vals, arg_names)
|
|
2321
2324
|
|
|
2325
|
+
# v1.9.7: async fn — wrap body execution in a Python coroutine
|
|
2326
|
+
if getattr(fn, 'is_async', False):
|
|
2327
|
+
async def _async_body():
|
|
2328
|
+
nonlocal result
|
|
2329
|
+
prev_fn2 = self._current_fn
|
|
2330
|
+
prev_def2 = getattr(self, '_deferred', None)
|
|
2331
|
+
self._deferred = []
|
|
2332
|
+
self._current_fn = fn
|
|
2333
|
+
try:
|
|
2334
|
+
for stmt in fn.body.body:
|
|
2335
|
+
self.visit(stmt)
|
|
2336
|
+
except ReturnSignal as r:
|
|
2337
|
+
result = r.value
|
|
2338
|
+
except PropagateSignal as sig:
|
|
2339
|
+
result = sig.err_val
|
|
2340
|
+
finally:
|
|
2341
|
+
for deferred_expr in reversed(self._deferred):
|
|
2342
|
+
try: self.visit(deferred_expr)
|
|
2343
|
+
except Exception: pass
|
|
2344
|
+
self._deferred = prev_def2 if prev_def2 is not None else []
|
|
2345
|
+
self._current_fn = prev_fn2
|
|
2346
|
+
self._env = prev_env
|
|
2347
|
+
self._call_depth -= 1
|
|
2348
|
+
self._call_stack.pop()
|
|
2349
|
+
return result
|
|
2350
|
+
return InScriptCoroutine(_async_body(), fn_name=fn.name or "<async>")
|
|
2351
|
+
|
|
2322
2352
|
# v1.3.0: TCO trampoline — self-recursive tail calls loop instead of recurse
|
|
2323
2353
|
result = None
|
|
2324
2354
|
prev_fn = self._current_fn
|
|
@@ -2443,7 +2473,24 @@ class Interpreter(Visitor):
|
|
|
2443
2473
|
return InScriptRange(start, end, inclusive=node.inclusive)
|
|
2444
2474
|
|
|
2445
2475
|
def visit_AwaitExpr(self, node: AwaitExpr) -> Any:
|
|
2446
|
-
|
|
2476
|
+
"""
|
|
2477
|
+
v1.9.7: True async/await.
|
|
2478
|
+
- InScriptCoroutine → drive via Python coroutine protocol (sync driver).
|
|
2479
|
+
- Plain value → passthrough (backwards compatible).
|
|
2480
|
+
|
|
2481
|
+
We use a synchronous driver (coro.send(None)) rather than asyncio.run()
|
|
2482
|
+
because InScript coroutine bodies contain no real Python await points —
|
|
2483
|
+
they are synchronous interpreter execution wrapped in `async def`.
|
|
2484
|
+
This also safely handles nested async calls without event-loop conflicts.
|
|
2485
|
+
"""
|
|
2486
|
+
val = self.visit(node.expr)
|
|
2487
|
+
if isinstance(val, InScriptCoroutine):
|
|
2488
|
+
try:
|
|
2489
|
+
val.coro.send(None)
|
|
2490
|
+
return None # coroutine yielded unexpectedly — shouldn't happen
|
|
2491
|
+
except StopIteration as e:
|
|
2492
|
+
return e.value
|
|
2493
|
+
return val # plain value: passthrough
|
|
2447
2494
|
|
|
2448
2495
|
def visit_SpawnExpr(self, node: SpawnExpr) -> Any:
|
|
2449
2496
|
return None # Phase 6 (ECS)
|
|
@@ -292,26 +292,12 @@ class Lexer:
|
|
|
292
292
|
if ch in (" ", "\t", "\r", "\n"):
|
|
293
293
|
return
|
|
294
294
|
|
|
295
|
-
# // — floor-division operator
|
|
296
|
-
# v1.
|
|
297
|
-
#
|
|
298
|
-
# Floor division: `10 // 3`, `x//2`, `(a+b) // c`
|
|
299
|
-
# Rule: if the character BEFORE // was a digit, ), ], or identifier char → floor div
|
|
300
|
-
# otherwise → line comment
|
|
295
|
+
# // — floor-division operator (v1.9.6: ALWAYS floor division, no exceptions)
|
|
296
|
+
# v1.9.6: `#` is the new line-comment character.
|
|
297
|
+
# `//` with or without spaces is always integer floor division: 10 // 3 → 3
|
|
301
298
|
if ch == "/" and self.current == "/":
|
|
302
299
|
self.advance() # consume second /
|
|
303
|
-
|
|
304
|
-
# Rule: the character IMMEDIATELY before first '/' (no whitespace allowed)
|
|
305
|
-
# must be digit/identifier/closing bracket to be floor-div.
|
|
306
|
-
# Any space/tab before the // → line comment.
|
|
307
|
-
first_slash_pos = self.pos - 2
|
|
308
|
-
prev = self.source[first_slash_pos - 1] if first_slash_pos > 0 else ''
|
|
309
|
-
if prev and (prev.isdigit() or prev.isalpha() or prev in ')]}'):
|
|
310
|
-
# `10//3`, `x//2`, `(a+b)//c` — no space → floor division
|
|
311
|
-
self._emit(TT.SLASH_SLASH, "//", sl, sc)
|
|
312
|
-
else:
|
|
313
|
-
# `10 // 3` with spaces, `5 // comment`, `// standalone` → comment
|
|
314
|
-
self._skip_line_comment()
|
|
300
|
+
self._emit(TT.SLASH_SLASH, "//", sl, sc)
|
|
315
301
|
return
|
|
316
302
|
if ch == "/" and self.current == "*":
|
|
317
303
|
self._skip_block_comment(sl, sc); return
|
|
@@ -586,7 +572,9 @@ class Lexer:
|
|
|
586
572
|
if self.match("?"): emit(TT.NULLISH, "??")
|
|
587
573
|
elif self.match("."): emit(TT.QUESTION_DOT, "?.")
|
|
588
574
|
else: emit(TT.QUESTION, "?")
|
|
589
|
-
elif ch == "#":
|
|
575
|
+
elif ch == "#":
|
|
576
|
+
# v1.9.6: # is the line-comment character (was: HASH annotation token)
|
|
577
|
+
self._skip_line_comment(); return
|
|
590
578
|
elif ch == "@": emit(TT.AT, "@")
|
|
591
579
|
elif ch == "(": emit(TT.LPAREN)
|
|
592
580
|
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 = "1.9.
|
|
7
|
+
version = "1.9.7"
|
|
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.7"
|
|
44
44
|
|
|
45
45
|
# ── ANSI colours ──────────────────────────────────────────────────────────────
|
|
46
46
|
def _c(code, text):
|
|
@@ -220,7 +220,7 @@ class Rect:
|
|
|
220
220
|
|
|
221
221
|
class InScriptFunction:
|
|
222
222
|
"""A user-defined function or lambda at runtime."""
|
|
223
|
-
def __init__(self, name, params, body, closure, is_native=False, native_fn=None, return_type=None):
|
|
223
|
+
def __init__(self, name, params, body, closure, is_native=False, native_fn=None, return_type=None, is_async=False):
|
|
224
224
|
self.name = name
|
|
225
225
|
self.params = params # List[Param] AST nodes
|
|
226
226
|
self.body = body # BlockStmt AST node
|
|
@@ -228,6 +228,7 @@ class InScriptFunction:
|
|
|
228
228
|
self.is_native = is_native
|
|
229
229
|
self.native_fn = native_fn # Python callable for native fns
|
|
230
230
|
self.return_type = return_type # Optional type annotation
|
|
231
|
+
self.is_async = is_async # v1.9.7: true for `async fn`
|
|
231
232
|
self._interp = None # Set by interpreter so stdlib can call us
|
|
232
233
|
|
|
233
234
|
def __repr__(self): return f"<fn {self.name}>"
|
|
@@ -239,6 +240,21 @@ class InScriptFunction:
|
|
|
239
240
|
raise TypeError(f"InScriptFunction '{self.name}' cannot be called without an interpreter context")
|
|
240
241
|
|
|
241
242
|
|
|
243
|
+
class InScriptCoroutine:
|
|
244
|
+
"""
|
|
245
|
+
v1.9.7: Wraps the result of calling an `async fn`.
|
|
246
|
+
Holds a Python coroutine that runs the function body.
|
|
247
|
+
Driven to completion by `await` via asyncio.
|
|
248
|
+
"""
|
|
249
|
+
def __init__(self, coro, fn_name: str = "<async>"):
|
|
250
|
+
self.coro = coro # Python coroutine object
|
|
251
|
+
self.fn_name = fn_name # for repr / error messages
|
|
252
|
+
|
|
253
|
+
def __repr__(self):
|
|
254
|
+
return f"<coroutine {self.fn_name}>"
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
|
|
242
258
|
class InScriptInstance:
|
|
243
259
|
"""An instance of a user-defined struct at runtime."""
|
|
244
260
|
def __init__(self, struct_name: str, fields: Dict[str, Any]):
|
|
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
|