tabs -> spaces

This commit is contained in:
Michael Zhang 2021-06-14 15:52:53 -05:00
parent 8c687c4d1c
commit 6e7563c84c
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
6 changed files with 304 additions and 304 deletions

220
agast.py
View file

@ -4,148 +4,148 @@ from lark import Transformer, Tree, Token
T = TypeVar("T") T = TypeVar("T")
class Ast: class Ast:
# def __new__(cls: Type[Ast], name: str, bases: Tuple[type], namespace: Dict[str, Any]) -> Ast: # def __new__(cls: Type[Ast], name: str, bases: Tuple[type], namespace: Dict[str, Any]) -> Ast:
# x = super().__new__(cls, name, bases, namespace) # x = super().__new__(cls, name, bases, namespace)
# x.id = cls.__gen() # x.id = cls.__gen()
# return x # return x
id: str id: str
n = 0 n = 0
@classmethod @classmethod
def __gen(cls, name: str = "") -> str: def __gen(cls, name: str = "") -> str:
newid = cls.n newid = cls.n
cls.n += 1 cls.n += 1
return f"_a{newid}{name}" return f"_a{newid}{name}"
def __init__(self) -> None: def __init__(self) -> None:
self.id = self.__gen() self.id = self.__gen()
class Decl: class Decl:
name: str name: str
class IfaceRef(str): pass class IfaceRef(str): pass
class IfaceField: class IfaceField:
def __init__(self, name: str, ty: str): def __init__(self, name: str, ty: str):
self.name = name self.name = name
self.ty = ty self.ty = ty
class Iface(Decl): class Iface(Decl):
def __init__(self, name: str, fields: List[IfaceField]): def __init__(self, name: str, fields: List[IfaceField]):
self.name = name self.name = name
self.fields = fields self.fields = fields
class Expr(Ast): class Expr(Ast):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
class NodeRef: pass class NodeRef: pass
class NodeRefByName(NodeRef, str): class NodeRefByName(NodeRef, str):
def __init__(self, name: str): def __init__(self, name: str):
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, ty: NodeRef): def __init__(self, name: str, ty: NodeRef):
self.name = name self.name = name
self.ty = ty self.ty = ty
def __repr__(self) -> str: return f"SymRename({self.name} : {self.ty})" def __repr__(self) -> str: return f"SymRename({self.name} : {self.ty})"
class Equation: class Equation:
def __init__(self, lhs: Expr, rhs: Expr): def __init__(self, lhs: Expr, rhs: Expr):
self.lhs = lhs self.lhs = lhs
self.rhs = rhs self.rhs = rhs
def __repr__(self) -> str: return f"{self.lhs} = {self.rhs}" def __repr__(self) -> str: return f"{self.lhs} = {self.rhs}"
class Variant: class Variant:
def __init__(self, prod: List[Sym], equations: List[Equation]): def __init__(self, prod: List[Sym], equations: List[Equation]):
self.prod = prod self.prod = prod
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 Node(Decl): class Node(Decl):
def __init__(self, name: str, ifaces: List[IfaceRef], variants: List[Variant]): def __init__(self, name: str, ifaces: List[IfaceRef], variants: List[Variant]):
self.name = name self.name = name
self.ifaces = ifaces self.ifaces = ifaces
self.variants = variants self.variants = variants
class ExprDot(Expr): class ExprDot(Expr):
def __init__(self, left: Expr, right: str): def __init__(self, left: Expr, right: str):
super().__init__() super().__init__()
self.left = left self.left = left
self.right = right self.right = right
def __repr__(self) -> str: return f"{self.left}.{self.right}" def __repr__(self) -> str: return f"{self.left}.{self.right}"
class ExprAdd(Expr): class ExprAdd(Expr):
def __init__(self, left: Expr, right: Expr): def __init__(self, left: Expr, right: Expr):
super().__init__() super().__init__()
self.left = left self.left = left
self.right = right self.right = right
def __repr__(self) -> str: return f"{self.left} + {self.right}" def __repr__(self) -> str: return f"{self.left} + {self.right}"
class ExprMul(Expr): class ExprMul(Expr):
def __init__(self, left: Expr, right: Expr): def __init__(self, left: Expr, right: Expr):
super().__init__() super().__init__()
self.left = left self.left = left
self.right = right self.right = right
def __repr__(self) -> str: return f"{self.left} * {self.right}" def __repr__(self) -> str: return f"{self.left} * {self.right}"
class ExprCall(Expr): class ExprCall(Expr):
def __init__(self, func: Expr, args: List[Expr]): def __init__(self, func: Expr, args: List[Expr]):
super().__init__() super().__init__()
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): class ExprName(Expr):
def __init__(self, name: str): def __init__(self, name: str):
super().__init__() super().__init__()
self.name = name self.name = name
def __repr__(self) -> str: return f"{self.name}" def __repr__(self) -> str: return f"{self.name}"
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 # interfaces
def iface(self, items: List[Any]) -> Iface: def iface(self, items: List[Any]) -> Iface:
[name, fields] = items [name, fields] = items
return Iface(name, fields) return Iface(name, fields)
def iface_field(self, items: List[str]) -> IfaceField: def iface_field(self, items: List[str]) -> IfaceField:
[name, ty] = items [name, ty] = items
return IfaceField(name, ty) return IfaceField(name, ty)
def iface_ref(self, items: List[str]) -> str: return items[0] def iface_ref(self, items: List[str]) -> str: return items[0]
def iface_refs(self, items: List[IfaceRef]) -> List[IfaceRef]: return items def iface_refs(self, items: List[IfaceRef]) -> List[IfaceRef]: return items
# nodes # nodes
def node(self, items: List[Any]) -> Node: def node(self, items: List[Any]) -> Node:
[name, ifaces, variants] = items [name, ifaces, variants] = items
return Node(name, ifaces, variants) return Node(name, ifaces, variants)
def node_ref_name(self, items: List[str]) -> NodeRefByName: return NodeRefByName(items[0]) def node_ref_name(self, items: List[str]) -> NodeRefByName: return NodeRefByName(items[0])
# variants # variants
def variants(self, items: List[Variant]) -> List[Variant]: return items 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)
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])
# equations # equations
def equations(self, items: List[Equation]) -> List[Equation]: return items def equations(self, items: List[Equation]) -> List[Equation]: return items
def equation_semi(self, items: List[Equation]) -> Equation: return items[0] def equation_semi(self, items: List[Equation]) -> Equation: return items[0]
def equation(self, items: List[Expr]) -> Equation: return Equation(items[0], items[1]) def equation(self, items: List[Expr]) -> Equation: return Equation(items[0], items[1])
# expr # expr
def expr_dot(self, items: List[Any]) -> Expr: def expr_dot(self, items: List[Any]) -> Expr:
[left, right] = items [left, right] = items
return ExprDot(left, right) return ExprDot(left, right)
def expr_add(self, items: List[Expr]) -> Expr: def expr_add(self, items: List[Expr]) -> Expr:
[left, right] = items [left, right] = items
return ExprAdd(left, right) return ExprAdd(left, right)
def expr_mul(self, items: List[Expr]) -> Expr: def expr_mul(self, items: List[Expr]) -> Expr:
[left, right] = items [left, right] = items
return ExprMul(left, right) return ExprMul(left, right)
def expr_call(self, items: List[Expr]) -> Expr: def expr_call(self, items: List[Expr]) -> Expr:
[func, args] = items [func, args] = items
# TODO: args should be a list of exprs -_ - # TODO: args should be a list of exprs -_ -
return ExprCall(func, [args]) return ExprCall(func, [args])
def expr_name(self, items: List[str]) -> Expr: def expr_name(self, items: List[str]) -> Expr:
return ExprName(items[0]) return ExprName(items[0])
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)

