add some more productions to the transformer

This commit is contained in:
Michael Zhang 2021-06-09 01:33:53 -05:00
parent 0dff746fc2
commit 5c09d658b9
6 changed files with 105 additions and 17 deletions

View file

@ -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
View 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
View file

@ -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}''')
""")) """))

View file

@ -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
View 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
View file

@ -0,0 +1 @@
watchexec --shell=powershell -ce py -i gen './run.ps1'