add some more productions to the transformer
This commit is contained in:
parent
0dff746fc2
commit
5c09d658b9
6 changed files with 105 additions and 17 deletions
46
agast.py
46
agast.py
|
@ -1,11 +1,26 @@
|
||||||
from typing import *
|
from typing import *
|
||||||
from lark import Transformer, Tree
|
from lark import Transformer, Tree, Token
|
||||||
|
|
||||||
class Interface: pass
|
T = TypeVar("T")
|
||||||
|
|
||||||
class Node: pass
|
class Decl:
|
||||||
|
name: str
|
||||||
|
class Iface(Decl):
|
||||||
|
def __init__(self, name: str):
|
||||||
|
self.name = name
|
||||||
|
class IfaceField: pass
|
||||||
|
|
||||||
|
class IfaceRef: pass
|
||||||
|
|
||||||
|
class Node(Decl):
|
||||||
|
ifaces: List[IfaceRef]
|
||||||
|
|
||||||
class NodeRef: pass
|
class NodeRef: pass
|
||||||
|
class NodeRefByName(NodeRef):
|
||||||
|
def __init__(self, name: str):
|
||||||
|
self.name = name
|
||||||
|
def __repr__(self) -> str: return f"NodeRefByName({self.name})"
|
||||||
|
|
||||||
|
|
||||||
class Sym: pass
|
class Sym: pass
|
||||||
class SymRename(Sym):
|
class SymRename(Sym):
|
||||||
|
@ -42,14 +57,33 @@ class ExprCall(Expr):
|
||||||
self.func = func
|
self.func = func
|
||||||
self.args = args
|
self.args = args
|
||||||
def __repr__(self) -> str: return f"{self.func}({self.args})"
|
def __repr__(self) -> str: return f"{self.func}({self.args})"
|
||||||
|
class ExprName(Expr):
|
||||||
|
def __init__(self, name: str):
|
||||||
|
self.name = name
|
||||||
|
def __repr__(self) -> str: return f"{self.name}"
|
||||||
|
|
||||||
|
class Parser(Transformer[List[Decl]]):
|
||||||
|
def program(self, items: List[Decl]) -> List[Decl]: return items
|
||||||
|
|
||||||
|
def iface(self, items: List[Any]) -> Iface:
|
||||||
|
[name, fields] = items
|
||||||
|
return Iface(name)
|
||||||
|
def iface_field(self, items: List[str]) -> IfaceField:
|
||||||
|
[name, ty] = items
|
||||||
|
return IfaceField()
|
||||||
|
|
||||||
|
def node(self, items: List[Any]) -> Node:
|
||||||
|
return Node()
|
||||||
|
|
||||||
class Parser(Transformer[None]):
|
|
||||||
def variant(self, items: List[Any]) -> Variant:
|
def variant(self, items: List[Any]) -> Variant:
|
||||||
[prod, equations] = items
|
[prod, equations] = items
|
||||||
return Variant(prod, equations)
|
return Variant(prod, equations)
|
||||||
def prod(self, items: List[Sym]) -> List[Sym]: return items
|
def prod(self, items: List[Sym]) -> List[Sym]: return items
|
||||||
|
|
||||||
def sym_rename(self, items: List[Any]) -> Sym: return SymRename(items[0], items[1])
|
def sym_rename(self, items: List[Any]) -> Sym: return SymRename(items[0], items[1])
|
||||||
|
|
||||||
|
def node_ref_name(self, items: List[str]) -> NodeRefByName: return NodeRefByName(items[0])
|
||||||
|
|
||||||
def expr_dot(self, items: List[Expr]) -> Expr:
|
def expr_dot(self, items: List[Expr]) -> Expr:
|
||||||
[left, _, right] = items
|
[left, _, right] = items
|
||||||
return ExprDot(left, right)
|
return ExprDot(left, right)
|
||||||
|
@ -62,3 +96,7 @@ class Parser(Transformer[None]):
|
||||||
def expr_call(self, items: List[Expr]) -> Expr:
|
def expr_call(self, items: List[Expr]) -> Expr:
|
||||||
[func, _, args, _] = items
|
[func, _, args, _] = items
|
||||||
return ExprMul(func, args)
|
return ExprMul(func, args)
|
||||||
|
|
||||||
|
def sep_trail(self, items: List[Tree]) -> List[T]:
|
||||||
|
return list(map(lambda it: cast(T, it), items))
|
||||||
|
def ident(self, items: List[Token]) -> str: return cast(str, items[0].value)
|
||||||
|
|
17
agtypeck.py
Normal file
17
agtypeck.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
from typing import *
|
||||||
|
from agast import *
|
||||||
|
|
||||||
|
def typecheck(program: List[Decl]) -> None:
|
||||||
|
i = 0
|
||||||
|
def gen(name: str = "") -> str:
|
||||||
|
return f"__ag{i:03}{name}"
|
||||||
|
|
||||||
|
# collect a list of name -> iface declarations
|
||||||
|
ifaces: Dict[str, Decl] = dict(
|
||||||
|
map(lambda c: (c.name, c),
|
||||||
|
filter(lambda c: isinstance(c, Iface),
|
||||||
|
program)))
|
||||||
|
print(ifaces)
|
||||||
|
|
||||||
|
for node in filter(lambda c: isinstance(c, Node), program):
|
||||||
|
print(node)
|
21
gen.py
21
gen.py
|
@ -2,23 +2,34 @@ import textwrap
|
||||||
import os
|
import os
|
||||||
from lark import Lark
|
from lark import Lark
|
||||||
|
|
||||||
from agast import Parser, Interface
|
from agast import *
|
||||||
|
from agtypeck import *
|
||||||
|
|
||||||
p = Lark(open("grammar.lark").read(), parser="lalr", transformer=Parser())
|
p = Lark(open("grammar.lark").read(), start="program", parser="lalr")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
with open("arith.ag") as f:
|
with open("arith.ag") as f:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
|
|
||||||
t = p.parse(data)
|
cst = p.parse(data)
|
||||||
print(t)
|
# print("cst", cst)
|
||||||
|
|
||||||
|
trans = Parser()
|
||||||
|
ast = trans.transform(cst)
|
||||||
|
print("ast", ast)
|
||||||
|
|
||||||
|
typecheck(ast)
|
||||||
|
|
||||||
|
parser_data = ""
|
||||||
|
|
||||||
if not os.path.exists("gen"):
|
if not os.path.exists("gen"):
|
||||||
os.makedirs("gen")
|
os.makedirs("gen")
|
||||||
with open("gen/arith.py", "w") as f:
|
with open("gen/arith.py", "w") as f:
|
||||||
f.write(textwrap.dedent("""
|
f.write(textwrap.dedent(f"""
|
||||||
from typing import Generic, TypeVar
|
from typing import Generic, TypeVar
|
||||||
|
from lark import Lark
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
class Thunk(Generic[T]):
|
class Thunk(Generic[T]):
|
||||||
pass
|
pass
|
||||||
|
parser = Lark('''{parser_data}''')
|
||||||
"""))
|
"""))
|
||||||
|
|
21
grammar.lark
21
grammar.lark
|
@ -1,19 +1,22 @@
|
||||||
start: decl*
|
program: decl*
|
||||||
|
|
||||||
decl: iface
|
?decl: iface
|
||||||
| node
|
| node
|
||||||
|
|
||||||
iface: IFACE IDENT "{" iface_field (COMMA iface_field)? COMMA? "}"
|
sep_trail{item, punc}: item (punc item)? punc?
|
||||||
iface_field: IDENT COLON IDENT
|
|
||||||
|
|
||||||
node: NODE IDENT COLON IDENT "{" variant* "}"
|
iface: "iface" ident "{" sep_trail{iface_field, ","} "}"
|
||||||
|
iface_field: ident ":" ident
|
||||||
|
|
||||||
|
node: NODE ident ":" ident "{" variant* "}"
|
||||||
variant: prod "=>" "{" equation_* "}"
|
variant: prod "=>" "{" equation_* "}"
|
||||||
prod: sym*
|
prod: sym*
|
||||||
sym: sym_rename
|
sym: sym_rename
|
||||||
| STRING
|
| STRING
|
||||||
sym_rename: "<" IDENT ":" node_ref ">"
|
sym_rename: "<" ident ":" node_ref ">"
|
||||||
node_ref: IDENT
|
node_ref: node_ref_name
|
||||||
| STRING
|
| STRING
|
||||||
|
node_ref_name: ident
|
||||||
equation_: equation SEMI
|
equation_: equation SEMI
|
||||||
equation: expr EQ expr
|
equation: expr EQ expr
|
||||||
|
|
||||||
|
@ -21,13 +24,15 @@ expr: expr_dot
|
||||||
| expr_add
|
| expr_add
|
||||||
| expr_mul
|
| expr_mul
|
||||||
| expr_call
|
| expr_call
|
||||||
| IDENT
|
| expr_name
|
||||||
expr_dot: expr DOT expr
|
expr_dot: expr DOT expr
|
||||||
expr_add: expr ADD expr
|
expr_add: expr ADD expr
|
||||||
expr_mul: expr MUL expr
|
expr_mul: expr MUL expr
|
||||||
expr_call: expr LPAR args RPAR
|
expr_call: expr LPAR args RPAR
|
||||||
|
expr_name: ident
|
||||||
args: expr (COMMA expr)? COMMA?
|
args: expr (COMMA expr)? COMMA?
|
||||||
|
|
||||||
|
ident: IDENT
|
||||||
IDENT: /([a-zA-Z][a-zA-Z0-9_]*)|(_[a-zA-Z0-9_]+)/
|
IDENT: /([a-zA-Z][a-zA-Z0-9_]*)|(_[a-zA-Z0-9_]+)/
|
||||||
IFACE: "iface"
|
IFACE: "iface"
|
||||||
NODE: "node"
|
NODE: "node"
|
||||||
|
|
16
run.ps1
Normal file
16
run.ps1
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#blessed https://stackoverflow.com/a/52784160
|
||||||
|
|
||||||
|
function Invoke-Call {
|
||||||
|
param (
|
||||||
|
[scriptblock]$ScriptBlock,
|
||||||
|
[string]$ErrorAction = $ErrorActionPreference
|
||||||
|
)
|
||||||
|
& @ScriptBlock
|
||||||
|
if (($lastexitcode -ne 0) -and $ErrorAction -eq "Stop") {
|
||||||
|
exit $lastexitcode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Invoke-Call -ScriptBlock {mypy (get-item *.py) } -ErrorAction Stop
|
||||||
|
Invoke-Call -ScriptBlock {python gen.py } -ErrorAction Stop
|
||||||
|
Invoke-Call -ScriptBlock {mypy (get-item gen/*.py) } -ErrorAction Stop
|
1
watch.ps1
Normal file
1
watch.ps1
Normal file
|
@ -0,0 +1 @@
|
||||||
|
watchexec --shell=powershell -ce py -i gen './run.ps1'
|
Loading…
Reference in a new issue