228
aggen.py
View file

@ -9,132 +9,132 @@ global i
i = 0 i = 0
class GenResult: class GenResult:
def __init__(self, pd: str = "", ex: str = ""): def __init__(self, pd: str = "", ex: str = ""):
self.parser_data = pd self.parser_data = pd
self.extra = ex self.extra = ex
def gen(program: List[Decl]) -> GenResult: def gen(program: List[Decl]) -> GenResult:
res = GenResult() res = GenResult()
def gen(prefix: str = "", suffix: str = "") -> str: def gen(prefix: str = "", suffix: str = "") -> str:
global i global i
presan = re.sub("[^0-9a-zA-Z]+", "_", prefix) presan = re.sub("[^0-9a-zA-Z]+", "_", prefix)
sufsan = re.sub("[^0-9a-zA-Z]+", "_", suffix) sufsan = re.sub("[^0-9a-zA-Z]+", "_", suffix)
i += 1 i += 1
return f"{presan}{i}{sufsan}" return f"{presan}{i}{sufsan}"
def v(name: str) -> str: def v(name: str) -> str:
return f"__ag_{name}" return f"__ag_{name}"
# builtins # builtins
builtins: Dict[str, str] = { builtins: Dict[str, str] = {
"parseInt": "", "parseInt": "",
} }
# collect a list of name -> iface declarations # collect a list of name -> iface declarations
ifaces: Dict[str, Iface] = dict( ifaces: Dict[str, Iface] = dict(
map(lambda c: (c.name, cast(Iface, c)), map(lambda c: (c.name, cast(Iface, c)),
filter(lambda c: isinstance(c, Iface), filter(lambda c: isinstance(c, Iface),
program))) program)))
# list of node -> iface mappings # list of node -> iface mappings
what_ifaces: Dict[str, Set[str]] = dict() what_ifaces: Dict[str, Set[str]] = dict()
what_fields: Dict[str, Dict[str, str]] = dict() what_fields: Dict[str, Dict[str, str]] = dict()
for node in filter(lambda c: isinstance(c, Node), program): for node in filter(lambda c: isinstance(c, Node), program):
node = cast(Node, node) node = cast(Node, node)
# all_fields = dict() # all_fields = dict()
what_ifaces[node.name] = set(node.ifaces) what_ifaces[node.name] = set(node.ifaces)
this_fields = dict() this_fields = dict()
for iface in node.ifaces: for iface in node.ifaces:
fields = ifaces[iface].fields fields = ifaces[iface].fields
for field in fields: for field in fields:
if field.name in this_fields: if field.name in this_fields:
raise Exception("duplicate field name") raise Exception("duplicate field name")
this_fields[field.name] = field.ty this_fields[field.name] = field.ty
what_fields[node.name] = this_fields what_fields[node.name] = this_fields
print("what_ifaces:", what_ifaces) print("what_ifaces:", what_ifaces)
print("what_fields:", what_fields) print("what_fields:", what_fields)
# a high-level dictionary of productions; this has sub-productions # a high-level dictionary of productions; this has sub-productions
# that should be further expanded at a later step before converting # that should be further expanded at a later step before converting
# into lark code # into lark code
productions_hi: Dict[str, Union[str, List[str]]] = dict() productions_hi: Dict[str, Union[str, List[str]]] = dict()
# TODO: this should probably not be inlined here, but i'll move it # TODO: this should probably not be inlined here, but i'll move it
# out once i get more info into the 'env' # out once i get more info into the 'env'
def collect_required_thunks(env: List[Tuple[str, NodeRef]], expr: Expr) -> Dict[str, str]: def collect_required_thunks(env: List[Tuple[str, NodeRef]], expr: Expr) -> Dict[str, str]:
names = dict(env) names = dict(env)
print(f"collect_required_thunks({expr})", expr.__class__) print(f"collect_required_thunks({expr})", expr.__class__)
if isinstance(expr, ExprDot): if isinstance(expr, ExprDot):
return collect_required_thunks(env, expr.left) return collect_required_thunks(env, expr.left)
elif isinstance(expr, ExprMul): elif isinstance(expr, ExprMul):
a = collect_required_thunks(env, expr.left) a = collect_required_thunks(env, expr.left)
b = collect_required_thunks(env, expr.right) b = collect_required_thunks(env, expr.right)
a.update(b) a.update(b)
return a return a
elif isinstance(expr, ExprAdd): elif isinstance(expr, ExprAdd):
a = collect_required_thunks(env, expr.left) a = collect_required_thunks(env, expr.left)
b = collect_required_thunks(env, expr.right) b = collect_required_thunks(env, expr.right)
a.update(b) a.update(b)
return a return a
elif isinstance(expr, ExprCall): elif isinstance(expr, ExprCall):
return collect_required_thunks(env, expr.func) return collect_required_thunks(env, expr.func)
elif isinstance(expr, ExprName): elif isinstance(expr, ExprName):
if expr.name not in names and expr.name not in builtins: if expr.name not in names and expr.name not in builtins:
raise Exception(f"unbound name '{expr.name}'") raise Exception(f"unbound name '{expr.name}'")
return dict() return dict()
raise Exception(f"unhandled {expr.__class__}") raise Exception(f"unhandled {expr.__class__}")
for node in filter(lambda c: isinstance(c, Node), program): for node in filter(lambda c: isinstance(c, Node), program):
node = cast(Node, node) node = cast(Node, node)
n_class_name = gen(node.name) n_class_name = gen(node.name)
class_decl = textwrap.dedent(f""" class_decl = textwrap.dedent(f"""
class {v(n_class_name)}: pass class {v(n_class_name)}: pass
""") """)
res.extra += class_decl res.extra += class_decl
print(node.name, node.ifaces) print(node.name, node.ifaces)
for variant in node.variants: for variant in node.variants:
v_class_name = gen(f"{n_class_name}_var") v_class_name = gen(f"{n_class_name}_var")
class_decl = textwrap.dedent(f""" class_decl = textwrap.dedent(f"""
class {v(v_class_name)}({v(n_class_name)}): class {v(v_class_name)}({v(n_class_name)}):
''' ''' ''' '''
pass pass
""") """)
res.extra += class_decl res.extra += class_decl
prod_name = gen(node.name) prod_name = gen(node.name)
print(prod_name) print(prod_name)
# create an environment for checking the equations based on # create an environment for checking the equations based on
# the production # the production
env: List[Tuple[str, NodeRef]] = list() env: List[Tuple[str, NodeRef]] = list()
for sym in variant.prod: for sym in variant.prod:
if isinstance(sym, SymRename): if isinstance(sym, SymRename):
env.append((sym.name, sym.ty)) env.append((sym.name, sym.ty))
print(env) print(env)
# for each of the equations, find out what the equation is # for each of the equations, find out what the equation is
# trying to compute, and generate a thunk corresponding to # trying to compute, and generate a thunk corresponding to
# that value. # that value.
for eq in variant.equations: for eq in variant.equations:
eq_name = gen(f"eq_{node.name}") eq_name = gen(f"eq_{node.name}")
thunk_name = gen(f"thunk_{node.name}") thunk_name = gen(f"thunk_{node.name}")
print("RHS", eq.rhs, eq.rhs.id) print("RHS", eq.rhs, eq.rhs.id)
collect_required_thunks(copy.deepcopy(env), eq.rhs) collect_required_thunks(copy.deepcopy(env), eq.rhs)
func_impl = textwrap.dedent(f""" func_impl = textwrap.dedent(f"""
def {eq_name}() -> None: def {eq_name}() -> None:
''' {repr(eq)} ''' ''' {repr(eq)} '''
pass pass
def {thunk_name}() -> Thunk[None]: def {thunk_name}() -> Thunk[None]:
return Thunk({eq_name}) return Thunk({eq_name})
""") """)
print(f"```py\n{func_impl}\n```") print(f"```py\n{func_impl}\n```")
res.extra += func_impl res.extra += func_impl
# this is a "type alias" that connects it to one of the generated # this is a "type alias" that connects it to one of the generated
# names above # names above
res.extra += f"{node.name} = {v(n_class_name)}" res.extra += f"{node.name} = {v(n_class_name)}"
return res return res

