more shit
This commit is contained in:
parent
d91eb65d4d
commit
5dd92c99fe
9 changed files with 148 additions and 25 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
.mypy_cache
|
.mypy_cache
|
||||||
__pycache__
|
__pycache__
|
||||||
.vim
|
.vim
|
||||||
gen/
|
gen/*
|
||||||
|
!gen/__init__.py
|
||||||
|
|
2
Justfile
2
Justfile
|
@ -1,2 +1,2 @@
|
||||||
watch:
|
watch:
|
||||||
watchexec -ce py,lark -i gen 'mypy *.py && python gen.py && mypy gen/*.py'
|
watchexec -ce py,lark,ag -i gen 'mypy *.py && python gen.py && mypy gen/*.py'
|
||||||
|
|
34
agast.py
34
agast.py
|
@ -11,9 +11,7 @@ class Iface(Decl):
|
||||||
class IfaceField: pass
|
class IfaceField: pass
|
||||||
|
|
||||||
class IfaceRef: pass
|
class IfaceRef: pass
|
||||||
|
class Expr: pass
|
||||||
class Node(Decl):
|
|
||||||
ifaces: List[IfaceRef]
|
|
||||||
|
|
||||||
class NodeRef: pass
|
class NodeRef: pass
|
||||||
class NodeRefByName(NodeRef):
|
class NodeRefByName(NodeRef):
|
||||||
|
@ -21,14 +19,16 @@ class NodeRefByName(NodeRef):
|
||||||
self.name = name
|
self.name = name
|
||||||
def __repr__(self) -> str: return f"NodeRefByName({self.name})"
|
def __repr__(self) -> str: return f"NodeRefByName({self.name})"
|
||||||
|
|
||||||
|
|
||||||
class Sym: pass
|
class Sym: pass
|
||||||
class SymRename(Sym):
|
class SymRename(Sym):
|
||||||
def __init__(self, name: str, node_ref: NodeRef):
|
def __init__(self, name: str, node_ref: NodeRef):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.node_ref = node_ref
|
self.node_ref = node_ref
|
||||||
def __repr__(self) -> str: return f"SymRename({self.name} : {self.node_ref})"
|
def __repr__(self) -> str: return f"SymRename({self.name} : {self.node_ref})"
|
||||||
class Equation: pass
|
class Equation:
|
||||||
|
def __init__(self, lhs: Expr, rhs: Expr):
|
||||||
|
self.lhs = lhs
|
||||||
|
self.rhs = rhs
|
||||||
|
|
||||||
class Variant:
|
class Variant:
|
||||||
def __init__(self, prod: List[Sym], equations: List[Equation]):
|
def __init__(self, prod: List[Sym], equations: List[Equation]):
|
||||||
|
@ -36,7 +36,12 @@ class Variant:
|
||||||
self.equations = equations
|
self.equations = equations
|
||||||
def __repr__(self) -> str: return f"Variant({self.prod}, {self.equations})"
|
def __repr__(self) -> str: return f"Variant({self.prod}, {self.equations})"
|
||||||
|
|
||||||
class Expr: pass
|
class Node(Decl):
|
||||||
|
def __init__(self, name: str, ifaces: List[IfaceRef], variants: List[Variant]):
|
||||||
|
self.name = name
|
||||||
|
self.ifaces = ifaces
|
||||||
|
self.variants = variants
|
||||||
|
|
||||||
class ExprDot(Expr):
|
class ExprDot(Expr):
|
||||||
def __init__(self, left: Expr, right: Expr):
|
def __init__(self, left: Expr, right: Expr):
|
||||||
self.left = left
|
self.left = left
|
||||||
|
@ -65,16 +70,24 @@ class ExprName(Expr):
|
||||||
class Parser(Transformer[List[Decl]]):
|
class Parser(Transformer[List[Decl]]):
|
||||||
def program(self, items: List[Decl]) -> List[Decl]: return items
|
def program(self, items: List[Decl]) -> List[Decl]: return items
|
||||||
|
|
||||||
|
# interfaces
|
||||||
def iface(self, items: List[Any]) -> Iface:
|
def iface(self, items: List[Any]) -> Iface:
|
||||||
[name, fields] = items
|
[name, fields] = items
|
||||||
return Iface(name)
|
return Iface(name)
|
||||||
def iface_field(self, items: List[str]) -> IfaceField:
|
def iface_field(self, items: List[str]) -> IfaceField:
|
||||||
[name, ty] = items
|
[name, ty] = items
|
||||||
return IfaceField()
|
return IfaceField()
|
||||||
|
def iface_ref(self, items: List[str]) -> str: return items[0]
|
||||||
|
def iface_refs(self, items: List[IfaceRef]) -> List[IfaceRef]: return items
|
||||||
|
|
||||||
|
# nodes
|
||||||
def node(self, items: List[Any]) -> Node:
|
def node(self, items: List[Any]) -> Node:
|
||||||
return Node()
|
[name, ifaces, variants] = items
|
||||||
|
return Node(name, ifaces, variants)
|
||||||
|
def node_ref_name(self, items: List[str]) -> NodeRefByName: return NodeRefByName(items[0])
|
||||||
|
|
||||||
|
# variants
|
||||||
|
def variants(self, items: List[Variant]) -> List[Variant]: return items
|
||||||
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)
|
||||||
|
@ -82,8 +95,12 @@ class Parser(Transformer[List[Decl]]):
|
||||||
|
|
||||||
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])
|
# equations
|
||||||
|
def equations(self, items: List[Equation]) -> List[Equation]: return items
|
||||||
|
def equation_(self, items: List[Equation]) -> Equation: return items[0]
|
||||||
|
def equation(self, items: List[Expr]) -> Equation: return Equation(items[0], items[1])
|
||||||
|
|
||||||
|
# expr
|
||||||
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)
|
||||||
|
@ -99,4 +116,5 @@ class Parser(Transformer[List[Decl]]):
|
||||||
|
|
||||||
def sep_trail(self, items: List[Tree]) -> List[T]:
|
def sep_trail(self, items: List[Tree]) -> List[T]:
|
||||||
return list(map(lambda it: cast(T, it), items))
|
return list(map(lambda it: cast(T, it), items))
|
||||||
|
|
||||||
def ident(self, items: List[Token]) -> str: return cast(str, items[0].value)
|
def ident(self, items: List[Token]) -> str: return cast(str, items[0].value)
|
||||||
|
|
72
agtypeck.py
72
agtypeck.py
|
@ -1,15 +1,26 @@
|
||||||
from typing import *
|
from typing import *
|
||||||
|
import textwrap
|
||||||
|
import re
|
||||||
from agast import *
|
from agast import *
|
||||||
|
|
||||||
class TypecheckResult:
|
global i
|
||||||
def __init__(self, pd: str):
|
i = 0
|
||||||
self.parser_data = pd
|
|
||||||
|
|
||||||
|
class TypecheckResult:
|
||||||
|
def __init__(self, pd: str = "", ex: str = ""):
|
||||||
|
self.parser_data = pd
|
||||||
|
self.extra = ex
|
||||||
|
|
||||||
def typecheck(program: List[Decl]) -> TypecheckResult:
|
def typecheck(program: List[Decl]) -> TypecheckResult:
|
||||||
i = 0
|
res = TypecheckResult()
|
||||||
def gen(name: str = "") -> str:
|
def gen(prefix: str = "", suffix: str = "") -> str:
|
||||||
return f"__ag{i:03}{name}"
|
global i
|
||||||
|
presan = re.sub("[^0-9a-zA-Z]+", "_", prefix)
|
||||||
|
sufsan = re.sub("[^0-9a-zA-Z]+", "_", suffix)
|
||||||
|
i += 1
|
||||||
|
return f"{presan}{i}{sufsan}"
|
||||||
|
def v(name: str) -> str:
|
||||||
|
return f"__ag_{name}"
|
||||||
|
|
||||||
# collect a list of name -> iface declarations
|
# collect a list of name -> iface declarations
|
||||||
ifaces: Dict[str, Decl] = dict(
|
ifaces: Dict[str, Decl] = dict(
|
||||||
|
@ -24,6 +35,51 @@ def typecheck(program: List[Decl]) -> TypecheckResult:
|
||||||
productions_hi: Dict[str, Union[str, List[str]]] = dict()
|
productions_hi: Dict[str, Union[str, List[str]]] = dict()
|
||||||
|
|
||||||
for node in filter(lambda c: isinstance(c, Node), program):
|
for node in filter(lambda c: isinstance(c, Node), program):
|
||||||
print(node)
|
node = cast(Node, node)
|
||||||
|
n_class_name = gen(node.name)
|
||||||
|
class_decl = textwrap.dedent(f"""
|
||||||
|
class {v(n_class_name)}: pass
|
||||||
|
""")
|
||||||
|
res.extra += class_decl
|
||||||
|
|
||||||
return TypecheckResult("")
|
print(node.name, node.ifaces)
|
||||||
|
|
||||||
|
for variant in node.variants:
|
||||||
|
v_class_name = gen(f"{n_class_name}_var")
|
||||||
|
class_decl = textwrap.dedent(f"""
|
||||||
|
class {v(v_class_name)}({v(n_class_name)}):
|
||||||
|
''' '''
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
res.extra += class_decl
|
||||||
|
|
||||||
|
prod_name = gen(node.name)
|
||||||
|
print(prod_name)
|
||||||
|
|
||||||
|
for sym in variant.prod:
|
||||||
|
print("sym", sym)
|
||||||
|
|
||||||
|
# for each of the equations, find out what the equation is
|
||||||
|
# trying to compute, and generate a thunk corresponding to
|
||||||
|
# that value.
|
||||||
|
for eq in variant.equations:
|
||||||
|
print("--eq", eq)
|
||||||
|
print(eq.lhs)
|
||||||
|
eq_name = gen(f"eq_{node.name}")
|
||||||
|
thunk_name = gen(f"thunk_{node.name}")
|
||||||
|
|
||||||
|
func_impl = textwrap.dedent(f"""
|
||||||
|
def {eq_name}() -> None:
|
||||||
|
''' {repr(eq)} '''
|
||||||
|
pass
|
||||||
|
def {thunk_name}() -> Thunk[None]:
|
||||||
|
return Thunk({eq_name})
|
||||||
|
""")
|
||||||
|
print(f"```py\n{func_impl}\n```")
|
||||||
|
res.extra += func_impl
|
||||||
|
|
||||||
|
# this is a "type alias" that connects it to one of the generated
|
||||||
|
# names above
|
||||||
|
res.extra += f"{node.name} = {v(n_class_name)}"
|
||||||
|
|
||||||
|
return res
|
16
gen.py
16
gen.py
|
@ -1,5 +1,6 @@
|
||||||
import textwrap
|
import textwrap
|
||||||
import os
|
import os
|
||||||
|
import importlib
|
||||||
from lark import Lark
|
from lark import Lark
|
||||||
|
|
||||||
from agast import *
|
from agast import *
|
||||||
|
@ -23,7 +24,8 @@ if __name__ == "__main__":
|
||||||
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"""
|
fmt_str = textwrap.dedent("""
|
||||||
|
__all__ = ["parse"]
|
||||||
from typing import Generic, TypeVar, Optional, Callable
|
from typing import Generic, TypeVar, Optional, Callable
|
||||||
from lark import Lark, Transformer
|
from lark import Lark, Transformer
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
|
@ -37,7 +39,15 @@ if __name__ == "__main__":
|
||||||
if self.value is None:
|
if self.value is None:
|
||||||
self.value = self.func()
|
self.value = self.func()
|
||||||
return self.value
|
return self.value
|
||||||
parser = Lark('''{res.parser_data}''')
|
parser = Lark('''start:
|
||||||
|
{pd}''')
|
||||||
class Trans(Transformer[None]):
|
class Trans(Transformer[None]):
|
||||||
pass
|
pass
|
||||||
"""))
|
{ex}
|
||||||
|
def parse(input: str) -> None:
|
||||||
|
print(input)
|
||||||
|
""")
|
||||||
|
f.write(fmt_str.format(pd=res.parser_data, ex=res.extra))
|
||||||
|
|
||||||
|
mod = importlib.import_module("gen.arith")
|
||||||
|
mod.parse("1 + 2 * 3") # type: ignore
|
||||||
|
|
0
gen/__init__.py
Normal file
0
gen/__init__.py
Normal file
19
grammar.lark
19
grammar.lark
|
@ -2,14 +2,20 @@ program: decl*
|
||||||
|
|
||||||
?decl: iface
|
?decl: iface
|
||||||
| node
|
| node
|
||||||
|
| func
|
||||||
|
|
||||||
sep_trail{item, punc}: item (punc item)? punc?
|
sep_trail{item, punc}: item (punc item)? punc?
|
||||||
|
|
||||||
|
func: "fn" ident "(" ")" ("->" ty) "{" "}"
|
||||||
|
|
||||||
iface: "iface" ident "{" sep_trail{iface_field, ","} "}"
|
iface: "iface" ident "{" sep_trail{iface_field, ","} "}"
|
||||||
iface_field: ident ":" ident
|
iface_field: ident ":" ident
|
||||||
|
|
||||||
node: "node" ident ":" ident "{" variant* "}"
|
iface_ref: ident
|
||||||
variant: prod "=>" "{" equation_* "}"
|
iface_refs: iface_ref*
|
||||||
|
node: "node" ident ":" iface_refs "{" variants "}"
|
||||||
|
variants: variant*
|
||||||
|
variant: prod "=>" "{" equations "}"
|
||||||
prod: sym*
|
prod: sym*
|
||||||
sym: sym_rename
|
sym: sym_rename
|
||||||
| STRING
|
| STRING
|
||||||
|
@ -17,7 +23,10 @@ sym_rename: "<" ident ":" node_ref ">"
|
||||||
node_ref: node_ref_name
|
node_ref: node_ref_name
|
||||||
| STRING
|
| STRING
|
||||||
node_ref_name: ident
|
node_ref_name: ident
|
||||||
|
equations: equation_*
|
||||||
equation_: equation ";"
|
equation_: equation ";"
|
||||||
|
// TODO: the left side should really be a separate type
|
||||||
|
// called lvalue, and should NOT include literals
|
||||||
equation: expr "=" expr
|
equation: expr "=" expr
|
||||||
|
|
||||||
expr: expr_dot
|
expr: expr_dot
|
||||||
|
@ -32,9 +41,13 @@ expr_call: expr "(" args ")"
|
||||||
expr_name: ident
|
expr_name: ident
|
||||||
args: sep_trail{expr, ","}
|
args: sep_trail{expr, ","}
|
||||||
|
|
||||||
|
ty: ident
|
||||||
|
|
||||||
ident: IDENT
|
ident: IDENT
|
||||||
|
COMMENT: /\/\/[^\n]*/
|
||||||
IDENT: /([a-zA-Z][a-zA-Z0-9_]*)|(_[a-zA-Z0-9_]+)/
|
IDENT: /([a-zA-Z][a-zA-Z0-9_]*)|(_[a-zA-Z0-9_]+)/
|
||||||
|
|
||||||
%import python.STRING
|
%import python.STRING
|
||||||
%import common.WS
|
%import common.WS
|
||||||
%ignore WS
|
%ignore WS
|
||||||
|
%ignore COMMENT
|
25
let.ag
Normal file
25
let.ag
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
iface HasEnv {
|
||||||
|
env: Map<str, str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
iface HasVal {
|
||||||
|
val: str,
|
||||||
|
}
|
||||||
|
|
||||||
|
alias Ident = /([a-zA-Z][a-zA-Z0-9_]*)|(_[a-zA-Z0-9_]+)/
|
||||||
|
|
||||||
|
node Expr : HasEnv + HasVal {
|
||||||
|
"let" <name:Ident> "=" <val:Expr> "in" <body:Expr> => {
|
||||||
|
body.env = self.env.with(name, val);
|
||||||
|
self.val = body.val;
|
||||||
|
}
|
||||||
|
<name:Ident> => {
|
||||||
|
// TODO: does env need to be referenced here?
|
||||||
|
// TODO: how to check for unbound names ahead of time
|
||||||
|
// (for self-implementation)
|
||||||
|
self.val = self.env.lookup(name);
|
||||||
|
}
|
||||||
|
<string:StringLit> => {
|
||||||
|
self.val = string;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +1 @@
|
||||||
watchexec --shell=powershell -ce py,lark -i gen './run.ps1'
|
watchexec --shell=powershell -ce py,lark,ag -i gen './run.ps1'
|
||||||
|
|
Loading…
Add table
Reference in a new issue