godcode-engine 4.0.0__py3-none-any.whl
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.
- godcode/__init__.py +86 -0
- godcode/__main__.py +7 -0
- godcode/agentics.py +235 -0
- godcode/ast.py +227 -0
- godcode/chain.py +210 -0
- godcode/cli.py +698 -0
- godcode/environment.py +74 -0
- godcode/errors.py +69 -0
- godcode/interpreter.py +1104 -0
- godcode/ledger.py +88 -0
- godcode/lexer.py +218 -0
- godcode/lsp.py +677 -0
- godcode/parser.py +525 -0
- godcode/plugins.py +255 -0
- godcode/registry.py +515 -0
- godcode/sandbox.py +385 -0
- godcode/scrolls/covenant.god +10 -0
- godcode/scrolls/covenant.toml +6 -0
- godcode/scrolls/lists.god +53 -0
- godcode/scrolls/lists.toml +6 -0
- godcode/scrolls/math.god +64 -0
- godcode/scrolls/math.toml +6 -0
- godcode/scrolls/prophecy.god +14 -0
- godcode/scrolls/prophecy.toml +6 -0
- godcode/scrolls/strings.god +32 -0
- godcode/scrolls/strings.toml +6 -0
- godcode/scrolls/time.god +10 -0
- godcode/scrolls/time.toml +6 -0
- godcode/spirit.py +180 -0
- godcode/tokens.py +91 -0
- godcode/tools.py +378 -0
- godcode/values.py +56 -0
- godcode_engine-4.0.0.dist-info/METADATA +212 -0
- godcode_engine-4.0.0.dist-info/RECORD +38 -0
- godcode_engine-4.0.0.dist-info/WHEEL +5 -0
- godcode_engine-4.0.0.dist-info/entry_points.txt +2 -0
- godcode_engine-4.0.0.dist-info/licenses/LICENSE +201 -0
- godcode_engine-4.0.0.dist-info/top_level.txt +1 -0
godcode/__init__.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""God Code v3.0 — the language of divine computation."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
__version__ = "4.0.0"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class RunResult:
|
|
14
|
+
"""The outcome of running God Code from a host program.
|
|
15
|
+
|
|
16
|
+
``output`` is the captured REVEAL output (lines joined with ``\\n``);
|
|
17
|
+
``return_value`` is the value of a top-level ``RETURN`` (if the scroll
|
|
18
|
+
ascends that way) or of the last expression statement evaluated, else
|
|
19
|
+
``None``; ``error`` is the divine error message (with line number) when
|
|
20
|
+
the run failed; ``ok`` tells whether the run completed.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
output: str = ""
|
|
24
|
+
return_value: Any = None
|
|
25
|
+
error: str | None = None
|
|
26
|
+
ok: bool = False
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def run_source(source: str, *, filename: str = "<string>") -> RunResult:
|
|
30
|
+
"""Run God Code source from a host program and capture the outcome.
|
|
31
|
+
|
|
32
|
+
REVEAL output is captured per-interpreter (via the interpreter's ``emit``
|
|
33
|
+
hook), so this is safe to call many times in one process. Plugin
|
|
34
|
+
auto-loading still applies unless ``GODCODE_NO_PLUGINS=1`` is set.
|
|
35
|
+
Embedding runs do not write the audit log.
|
|
36
|
+
"""
|
|
37
|
+
from godcode.errors import GodCodeError, ReturnSignal
|
|
38
|
+
from godcode.interpreter import Interpreter
|
|
39
|
+
|
|
40
|
+
lines: list[str] = []
|
|
41
|
+
interpreter = Interpreter(log_path=None)
|
|
42
|
+
interpreter.emit = lines.append
|
|
43
|
+
try:
|
|
44
|
+
interpreter.run_source(source, source_name=filename)
|
|
45
|
+
except ReturnSignal as ret:
|
|
46
|
+
# A top-level RETURN becomes the run's return value.
|
|
47
|
+
return RunResult(
|
|
48
|
+
output="\n".join(lines), return_value=ret.value, error=None, ok=True
|
|
49
|
+
)
|
|
50
|
+
except GodCodeError as err:
|
|
51
|
+
return RunResult(
|
|
52
|
+
output="\n".join(lines),
|
|
53
|
+
return_value=None,
|
|
54
|
+
error=str(err),
|
|
55
|
+
ok=False,
|
|
56
|
+
)
|
|
57
|
+
except Exception as exc: # a host/plugin failure outside the divine errors
|
|
58
|
+
return RunResult(
|
|
59
|
+
output="\n".join(lines),
|
|
60
|
+
return_value=None,
|
|
61
|
+
error=f"the outer world faltered: {exc!r}",
|
|
62
|
+
ok=False,
|
|
63
|
+
)
|
|
64
|
+
return RunResult(
|
|
65
|
+
output="\n".join(lines),
|
|
66
|
+
return_value=interpreter.last_value,
|
|
67
|
+
error=None,
|
|
68
|
+
ok=True,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def run_file(path: str | Path) -> RunResult:
|
|
73
|
+
"""Run a God Code scroll file from a host program; see :func:`run_source`."""
|
|
74
|
+
try:
|
|
75
|
+
source = Path(path).read_text(encoding="utf-8")
|
|
76
|
+
except OSError as exc:
|
|
77
|
+
return RunResult(
|
|
78
|
+
output="",
|
|
79
|
+
return_value=None,
|
|
80
|
+
error=f"cannot read '{path}': {exc.strerror or exc}",
|
|
81
|
+
ok=False,
|
|
82
|
+
)
|
|
83
|
+
return run_source(source, filename=str(path))
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
__all__ = ["__version__", "RunResult", "run_source", "run_file"]
|
godcode/__main__.py
ADDED
godcode/agentics.py
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"""Machine-readable output for AI agents (Mini-Pillar 5 — Agentics).
|
|
2
|
+
|
|
3
|
+
This module turns God Code diagnostics and run results into stable JSON
|
|
4
|
+
payloads an agent can parse without scraping divine prose. The CLI wires
|
|
5
|
+
it in behind ``--json`` on the ``run`` and ``check`` commands.
|
|
6
|
+
|
|
7
|
+
Error-code mapping choice
|
|
8
|
+
-------------------------
|
|
9
|
+
Codes are a small, stable, language-agnostic vocabulary derived from the
|
|
10
|
+
v2.0 exception hierarchy in :mod:`godcode.errors` (there is no
|
|
11
|
+
``GodCodeSyntaxError`` class in v2.0, so the mapping below is explicit):
|
|
12
|
+
|
|
13
|
+
LexerError -> LEXER_ERROR
|
|
14
|
+
ParseError -> PARSE_ERROR
|
|
15
|
+
GodRuntimeError -> RUNTIME_ERROR
|
|
16
|
+
|
|
17
|
+
Any other ``GodCodeError`` subclass falls back to a mechanical
|
|
18
|
+
CamelCase -> UPPER_SNAKE conversion of its class name
|
|
19
|
+
(e.g. ``FooBarError`` -> ``FOO_BAR_ERROR``). Failures that are not God
|
|
20
|
+
Code failures at all (an unreadable scroll file) use ``FILE_ERROR``,
|
|
21
|
+
which is not an exception class.
|
|
22
|
+
|
|
23
|
+
Capture choice
|
|
24
|
+
--------------
|
|
25
|
+
``run`` output is captured with :func:`contextlib.redirect_stdout` into
|
|
26
|
+
a :class:`io.StringIO` around the interpreter call — no dependency on
|
|
27
|
+
any capture hooks from sibling pillars.
|
|
28
|
+
|
|
29
|
+
Seals
|
|
30
|
+
-----
|
|
31
|
+
After the run we diff the interpreter's bound ``ledger`` (when present)
|
|
32
|
+
against its block count before the run. Blocks sealed during the run are
|
|
33
|
+
reported as ``{"block": <index>, "hash": <sha>}``. When no ledger is
|
|
34
|
+
bound or it cannot be read, ``seals`` is ``[]`` — never an error.
|
|
35
|
+
"""
|
|
36
|
+
from __future__ import annotations
|
|
37
|
+
|
|
38
|
+
import contextlib
|
|
39
|
+
import io
|
|
40
|
+
import json
|
|
41
|
+
import re
|
|
42
|
+
import sys
|
|
43
|
+
import time
|
|
44
|
+
from pathlib import Path
|
|
45
|
+
|
|
46
|
+
TOOL_NAME = "godcode"
|
|
47
|
+
|
|
48
|
+
# ---------------------------------------------------------------------------
|
|
49
|
+
# error codes
|
|
50
|
+
# ---------------------------------------------------------------------------
|
|
51
|
+
_CODE_MAP = {
|
|
52
|
+
"LexerError": "LEXER_ERROR",
|
|
53
|
+
"ParseError": "PARSE_ERROR",
|
|
54
|
+
"GodRuntimeError": "RUNTIME_ERROR",
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
_HINTS = {
|
|
58
|
+
"LEXER_ERROR": (
|
|
59
|
+
"Scan the reported line for stray symbols or an unterminated "
|
|
60
|
+
"string; God Code strings use double quotes."
|
|
61
|
+
),
|
|
62
|
+
"PARSE_ERROR": (
|
|
63
|
+
"Every scroll needs BEGIN CREATION ... END CREATION; comparisons "
|
|
64
|
+
"use IS / IS NOT, and every block needs its closer "
|
|
65
|
+
"(ENDIF, ENDFOR, ENDWHILE, END RITE)."
|
|
66
|
+
),
|
|
67
|
+
"RUNTIME_ERROR": (
|
|
68
|
+
"The scroll parsed but stumbled while running — DECLARE every "
|
|
69
|
+
"name before use and re-read the reported line."
|
|
70
|
+
),
|
|
71
|
+
"FILE_ERROR": "Check the path — the scroll must exist and be readable.",
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _to_snake(name: str) -> str:
|
|
76
|
+
return re.sub(r"(?<!^)(?=[A-Z])", "_", name).upper()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def error_code(err) -> str:
|
|
80
|
+
"""Map a God Code exception to its stable machine code."""
|
|
81
|
+
name = type(err).__name__
|
|
82
|
+
if name in _CODE_MAP:
|
|
83
|
+
return _CODE_MAP[name]
|
|
84
|
+
snake = _to_snake(name)
|
|
85
|
+
return snake if snake.endswith("_ERROR") else snake + "_ERROR"
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def hint_for(code: str) -> str | None:
|
|
89
|
+
"""One-line actionable suggestion for a code, or None."""
|
|
90
|
+
return _HINTS.get(code)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def diagnostic(err, *, severity: str = "error") -> dict:
|
|
94
|
+
"""Turn a GodCodeError into a JSON-serializable diagnostic dict."""
|
|
95
|
+
code = error_code(err)
|
|
96
|
+
# err.msg is the clean message; str(err) may append "(line N)" which
|
|
97
|
+
# would duplicate the structured line/col fields below.
|
|
98
|
+
return {
|
|
99
|
+
"line": getattr(err, "line", None),
|
|
100
|
+
"col": getattr(err, "col", None),
|
|
101
|
+
"code": code,
|
|
102
|
+
"severity": severity,
|
|
103
|
+
"message": getattr(err, "msg", None) or str(err),
|
|
104
|
+
"hint": hint_for(code),
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _file_error_diagnostic(path: str, exc: OSError) -> dict:
|
|
109
|
+
detail = exc.strerror or str(exc)
|
|
110
|
+
return {
|
|
111
|
+
"line": None,
|
|
112
|
+
"col": None,
|
|
113
|
+
"code": "FILE_ERROR",
|
|
114
|
+
"severity": "error",
|
|
115
|
+
"message": f"godcode: cannot read '{path}': {detail}",
|
|
116
|
+
"hint": hint_for("FILE_ERROR"),
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# ---------------------------------------------------------------------------
|
|
121
|
+
# payload builders
|
|
122
|
+
# ---------------------------------------------------------------------------
|
|
123
|
+
def check_payload(file: str, ok: bool, diagnostics: list[dict]) -> dict:
|
|
124
|
+
return {
|
|
125
|
+
"tool": TOOL_NAME,
|
|
126
|
+
"command": "check",
|
|
127
|
+
"file": file,
|
|
128
|
+
"ok": ok,
|
|
129
|
+
"diagnostics": diagnostics,
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def run_payload(file: str, ok: bool, output: list[str],
|
|
134
|
+
seals: list[dict], error: dict | None, ms: int,
|
|
135
|
+
intents: list[dict] | None = None) -> dict:
|
|
136
|
+
return {
|
|
137
|
+
"tool": TOOL_NAME,
|
|
138
|
+
"command": "run",
|
|
139
|
+
"file": file,
|
|
140
|
+
"ok": ok,
|
|
141
|
+
"output": output,
|
|
142
|
+
"seals": seals,
|
|
143
|
+
"intents": intents if intents is not None else [],
|
|
144
|
+
"error": error,
|
|
145
|
+
"stats": {"ms": ms},
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def emit(payload: dict) -> None:
|
|
150
|
+
"""Write one JSON document to stdout; nothing else may be printed."""
|
|
151
|
+
sys.stdout.write(json.dumps(payload, ensure_ascii=False) + "\n")
|
|
152
|
+
sys.stdout.flush()
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# ---------------------------------------------------------------------------
|
|
156
|
+
# --json command implementations (called from godcode.cli)
|
|
157
|
+
# ---------------------------------------------------------------------------
|
|
158
|
+
def cmd_check_json(args) -> int:
|
|
159
|
+
"""`godcode check --json FILE`. Exit 0 if pure, 1 if diagnostics."""
|
|
160
|
+
from godcode.errors import GodCodeError
|
|
161
|
+
from godcode.lexer import Lexer
|
|
162
|
+
from godcode.parser import Parser
|
|
163
|
+
|
|
164
|
+
try:
|
|
165
|
+
source = Path(args.file).read_text(encoding="utf-8")
|
|
166
|
+
except OSError as exc:
|
|
167
|
+
emit(check_payload(args.file, False, [_file_error_diagnostic(args.file, exc)]))
|
|
168
|
+
return 1
|
|
169
|
+
try:
|
|
170
|
+
Parser(Lexer(source).lex()).parse()
|
|
171
|
+
except GodCodeError as err:
|
|
172
|
+
emit(check_payload(args.file, False, [diagnostic(err)]))
|
|
173
|
+
return 1
|
|
174
|
+
emit(check_payload(args.file, True, []))
|
|
175
|
+
return 0
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _ledger_block_count(interp) -> int | None:
|
|
179
|
+
ledger = getattr(interp, "ledger", None)
|
|
180
|
+
if ledger is None:
|
|
181
|
+
return None
|
|
182
|
+
try:
|
|
183
|
+
return len(ledger.read_all())
|
|
184
|
+
except Exception:
|
|
185
|
+
return None
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _new_seals(interp, before: int | None) -> list[dict]:
|
|
189
|
+
"""Best-effort list of covenant blocks sealed during the run."""
|
|
190
|
+
if before is None:
|
|
191
|
+
return []
|
|
192
|
+
ledger = getattr(interp, "ledger", None)
|
|
193
|
+
if ledger is None:
|
|
194
|
+
return []
|
|
195
|
+
try:
|
|
196
|
+
blocks = ledger.read_all()[before:]
|
|
197
|
+
except Exception:
|
|
198
|
+
return []
|
|
199
|
+
seals = []
|
|
200
|
+
for block in blocks:
|
|
201
|
+
if isinstance(block, dict) and "hash" in block:
|
|
202
|
+
seals.append({"block": block.get("index"), "hash": block.get("hash")})
|
|
203
|
+
return seals
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def cmd_run_json(args) -> int:
|
|
207
|
+
"""`godcode run --json FILE`. Exit 0 on success, 1 on failure."""
|
|
208
|
+
from godcode.errors import GodCodeError
|
|
209
|
+
from godcode.cli import _make_interpreter # shared with the plain run path
|
|
210
|
+
|
|
211
|
+
try:
|
|
212
|
+
source = Path(args.file).read_text(encoding="utf-8")
|
|
213
|
+
except OSError as exc:
|
|
214
|
+
emit(run_payload(args.file, False, [], [], _file_error_diagnostic(args.file, exc), 0))
|
|
215
|
+
return 1
|
|
216
|
+
|
|
217
|
+
interp = _make_interpreter(args.log)
|
|
218
|
+
seals_before = _ledger_block_count(interp)
|
|
219
|
+
|
|
220
|
+
buf = io.StringIO()
|
|
221
|
+
error: dict | None = None
|
|
222
|
+
start = time.perf_counter()
|
|
223
|
+
with contextlib.redirect_stdout(buf):
|
|
224
|
+
try:
|
|
225
|
+
interp.run_source(source, source_name=args.file)
|
|
226
|
+
except GodCodeError as err:
|
|
227
|
+
error = diagnostic(err)
|
|
228
|
+
ms = int((time.perf_counter() - start) * 1000)
|
|
229
|
+
|
|
230
|
+
output = buf.getvalue().splitlines()
|
|
231
|
+
seals = _new_seals(interp, seals_before)
|
|
232
|
+
intents = list(getattr(interp, "intent_checks", []) or [])
|
|
233
|
+
emit(run_payload(args.file, error is None, output, seals, error, ms,
|
|
234
|
+
intents=intents))
|
|
235
|
+
return 0 if error is None else 1
|
godcode/ast.py
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"""Abstract syntax tree nodes for God Code v2.0.
|
|
2
|
+
|
|
3
|
+
Every node carries 1-based ``line``/``col`` of the token that opened it.
|
|
4
|
+
Expression fields are annotated with the ``Expr`` alias (a union of all
|
|
5
|
+
expression node types).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import Union
|
|
12
|
+
|
|
13
|
+
# Filled in below once the classes exist; string form keeps runtime cheap.
|
|
14
|
+
Expr = Union[
|
|
15
|
+
"BinaryOp", "UnaryOp", "Literal", "Identifier",
|
|
16
|
+
"ListLiteral", "Index", "CallExpr",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# -- program structure -------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class Program:
|
|
24
|
+
statements: list = field(default_factory=list)
|
|
25
|
+
line: int = 1
|
|
26
|
+
col: int = 1
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class CreationBlock:
|
|
31
|
+
statements: list = field(default_factory=list)
|
|
32
|
+
line: int = 1
|
|
33
|
+
col: int = 1
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# -- statements --------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class Declare:
|
|
40
|
+
name: str
|
|
41
|
+
value: Expr
|
|
42
|
+
line: int = 1
|
|
43
|
+
col: int = 1
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class DeclareIntent:
|
|
48
|
+
"""DECLARE INTENT "words..." ON rite_name -- the v4.0 intent layer."""
|
|
49
|
+
text: str
|
|
50
|
+
rite: str
|
|
51
|
+
line: int = 1
|
|
52
|
+
col: int = 1
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class Breathe:
|
|
57
|
+
name: str
|
|
58
|
+
line: int = 1
|
|
59
|
+
col: int = 1
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass
|
|
63
|
+
class Reveal:
|
|
64
|
+
expr: Expr
|
|
65
|
+
line: int = 1
|
|
66
|
+
col: int = 1
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass
|
|
70
|
+
class Prophesy:
|
|
71
|
+
text: str
|
|
72
|
+
line: int = 1
|
|
73
|
+
col: int = 1
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@dataclass
|
|
77
|
+
class Ascend:
|
|
78
|
+
line: int = 1
|
|
79
|
+
col: int = 1
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@dataclass
|
|
83
|
+
class Reflect:
|
|
84
|
+
line: int = 1
|
|
85
|
+
col: int = 1
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@dataclass
|
|
89
|
+
class Bless:
|
|
90
|
+
name: str
|
|
91
|
+
line: int = 1
|
|
92
|
+
col: int = 1
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@dataclass
|
|
96
|
+
class Anoint:
|
|
97
|
+
name: str
|
|
98
|
+
line: int = 1
|
|
99
|
+
col: int = 1
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@dataclass
|
|
103
|
+
class SealStmt:
|
|
104
|
+
expr: Expr
|
|
105
|
+
line: int = 1
|
|
106
|
+
col: int = 1
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@dataclass
|
|
110
|
+
class Testify:
|
|
111
|
+
expr: Expr
|
|
112
|
+
line: int = 1
|
|
113
|
+
col: int = 1
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@dataclass
|
|
117
|
+
class IfStmt:
|
|
118
|
+
cond: Expr
|
|
119
|
+
then_body: list = field(default_factory=list)
|
|
120
|
+
else_body: list = field(default_factory=list)
|
|
121
|
+
line: int = 1
|
|
122
|
+
col: int = 1
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@dataclass
|
|
126
|
+
class ForLoop:
|
|
127
|
+
var: str
|
|
128
|
+
iterable: Expr
|
|
129
|
+
body: list = field(default_factory=list)
|
|
130
|
+
line: int = 1
|
|
131
|
+
col: int = 1
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@dataclass
|
|
135
|
+
class WhileLoop:
|
|
136
|
+
cond: Expr
|
|
137
|
+
body: list = field(default_factory=list)
|
|
138
|
+
line: int = 1
|
|
139
|
+
col: int = 1
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@dataclass
|
|
143
|
+
class DefineRite:
|
|
144
|
+
name: str
|
|
145
|
+
params: list = field(default_factory=list) # list[str]
|
|
146
|
+
body: list = field(default_factory=list)
|
|
147
|
+
line: int = 1
|
|
148
|
+
col: int = 1
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@dataclass
|
|
152
|
+
class Return:
|
|
153
|
+
expr: Expr | None = None
|
|
154
|
+
line: int = 1
|
|
155
|
+
col: int = 1
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@dataclass
|
|
159
|
+
class Import:
|
|
160
|
+
path: str
|
|
161
|
+
line: int = 1
|
|
162
|
+
col: int = 1
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@dataclass
|
|
166
|
+
class ExprStmt:
|
|
167
|
+
expr: Expr
|
|
168
|
+
line: int = 1
|
|
169
|
+
col: int = 1
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
# -- expressions -------------------------------------------------------------
|
|
173
|
+
|
|
174
|
+
@dataclass
|
|
175
|
+
class BinaryOp:
|
|
176
|
+
# op: '+','-','*','/','%', '==','!=','<','>','<=','>=', 'and','or'
|
|
177
|
+
op: str
|
|
178
|
+
left: Expr
|
|
179
|
+
right: Expr
|
|
180
|
+
line: int = 1
|
|
181
|
+
col: int = 1
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
@dataclass
|
|
185
|
+
class UnaryOp:
|
|
186
|
+
# op: 'not', '-'
|
|
187
|
+
op: str
|
|
188
|
+
operand: Expr
|
|
189
|
+
line: int = 1
|
|
190
|
+
col: int = 1
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
@dataclass
|
|
194
|
+
class Literal:
|
|
195
|
+
value: object # int | float | str | bool | None
|
|
196
|
+
line: int = 1
|
|
197
|
+
col: int = 1
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@dataclass
|
|
201
|
+
class Identifier:
|
|
202
|
+
name: str
|
|
203
|
+
line: int = 1
|
|
204
|
+
col: int = 1
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@dataclass
|
|
208
|
+
class ListLiteral:
|
|
209
|
+
items: list = field(default_factory=list) # list[Expr]
|
|
210
|
+
line: int = 1
|
|
211
|
+
col: int = 1
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@dataclass
|
|
215
|
+
class Index:
|
|
216
|
+
obj: Expr
|
|
217
|
+
index: Expr
|
|
218
|
+
line: int = 1
|
|
219
|
+
col: int = 1
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@dataclass
|
|
223
|
+
class CallExpr:
|
|
224
|
+
callee: str
|
|
225
|
+
args: list = field(default_factory=list) # list[Expr]
|
|
226
|
+
line: int = 1
|
|
227
|
+
col: int = 1
|