View file

@ -9,47 +9,47 @@ from aggen import *
p = Lark(open("grammar.lark").read(), start="program", parser="lalr") 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()
cst = p.parse(data) cst = p.parse(data)
trans = Parser() trans = Parser()
ast = trans.transform(cst) ast = trans.transform(cst)
print("ast", ast) print("ast", ast)
res = gen(ast) res = gen(ast)
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:
fmt_str = textwrap.dedent(""" fmt_str = textwrap.dedent("""
__all__ = ["parse"] __all__ = ["parse"]
from typing import Generic, TypeVar, Optional, Callable, Dict, Any from typing import Generic, TypeVar, Optional, Callable, Dict, Any
from lark import Lark, Transformer from lark import Lark, Transformer
T = TypeVar('T') T = TypeVar('T')
builtins: Dict[str, Any] = {{ builtins: Dict[str, Any] = {{
"parseInt": lambda s: int(s) "parseInt": lambda s: int(s)
}} }}
class Thunk(Generic[T]): class Thunk(Generic[T]):
''' A thunk represents a value that may be computed lazily. ''' ''' A thunk represents a value that may be computed lazily. '''
value: Optional[T] value: Optional[T]
def __init__(self, func: Callable[[], T]): def __init__(self, func: Callable[[], T]):
self.func = func self.func = func
self.value = None self.value = None
def get(self) -> T: def get(self) -> T:
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('''start: parser = Lark('''start:
{pd}''') {pd}''')
class Trans(Transformer[None]): class Trans(Transformer[None]):
pass pass
{ex} {ex}
def parse(input: str) -> None: def parse(input: str) -> None:
print(input) print(input)
""") """)
f.write(fmt_str.format(pd=res.parser_data, ex=res.extra)) f.write(fmt_str.format(pd=res.parser_data, ex=res.extra))
mod = importlib.import_module("gen.arith") mod = importlib.import_module("gen.arith")
mod.parse("1 + 2 * 3") # type: ignore mod.parse("1 + 2 * 3") # type: ignore

