beancode 0.1.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.
- beancode/__init__.py +106 -0
- beancode/__main__.py +60 -0
- beancode/bean_ast.py +488 -0
- beancode/bean_ffi.py +68 -0
- beancode/interpreter.py +1768 -0
- beancode/lexer.py +535 -0
- beancode/modules/__init__.py +0 -0
- beancode/modules/beanray.py +196 -0
- beancode/modules/demo_ffimod.py +34 -0
- beancode/parser.py +1363 -0
- beancode-0.1.0.dist-info/LICENSE.md +357 -0
- beancode-0.1.0.dist-info/METADATA +143 -0
- beancode-0.1.0.dist-info/RECORD +15 -0
- beancode-0.1.0.dist-info/WHEEL +4 -0
- beancode-0.1.0.dist-info/entry_points.txt +3 -0
beancode/__init__.py
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
class BCError(Exception):
|
|
2
|
+
# row, col, bol
|
|
3
|
+
pos: tuple[int, int, int]
|
|
4
|
+
|
|
5
|
+
def __init__(self, msg: str, ctx=None) -> None: # type: ignore
|
|
6
|
+
self.len = 1
|
|
7
|
+
if type(ctx).__name__ == "Token":
|
|
8
|
+
self.pos = ctx.pos # type: ignore
|
|
9
|
+
self.len = len(ctx.get_raw()[0]) # type: ignore
|
|
10
|
+
elif type(ctx) == tuple:
|
|
11
|
+
self.pos = ctx
|
|
12
|
+
else:
|
|
13
|
+
self.pos = (0, 0, 0) # type: ignore
|
|
14
|
+
|
|
15
|
+
s = f"\033[31;1merror: \033[0m\033[2m{msg}\033[0m\n"
|
|
16
|
+
self.msg = s
|
|
17
|
+
super().__init__(s)
|
|
18
|
+
|
|
19
|
+
def print(self, filename: str, file_content: str):
|
|
20
|
+
line = self.pos[0]
|
|
21
|
+
col = self.pos[1]
|
|
22
|
+
bol = self.pos[2]
|
|
23
|
+
|
|
24
|
+
eol = bol
|
|
25
|
+
while eol != len(file_content) and file_content[eol] != "\n":
|
|
26
|
+
eol += 1
|
|
27
|
+
|
|
28
|
+
if self.pos == (0, 0, 0):
|
|
29
|
+
print(self.msg, end="")
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
line_begin = f" \033[31;1m{line}\033[0m | "
|
|
33
|
+
padding = len(str(line) + " | ") + col - 1
|
|
34
|
+
spaces = lambda *_: " " * padding
|
|
35
|
+
|
|
36
|
+
print(f"\033[0m\033[1m{filename}:{line}: ", end="")
|
|
37
|
+
print(self.msg, end="")
|
|
38
|
+
|
|
39
|
+
print(line_begin, end="")
|
|
40
|
+
print(file_content[bol:eol])
|
|
41
|
+
|
|
42
|
+
tildes = f"{spaces()}\033[31;1m{'~' * self.len}\033[0m"
|
|
43
|
+
print(tildes)
|
|
44
|
+
indicator = f"{spaces()}\033[31;1m∟ \033[0m\033[1merror at line {line} column {col}\033[0m"
|
|
45
|
+
print(indicator)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class BCWarning(Exception):
|
|
49
|
+
# row, col, bol
|
|
50
|
+
pos: tuple[int, int, int]
|
|
51
|
+
|
|
52
|
+
def __init__(self, msg: str, ctx=None, data=None) -> None: # type: ignore
|
|
53
|
+
self.len = 1
|
|
54
|
+
self.data = data
|
|
55
|
+
if type(ctx).__name__ == "Token":
|
|
56
|
+
self.pos = ctx.pos # type: ignore
|
|
57
|
+
self.len = len(ctx.get_raw()[0]) # type: ignore
|
|
58
|
+
elif type(ctx) == tuple[int, int, int]:
|
|
59
|
+
self.pos = ctx
|
|
60
|
+
else:
|
|
61
|
+
self.pos = (0, 0, 0) # type: ignore
|
|
62
|
+
|
|
63
|
+
s = f"\033[35;1mwarning: \033[0m\033[2m{msg}\033[0m\n"
|
|
64
|
+
self.msg = s
|
|
65
|
+
super().__init__(s)
|
|
66
|
+
|
|
67
|
+
def print(self, filename: str, file_content: str):
|
|
68
|
+
line = self.pos[0]
|
|
69
|
+
col = self.pos[1]
|
|
70
|
+
bol = self.pos[2]
|
|
71
|
+
|
|
72
|
+
eol = bol
|
|
73
|
+
while eol != len(file_content) and file_content[eol] != "\n":
|
|
74
|
+
eol += 1
|
|
75
|
+
|
|
76
|
+
if self.pos == (0, 0, 0):
|
|
77
|
+
print(self.msg, end="")
|
|
78
|
+
return
|
|
79
|
+
|
|
80
|
+
line_begin = f" \033[35;1m{line}\033[0m | "
|
|
81
|
+
padding = len(str(line) + " | ") + col
|
|
82
|
+
spaces = lambda *_: " " * padding
|
|
83
|
+
|
|
84
|
+
print(f"\033[0m\033[1m{filename}:{line}: ", end="")
|
|
85
|
+
print(self.msg, end="")
|
|
86
|
+
|
|
87
|
+
print(line_begin, end="")
|
|
88
|
+
print(file_content[bol:eol])
|
|
89
|
+
|
|
90
|
+
tildes = f"{spaces()}\033[35;1m{'~' * self.len}\033[0m"
|
|
91
|
+
print(tildes)
|
|
92
|
+
indicator = f"{spaces()}\033[35;1m∟ \033[0m\033[1mwarning at line {line} column {col}\033[0m"
|
|
93
|
+
print(indicator)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def error(msg: str):
|
|
97
|
+
print(f"\033[31;1merror: \033[0m{msg}")
|
|
98
|
+
exit(1)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def panic(msg: str):
|
|
102
|
+
print(f"\033[31;1mpanic! \033[0m{msg}")
|
|
103
|
+
print(
|
|
104
|
+
"\033[31mplease report this error to the developers. A traceback is provided:\033[0m"
|
|
105
|
+
)
|
|
106
|
+
raise Exception("panicked")
|
beancode/__main__.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import argparse
|
|
4
|
+
|
|
5
|
+
from .interpreter import Interpreter
|
|
6
|
+
from .lexer import *
|
|
7
|
+
from .parser import Parser
|
|
8
|
+
from . import BCError, BCWarning, error
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def main():
|
|
12
|
+
parser = argparse.ArgumentParser()
|
|
13
|
+
parser.add_argument("file", type=str)
|
|
14
|
+
parser.add_argument(
|
|
15
|
+
"--debug", action="store_true", help="show debugging information"
|
|
16
|
+
)
|
|
17
|
+
args = parser.parse_args()
|
|
18
|
+
|
|
19
|
+
if not os.path.exists(args.file):
|
|
20
|
+
error(f"file {args.file} does not exist!")
|
|
21
|
+
|
|
22
|
+
with open(args.file, "r+") as f:
|
|
23
|
+
file_content = f.read()
|
|
24
|
+
|
|
25
|
+
lexer = Lexer(file_content)
|
|
26
|
+
toks = lexer.tokenize()
|
|
27
|
+
|
|
28
|
+
if args.debug:
|
|
29
|
+
for tok in toks:
|
|
30
|
+
print(tok)
|
|
31
|
+
|
|
32
|
+
parser = Parser(toks)
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
program, _ = parser.program()
|
|
36
|
+
except BCError as err:
|
|
37
|
+
err.print(args.file, file_content)
|
|
38
|
+
exit(1)
|
|
39
|
+
except BCWarning as w:
|
|
40
|
+
w.print(args.file, file_content)
|
|
41
|
+
exit(1)
|
|
42
|
+
|
|
43
|
+
if args.debug:
|
|
44
|
+
print("\033[1m----- BEGINNING OF AST -----\033[0m", file=sys.stderr)
|
|
45
|
+
for stmt in program.stmts:
|
|
46
|
+
print(stmt)
|
|
47
|
+
print()
|
|
48
|
+
print("\033[0m\033[1m----- END OF AST -----\033[0m", file=sys.stderr)
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
i = Interpreter(program.stmts)
|
|
52
|
+
i.toplevel = True
|
|
53
|
+
i.visit_block(None)
|
|
54
|
+
except BCError as err:
|
|
55
|
+
err.print(args.file, file_content)
|
|
56
|
+
exit(1)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
if __name__ == "__main__":
|
|
60
|
+
main()
|
beancode/bean_ast.py
ADDED
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from . import *
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class Expr:
|
|
8
|
+
# location of the token
|
|
9
|
+
pos: tuple[int, int, int] | None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
BCPrimitiveType = typing.Literal["integer", "real", "char", "string", "boolean", "null"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class BCArrayType:
|
|
17
|
+
inner: BCPrimitiveType
|
|
18
|
+
is_matrix: bool # true: 2d array
|
|
19
|
+
flat_bounds: tuple["Expr", "Expr"] | None = None # begin:end
|
|
20
|
+
matrix_bounds: tuple["Expr", "Expr", "Expr", "Expr"] | None = (
|
|
21
|
+
None # begin:end,begin:end
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def has_bounds(self) -> bool:
|
|
25
|
+
return self.flat_bounds is not None or self.matrix_bounds is not None
|
|
26
|
+
|
|
27
|
+
def get_flat_bounds(self) -> tuple["Expr", "Expr"]:
|
|
28
|
+
if self.flat_bounds is None:
|
|
29
|
+
raise BCError("tried to access flat bounds on array without flat bounds")
|
|
30
|
+
return self.flat_bounds
|
|
31
|
+
|
|
32
|
+
def get_matrix_bounds(self) -> tuple["Expr", "Expr", "Expr", "Expr"]:
|
|
33
|
+
if self.matrix_bounds is None:
|
|
34
|
+
raise BCError("tried to access matrixbounds on array without matrix bounds")
|
|
35
|
+
return self.matrix_bounds
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class BCArray:
|
|
40
|
+
typ: BCArrayType
|
|
41
|
+
flat: list["BCValue"] | None = None # must be a BCPrimitiveType
|
|
42
|
+
matrix: list[list["BCValue"]] | None = None # must be a BCPrimitiveType
|
|
43
|
+
flat_bounds: tuple[int, int] | None = None
|
|
44
|
+
matrix_bounds: tuple[int, int, int, int] | None = None
|
|
45
|
+
|
|
46
|
+
def __repr__(self) -> str:
|
|
47
|
+
if not self.typ.is_matrix:
|
|
48
|
+
return str(self.flat)
|
|
49
|
+
else:
|
|
50
|
+
return str(self.matrix)
|
|
51
|
+
|
|
52
|
+
def get_flat(self) -> list["BCValue"]:
|
|
53
|
+
if self.flat is None:
|
|
54
|
+
raise BCError("tried to access flat array from a matrix array")
|
|
55
|
+
return self.flat
|
|
56
|
+
|
|
57
|
+
def get_matrix(self) -> list[list["BCValue"]]:
|
|
58
|
+
if self.matrix is None:
|
|
59
|
+
raise BCError("tried to access matrix array from a flat array")
|
|
60
|
+
return self.matrix
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
BCType = BCArrayType | BCPrimitiveType
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass
|
|
67
|
+
class BCValue:
|
|
68
|
+
kind: BCType
|
|
69
|
+
integer: int | None = None
|
|
70
|
+
real: float | None = None
|
|
71
|
+
char: str | None = None
|
|
72
|
+
string: str | None = None
|
|
73
|
+
boolean: bool | None = None
|
|
74
|
+
array: BCArray | None = None
|
|
75
|
+
|
|
76
|
+
def is_uninitialized(self) -> bool:
|
|
77
|
+
return (
|
|
78
|
+
self.integer is None
|
|
79
|
+
and self.real is None
|
|
80
|
+
and self.char is None
|
|
81
|
+
and self.string is None
|
|
82
|
+
and self.boolean is None
|
|
83
|
+
and self.array is None
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def is_null(self) -> bool:
|
|
87
|
+
return self.kind == "null"
|
|
88
|
+
|
|
89
|
+
@classmethod
|
|
90
|
+
def empty(cls, kind: BCType) -> "BCValue":
|
|
91
|
+
return cls(
|
|
92
|
+
kind,
|
|
93
|
+
integer=None,
|
|
94
|
+
real=None,
|
|
95
|
+
char=None,
|
|
96
|
+
string=None,
|
|
97
|
+
boolean=None,
|
|
98
|
+
array=None,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
@classmethod
|
|
102
|
+
def new_integer(cls, i: int) -> "BCValue":
|
|
103
|
+
return cls("integer", integer=i)
|
|
104
|
+
|
|
105
|
+
@classmethod
|
|
106
|
+
def new_real(cls, r: float) -> "BCValue":
|
|
107
|
+
return cls("real", real=r)
|
|
108
|
+
|
|
109
|
+
@classmethod
|
|
110
|
+
def new_boolean(cls, b: bool) -> "BCValue":
|
|
111
|
+
return cls("boolean", boolean=b)
|
|
112
|
+
|
|
113
|
+
@classmethod
|
|
114
|
+
def new_char(cls, c: str) -> "BCValue":
|
|
115
|
+
return cls("char", char=c[0])
|
|
116
|
+
|
|
117
|
+
@classmethod
|
|
118
|
+
def new_string(cls, s: str) -> "BCValue":
|
|
119
|
+
return cls("string", string=s)
|
|
120
|
+
|
|
121
|
+
# arrays later
|
|
122
|
+
|
|
123
|
+
def get_integer(self) -> int:
|
|
124
|
+
if self.kind != "integer":
|
|
125
|
+
raise BCError(f"tried to access integer value from BCValue of {self.kind}")
|
|
126
|
+
|
|
127
|
+
return self.integer # type: ignore
|
|
128
|
+
|
|
129
|
+
def get_real(self) -> float:
|
|
130
|
+
if self.kind != "real":
|
|
131
|
+
raise BCError(f"tried to access real value from BCValue of {self.kind}")
|
|
132
|
+
|
|
133
|
+
return self.real # type: ignore
|
|
134
|
+
|
|
135
|
+
def get_char(self) -> str:
|
|
136
|
+
if self.kind != "char":
|
|
137
|
+
raise BCError(f"tried to access char value from BCValue of {self.kind}")
|
|
138
|
+
|
|
139
|
+
return self.char # type: ignore
|
|
140
|
+
|
|
141
|
+
def get_string(self) -> str:
|
|
142
|
+
if self.kind != "string":
|
|
143
|
+
raise BCError(f"tried to access string value from BCValue of {self.kind}")
|
|
144
|
+
|
|
145
|
+
return self.string # type: ignore
|
|
146
|
+
|
|
147
|
+
def get_boolean(self) -> bool:
|
|
148
|
+
if self.kind != "boolean":
|
|
149
|
+
raise BCError(f"tried to access boolean value from BCValue of {self.kind}")
|
|
150
|
+
|
|
151
|
+
return self.boolean # type: ignore
|
|
152
|
+
|
|
153
|
+
def get_array(self) -> BCArray:
|
|
154
|
+
if not isinstance(self.kind, BCArrayType):
|
|
155
|
+
raise BCError(f"tried to access array value from BCValue of {self.kind}")
|
|
156
|
+
|
|
157
|
+
return self.array # type: ignore
|
|
158
|
+
|
|
159
|
+
def __repr__(self) -> str: # type: ignore
|
|
160
|
+
if isinstance(self.kind, BCArrayType):
|
|
161
|
+
return self.array.__repr__()
|
|
162
|
+
|
|
163
|
+
if self.is_uninitialized():
|
|
164
|
+
return "(null)"
|
|
165
|
+
|
|
166
|
+
match self.kind:
|
|
167
|
+
case "string":
|
|
168
|
+
return self.get_string()
|
|
169
|
+
case "real":
|
|
170
|
+
return str(self.get_real())
|
|
171
|
+
case "integer":
|
|
172
|
+
return str(self.get_integer())
|
|
173
|
+
case "char":
|
|
174
|
+
return str(self.get_char())
|
|
175
|
+
case "boolean":
|
|
176
|
+
return str(self.get_boolean())
|
|
177
|
+
case "null":
|
|
178
|
+
return "(null)"
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@dataclass
|
|
182
|
+
class Literal(Expr):
|
|
183
|
+
kind: BCPrimitiveType
|
|
184
|
+
integer: int | None = None
|
|
185
|
+
real: float | None = None
|
|
186
|
+
char: str | None = None
|
|
187
|
+
string: str | None = None
|
|
188
|
+
boolean: bool | None = None
|
|
189
|
+
|
|
190
|
+
def to_bcvalue(self) -> BCValue:
|
|
191
|
+
return BCValue(
|
|
192
|
+
self.kind,
|
|
193
|
+
integer=self.integer,
|
|
194
|
+
real=self.real,
|
|
195
|
+
char=self.char,
|
|
196
|
+
string=self.string,
|
|
197
|
+
boolean=self.boolean,
|
|
198
|
+
array=None,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@dataclass
|
|
203
|
+
class Negation(Expr):
|
|
204
|
+
inner: Expr
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@dataclass
|
|
208
|
+
class Not(Expr):
|
|
209
|
+
inner: Expr
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@dataclass
|
|
213
|
+
class Grouping(Expr):
|
|
214
|
+
inner: Expr
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
@dataclass
|
|
218
|
+
class Identifier(Expr):
|
|
219
|
+
ident: str
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@dataclass
|
|
223
|
+
class Typecast(Expr):
|
|
224
|
+
typ: BCPrimitiveType
|
|
225
|
+
expr: Expr
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
@dataclass
|
|
229
|
+
class ArrayLiteral(Expr):
|
|
230
|
+
items: list[Expr]
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
Operator = typing.Literal[
|
|
234
|
+
"assign",
|
|
235
|
+
"equal",
|
|
236
|
+
"less_than",
|
|
237
|
+
"greater_than",
|
|
238
|
+
"less_than_or_equal",
|
|
239
|
+
"greater_than_or_equal",
|
|
240
|
+
"not_equal",
|
|
241
|
+
"mul",
|
|
242
|
+
"div",
|
|
243
|
+
"add",
|
|
244
|
+
"sub",
|
|
245
|
+
"and",
|
|
246
|
+
"or",
|
|
247
|
+
"not",
|
|
248
|
+
]
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
@dataclass
|
|
252
|
+
class BinaryExpr(Expr):
|
|
253
|
+
lhs: Expr
|
|
254
|
+
op: Operator
|
|
255
|
+
rhs: Expr
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
@dataclass
|
|
259
|
+
class ArrayIndex(Expr):
|
|
260
|
+
ident: Identifier
|
|
261
|
+
idx_outer: Expr
|
|
262
|
+
idx_inner: Expr | None = None
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
StatementKind = typing.Literal[
|
|
266
|
+
"declare",
|
|
267
|
+
"output",
|
|
268
|
+
"input",
|
|
269
|
+
"constant",
|
|
270
|
+
"assign",
|
|
271
|
+
"if",
|
|
272
|
+
"caseof",
|
|
273
|
+
"while",
|
|
274
|
+
"for",
|
|
275
|
+
"repeatuntil",
|
|
276
|
+
"function",
|
|
277
|
+
"procedure",
|
|
278
|
+
"call",
|
|
279
|
+
"fncall",
|
|
280
|
+
"return",
|
|
281
|
+
"scope",
|
|
282
|
+
"include",
|
|
283
|
+
]
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
@dataclass
|
|
287
|
+
class CallStatement:
|
|
288
|
+
pos: tuple[int, int, int]
|
|
289
|
+
ident: str
|
|
290
|
+
args: list[Expr]
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
@dataclass
|
|
294
|
+
class FunctionCall(Expr):
|
|
295
|
+
ident: str
|
|
296
|
+
args: list[Expr]
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
@dataclass
|
|
300
|
+
class OutputStatement:
|
|
301
|
+
pos: tuple[int, int, int]
|
|
302
|
+
items: list[Expr]
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
@dataclass
|
|
306
|
+
class InputStatement:
|
|
307
|
+
pos: tuple[int, int, int]
|
|
308
|
+
ident: Identifier
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
@dataclass
|
|
312
|
+
class ConstantStatement:
|
|
313
|
+
pos: tuple[int, int, int]
|
|
314
|
+
ident: Identifier
|
|
315
|
+
value: Literal
|
|
316
|
+
export: bool = False
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
@dataclass
|
|
320
|
+
class DeclareStatement:
|
|
321
|
+
pos: tuple[int, int, int]
|
|
322
|
+
ident: Identifier
|
|
323
|
+
typ: BCType
|
|
324
|
+
export: bool = False
|
|
325
|
+
expr: Expr | None = None
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
@dataclass
|
|
329
|
+
class AssignStatement:
|
|
330
|
+
pos: tuple[int, int, int]
|
|
331
|
+
ident: Identifier | ArrayIndex
|
|
332
|
+
value: Expr
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
@dataclass
|
|
336
|
+
class IfStatement:
|
|
337
|
+
pos: tuple[int, int, int]
|
|
338
|
+
cond: Expr
|
|
339
|
+
if_block: list["Statement"]
|
|
340
|
+
else_block: list["Statement"]
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
@dataclass
|
|
344
|
+
class CaseofBranch:
|
|
345
|
+
pos: tuple[int, int, int]
|
|
346
|
+
expr: Expr
|
|
347
|
+
stmt: "Statement"
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
@dataclass
|
|
351
|
+
class CaseofStatement:
|
|
352
|
+
pos: tuple[int, int, int]
|
|
353
|
+
expr: Expr
|
|
354
|
+
branches: list[CaseofBranch]
|
|
355
|
+
otherwise: "Statement | None"
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
@dataclass
|
|
359
|
+
class WhileStatement:
|
|
360
|
+
pos: tuple[int, int, int]
|
|
361
|
+
cond: Expr
|
|
362
|
+
block: list["Statement"]
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
@dataclass
|
|
366
|
+
class ForStatement:
|
|
367
|
+
pos: tuple[int, int, int]
|
|
368
|
+
counter: Identifier
|
|
369
|
+
block: list["Statement"]
|
|
370
|
+
begin: Expr
|
|
371
|
+
end: Expr
|
|
372
|
+
step: Expr | None
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
@dataclass
|
|
376
|
+
class RepeatUntilStatement:
|
|
377
|
+
pos: tuple[int, int, int]
|
|
378
|
+
cond: Expr
|
|
379
|
+
block: list["Statement"]
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
@dataclass
|
|
383
|
+
class FunctionArgument:
|
|
384
|
+
pos: tuple[int, int, int]
|
|
385
|
+
name: str
|
|
386
|
+
typ: BCType
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
@dataclass
|
|
390
|
+
class ProcedureStatement:
|
|
391
|
+
pos: tuple[int, int, int]
|
|
392
|
+
name: str
|
|
393
|
+
args: list[FunctionArgument]
|
|
394
|
+
block: list["Statement"]
|
|
395
|
+
export: bool = False
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
@dataclass
|
|
399
|
+
class FunctionStatement:
|
|
400
|
+
pos: tuple[int, int, int]
|
|
401
|
+
name: str
|
|
402
|
+
args: list[FunctionArgument]
|
|
403
|
+
returns: BCType
|
|
404
|
+
block: list["Statement"]
|
|
405
|
+
export: bool = False
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
@dataclass
|
|
409
|
+
class ReturnStatement:
|
|
410
|
+
pos: tuple[int, int, int]
|
|
411
|
+
expr: Expr | None
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
@dataclass
|
|
415
|
+
class ScopeStatement:
|
|
416
|
+
pos: tuple[int, int, int]
|
|
417
|
+
block: list["Statement"]
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
@dataclass
|
|
421
|
+
class IncludeStatement:
|
|
422
|
+
pos: tuple[int, int, int]
|
|
423
|
+
file: str
|
|
424
|
+
ffi: bool
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
@dataclass
|
|
428
|
+
class Statement:
|
|
429
|
+
kind: StatementKind
|
|
430
|
+
declare: DeclareStatement | None = None
|
|
431
|
+
output: OutputStatement | None = None
|
|
432
|
+
input: InputStatement | None = None
|
|
433
|
+
constant: ConstantStatement | None = None
|
|
434
|
+
assign: AssignStatement | None = None
|
|
435
|
+
if_s: IfStatement | None = None
|
|
436
|
+
caseof: CaseofStatement | None = None
|
|
437
|
+
while_s: WhileStatement | None = None
|
|
438
|
+
for_s: ForStatement | None = None
|
|
439
|
+
repeatuntil: RepeatUntilStatement | None = None
|
|
440
|
+
function: FunctionStatement | None = None
|
|
441
|
+
procedure: ProcedureStatement | None = None
|
|
442
|
+
call: CallStatement | None = None
|
|
443
|
+
fncall: FunctionCall | None = None # Impostor! expr as statement?!
|
|
444
|
+
return_s: ReturnStatement | None = None
|
|
445
|
+
scope: ScopeStatement | None = None
|
|
446
|
+
include: IncludeStatement | None = None
|
|
447
|
+
|
|
448
|
+
def __repr__(self) -> str:
|
|
449
|
+
match self.kind:
|
|
450
|
+
case "declare":
|
|
451
|
+
return self.declare.__repr__()
|
|
452
|
+
case "output":
|
|
453
|
+
return self.output.__repr__()
|
|
454
|
+
case "input":
|
|
455
|
+
return self.input.__repr__()
|
|
456
|
+
case "constant":
|
|
457
|
+
return self.constant.__repr__()
|
|
458
|
+
case "assign":
|
|
459
|
+
return self.assign.__repr__()
|
|
460
|
+
case "if":
|
|
461
|
+
return self.if_s.__repr__()
|
|
462
|
+
case "caseof":
|
|
463
|
+
return self.caseof.__repr__()
|
|
464
|
+
case "while":
|
|
465
|
+
return self.while_s.__repr__()
|
|
466
|
+
case "for":
|
|
467
|
+
return self.for_s.__repr__()
|
|
468
|
+
case "repeatuntil":
|
|
469
|
+
return self.repeatuntil.__repr__()
|
|
470
|
+
case "function":
|
|
471
|
+
return self.function.__repr__()
|
|
472
|
+
case "procedure":
|
|
473
|
+
return self.procedure.__repr__()
|
|
474
|
+
case "call":
|
|
475
|
+
return self.call.__repr__()
|
|
476
|
+
case "return":
|
|
477
|
+
return self.return_s.__repr__()
|
|
478
|
+
case "fncall":
|
|
479
|
+
return self.fncall.__repr__()
|
|
480
|
+
case "scope":
|
|
481
|
+
return self.scope.__repr__()
|
|
482
|
+
case "include":
|
|
483
|
+
return self.include.__repr__()
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
@dataclass
|
|
487
|
+
class Program:
|
|
488
|
+
stmts: list[Statement]
|
beancode/bean_ffi.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Callable, TypedDict
|
|
3
|
+
from .bean_ast import BCArrayType, BCPrimitiveType, BCType, BCValue, Literal
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _int_literal(i: int) -> Literal:
|
|
7
|
+
return Literal(None, "integer", integer=i)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def array(inner: BCPrimitiveType, low: int, high: int) -> BCArrayType:
|
|
11
|
+
b = (_int_literal(low), _int_literal(high))
|
|
12
|
+
return BCArrayType(inner, is_matrix=False, flat_bounds=b)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def matrix(
|
|
16
|
+
inner: BCPrimitiveType,
|
|
17
|
+
low_outer: int,
|
|
18
|
+
high_outer: int,
|
|
19
|
+
low_inner: int,
|
|
20
|
+
high_inner: int,
|
|
21
|
+
) -> BCArrayType:
|
|
22
|
+
b = (
|
|
23
|
+
_int_literal(low_outer),
|
|
24
|
+
_int_literal(high_outer),
|
|
25
|
+
_int_literal(low_inner),
|
|
26
|
+
_int_literal(high_inner),
|
|
27
|
+
)
|
|
28
|
+
return BCArrayType(inner, is_matrix=True, matrix_bounds=b)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
BCParamSpec = dict[str, BCType]
|
|
32
|
+
BCArgsList = dict[str, BCValue]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class BCFunction: # ffi variant of a function
|
|
37
|
+
name: str
|
|
38
|
+
params: BCParamSpec
|
|
39
|
+
returns: BCPrimitiveType
|
|
40
|
+
fn: Callable[[BCArgsList], BCValue]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class BCProcedure: # ffi variant of a function
|
|
45
|
+
name: str
|
|
46
|
+
params: BCParamSpec # spec of arg names and types
|
|
47
|
+
fn: Callable[[BCArgsList], None]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class BCDeclare:
|
|
52
|
+
name: str
|
|
53
|
+
typ: BCType | None = None # either typ, value or both must be set
|
|
54
|
+
value: BCValue | None = None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass
|
|
58
|
+
class BCConstant:
|
|
59
|
+
name: str
|
|
60
|
+
value: BCValue
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass
|
|
64
|
+
class Exports(TypedDict):
|
|
65
|
+
constants: list[BCConstant]
|
|
66
|
+
variables: list[BCDeclare]
|
|
67
|
+
procs: list[BCProcedure]
|
|
68
|
+
funcs: list[BCFunction]
|