initial
This commit is contained in:
commit
323c7a6282
7 changed files with 120 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
.mypy_cache
|
||||
gen/
|
2
Justfile
Normal file
2
Justfile
Normal file
|
@ -0,0 +1,2 @@
|
|||
watch:
|
||||
watchexec -ce py -i gen 'mypy *.py && python gen.py && mypy gen/*.py'
|
13
arith.ag
Normal file
13
arith.ag
Normal file
|
@ -0,0 +1,13 @@
|
|||
iface Node {
|
||||
val: int,
|
||||
}
|
||||
|
||||
node Expr : Node {
|
||||
<l:Expr> "+" <r:Expr> => {
|
||||
self.val = l.val + r.val;
|
||||
}
|
||||
<l:Expr> "*" <r:Expr> => {
|
||||
self.val = l.val * r.val;
|
||||
}
|
||||
<n:r"[0-9]+"> => { self.val = parseInt(n); }
|
||||
}
|
22
gen.py
Normal file
22
gen.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
import textwrap
|
||||
import os
|
||||
from lark import Lark
|
||||
|
||||
p = Lark(open("grammar.lark").read())
|
||||
|
||||
if __name__ == "__main__":
|
||||
with open("arith.ag") as f:
|
||||
data = f.read()
|
||||
|
||||
t = p.parse(data)
|
||||
print(t)
|
||||
|
||||
if not os.path.exists("gen"):
|
||||
os.makedirs("gen")
|
||||
with open("gen/arith.py", "w") as f:
|
||||
f.write(textwrap.dedent("""
|
||||
from typing import Generic, TypeVar
|
||||
T = TypeVar('T')
|
||||
class Thunk(Generic[T]):
|
||||
pass
|
||||
"""))
|
44
grammar.lark
Normal file
44
grammar.lark
Normal file
|
@ -0,0 +1,44 @@
|
|||
start: decl*
|
||||
|
||||
decl: iface
|
||||
| node
|
||||
|
||||
iface: IFACE IDENT "{" iface_field (COMMA iface_field)? COMMA? "}"
|
||||
iface_field: IDENT COLON IDENT
|
||||
|
||||
node: NODE IDENT COLON IDENT "{" node_prod* "}"
|
||||
node_prod: prod THICCARROW "{" (equation SEMI)* "}"
|
||||
prod: sym*
|
||||
sym: IDENT
|
||||
| LANG IDENT COLON node_ref RANG
|
||||
| STRING
|
||||
node_ref: IDENT
|
||||
| STRING
|
||||
equation: expr EQ expr
|
||||
|
||||
expr: expr DOT expr
|
||||
| expr ADD expr
|
||||
| expr MUL expr
|
||||
| expr LPAR args RPAR
|
||||
| IDENT
|
||||
args: expr (COMMA expr)? COMMA?
|
||||
|
||||
IDENT: /([a-zA-Z][a-zA-Z0-9_]*)|(_[a-zA-Z0-9_]+)/
|
||||
IFACE: "iface"
|
||||
NODE: "node"
|
||||
LANG: "<"
|
||||
RANG: ">"
|
||||
ADD: "+"
|
||||
MUL: "*"
|
||||
COMMA: ","
|
||||
COLON: ":"
|
||||
LPAR: "("
|
||||
RPAR: ")"
|
||||
EQ: "="
|
||||
DOT: "."
|
||||
SEMI: ";"
|
||||
THICCARROW: "=>"
|
||||
|
||||
%import python.STRING
|
||||
%import common.WS
|
||||
%ignore WS
|
35
main.py
Normal file
35
main.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
from typing import Generic, TypeVar, Optional, Callable
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
class Thunk(Generic[T]):
|
||||
value: Optional[T]
|
||||
|
||||
def __init__(self, func: Callable[[], T]):
|
||||
self.func = func
|
||||
self.value = None
|
||||
|
||||
def get(self) -> T:
|
||||
if self.value is None:
|
||||
self.value = self.func()
|
||||
return self.value
|
||||
|
||||
class Node:
|
||||
value: Thunk[int]
|
||||
|
||||
class Add(Node):
|
||||
def __init__(self, left: Node, right: Node):
|
||||
self.value = Thunk(lambda: left.value.get() + right.value.get())
|
||||
|
||||
class Mul(Node):
|
||||
def __init__(self, left: Node, right: Node):
|
||||
self.value = Thunk(lambda: left.value.get() * right.value.get())
|
||||
|
||||
class Lit(Node):
|
||||
def __init__(self, num: int):
|
||||
self.num = num
|
||||
self.value = Thunk(lambda: num)
|
||||
|
||||
if __name__ == "__main__":
|
||||
tree = Add(Mul(Lit(3), Lit(4)), Lit(5))
|
||||
print(tree.value.get())
|
2
mypy.ini
Normal file
2
mypy.ini
Normal file
|
@ -0,0 +1,2 @@
|
|||
[mypy]
|
||||
strict = True
|
Loading…
Reference in a new issue