View file

@ -1,13 +1,13 @@
iface HasValue { iface HasValue {
val: int, val: int,
} }
node Expr : HasValue { node Expr : HasValue {
<l:Expr> "+" <r:Expr> => { <l:Expr> "+" <r:Expr> => {
self.val = l.val + r.val * l.val; self.val = l.val + r.val * l.val;
} }
<l:Expr> "*" <r:Expr> => { <l:Expr> "*" <r:Expr> => {
self.val = l.val * r.val; self.val = l.val * r.val;
} }
<n:r"[0-9]+"> => { self.val = parseInt(n); } <n:r"[0-9]+"> => { self.val = parseInt(n); }
} }

30
let.ag
View file

@ -1,25 +1,25 @@
iface HasEnv { iface HasEnv {
env: Map<str, str>, env: Map<str, str>,
} }
iface HasVal { iface HasVal {
val: str, val: str,
} }
alias Ident = /([a-zA-Z][a-zA-Z0-9_]*)|(_[a-zA-Z0-9_]+)/ alias Ident = /([a-zA-Z][a-zA-Z0-9_]*)|(_[a-zA-Z0-9_]+)/
node Expr : HasEnv + HasVal { node Expr : HasEnv + HasVal {
"let" <name:Ident> "=" <val:Expr> "in" <body:Expr> => { "let" <name:Ident> "=" <val:Expr> "in" <body:Expr> => {
body.env = self.env.with(name, val); body.env = self.env.with(name, val);
self.val = body.val; self.val = body.val;
} }
<name:Ident> => { <name:Ident> => {
// TODO: does env need to be referenced here? // TODO: does env need to be referenced here?
// TODO: how to check for unbound names ahead of time // TODO: how to check for unbound names ahead of time
// (for self-implementation) // (for self-implementation)
self.val = self.env.lookup(name); self.val = self.env.lookup(name);
} }
<string:StringLit> => { <string:StringLit> => {
self.val = string; self.val = string;
} }
} }

36
old.py
View file

@ -3,33 +3,33 @@ from typing import Generic, TypeVar, Optional, Callable
T = TypeVar("T") T = TypeVar("T")
class Thunk(Generic[T]): class Thunk(Generic[T]):
value: Optional[T] value: Optional[T]
def __init__(self, func: Callable[[], T]): def __init__(self, func: Callable[[], T]):
self.func = func self.func = func
self.value = None self.value = None
def get(self) -> T: def get(self) -> T:
if self.value is None: if self.value is None:
self.value = self.func() self.value = self.func()
return self.value return self.value
class Node: class Node:
value: Thunk[int] value: Thunk[int]
class Add(Node): class Add(Node):
def __init__(self, left: Node, right: Node): def __init__(self, left: Node, right: Node):
self.value = Thunk(lambda: left.value.get() + right.value.get()) self.value = Thunk(lambda: left.value.get() + right.value.get())
class Mul(Node): class Mul(Node):
def __init__(self, left: Node, right: Node): def __init__(self, left: Node, right: Node):
self.value = Thunk(lambda: left.value.get() * right.value.get()) self.value = Thunk(lambda: left.value.get() * right.value.get())
class Lit(Node): class Lit(Node):
def __init__(self, num: int): def __init__(self, num: int):
self.num = num self.num = num
self.value = Thunk(lambda: num) self.value = Thunk(lambda: num)
if __name__ == "__main__": if __name__ == "__main__":
tree = Add(Mul(Lit(3), Lit(4)), Lit(5)) tree = Add(Mul(Lit(3), Lit(4)), Lit(5))
print(tree.value.get()) print(tree.value.get())