diff --git a/agast.py b/agast.py index cfe79ef..2e7e496 100644 --- a/agast.py +++ b/agast.py @@ -4,148 +4,148 @@ from lark import Transformer, Tree, Token T = TypeVar("T") class Ast: - # def __new__(cls: Type[Ast], name: str, bases: Tuple[type], namespace: Dict[str, Any]) -> Ast: - # x = super().__new__(cls, name, bases, namespace) - # x.id = cls.__gen() - # return x - id: str - n = 0 - @classmethod - def __gen(cls, name: str = "") -> str: - newid = cls.n - cls.n += 1 - return f"_a{newid}{name}" - def __init__(self) -> None: - self.id = self.__gen() + # def __new__(cls: Type[Ast], name: str, bases: Tuple[type], namespace: Dict[str, Any]) -> Ast: + # x = super().__new__(cls, name, bases, namespace) + # x.id = cls.__gen() + # return x + id: str + n = 0 + @classmethod + def __gen(cls, name: str = "") -> str: + newid = cls.n + cls.n += 1 + return f"_a{newid}{name}" + def __init__(self) -> None: + self.id = self.__gen() class Decl: - name: str + name: str class IfaceRef(str): pass class IfaceField: - def __init__(self, name: str, ty: str): - self.name = name - self.ty = ty + def __init__(self, name: str, ty: str): + self.name = name + self.ty = ty class Iface(Decl): - def __init__(self, name: str, fields: List[IfaceField]): - self.name = name - self.fields = fields + def __init__(self, name: str, fields: List[IfaceField]): + self.name = name + self.fields = fields class Expr(Ast): - def __init__(self) -> None: - super().__init__() + def __init__(self) -> None: + super().__init__() class NodeRef: pass class NodeRefByName(NodeRef, str): - def __init__(self, name: str): - self.name = name - def __repr__(self) -> str: return f"NodeRefByName({self.name})" + def __init__(self, name: str): + self.name = name + def __repr__(self) -> str: return f"NodeRefByName({self.name})" class Sym: pass class SymRename(Sym): - def __init__(self, name: str, ty: NodeRef): - self.name = name - self.ty = ty - def __repr__(self) -> str: return f"SymRename({self.name} : {self.ty})" + def __init__(self, name: str, ty: NodeRef): + self.name = name + self.ty = ty + def __repr__(self) -> str: return f"SymRename({self.name} : {self.ty})" class Equation: - def __init__(self, lhs: Expr, rhs: Expr): - self.lhs = lhs - self.rhs = rhs - def __repr__(self) -> str: return f"{self.lhs} = {self.rhs}" + def __init__(self, lhs: Expr, rhs: Expr): + self.lhs = lhs + self.rhs = rhs + def __repr__(self) -> str: return f"{self.lhs} = {self.rhs}" class Variant: - def __init__(self, prod: List[Sym], equations: List[Equation]): - self.prod = prod - self.equations = equations - def __repr__(self) -> str: return f"Variant({self.prod}, {self.equations})" + def __init__(self, prod: List[Sym], equations: List[Equation]): + self.prod = prod + self.equations = equations + def __repr__(self) -> str: return f"Variant({self.prod}, {self.equations})" class Node(Decl): - def __init__(self, name: str, ifaces: List[IfaceRef], variants: List[Variant]): - self.name = name - self.ifaces = ifaces - self.variants = variants + def __init__(self, name: str, ifaces: List[IfaceRef], variants: List[Variant]): + self.name = name + self.ifaces = ifaces + self.variants = variants class ExprDot(Expr): - def __init__(self, left: Expr, right: str): - super().__init__() - self.left = left - self.right = right - def __repr__(self) -> str: return f"{self.left}.{self.right}" + def __init__(self, left: Expr, right: str): + super().__init__() + self.left = left + self.right = right + def __repr__(self) -> str: return f"{self.left}.{self.right}" class ExprAdd(Expr): - def __init__(self, left: Expr, right: Expr): - super().__init__() - self.left = left - self.right = right - def __repr__(self) -> str: return f"{self.left} + {self.right}" + def __init__(self, left: Expr, right: Expr): + super().__init__() + self.left = left + self.right = right + def __repr__(self) -> str: return f"{self.left} + {self.right}" class ExprMul(Expr): - def __init__(self, left: Expr, right: Expr): - super().__init__() - self.left = left - self.right = right - def __repr__(self) -> str: return f"{self.left} * {self.right}" + def __init__(self, left: Expr, right: Expr): + super().__init__() + self.left = left + self.right = right + def __repr__(self) -> str: return f"{self.left} * {self.right}" class ExprCall(Expr): - def __init__(self, func: Expr, args: List[Expr]): - super().__init__() - self.func = func - self.args = args - def __repr__(self) -> str: return f"{self.func}({self.args})" + def __init__(self, func: Expr, args: List[Expr]): + super().__init__() + self.func = func + self.args = args + def __repr__(self) -> str: return f"{self.func}({self.args})" class ExprName(Expr): - def __init__(self, name: str): - super().__init__() - self.name = name - def __repr__(self) -> str: return f"{self.name}" + def __init__(self, name: str): + super().__init__() + 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 program(self, items: List[Decl]) -> List[Decl]: return items - # interfaces - def iface(self, items: List[Any]) -> Iface: - [name, fields] = items - return Iface(name, fields) - def iface_field(self, items: List[str]) -> IfaceField: - [name, ty] = items - return IfaceField(name, ty) - def iface_ref(self, items: List[str]) -> str: return items[0] - def iface_refs(self, items: List[IfaceRef]) -> List[IfaceRef]: return items + # interfaces + def iface(self, items: List[Any]) -> Iface: + [name, fields] = items + return Iface(name, fields) + def iface_field(self, items: List[str]) -> IfaceField: + [name, ty] = items + return IfaceField(name, ty) + 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: - [name, ifaces, variants] = items - return Node(name, ifaces, variants) - def node_ref_name(self, items: List[str]) -> NodeRefByName: return NodeRefByName(items[0]) + # nodes + def node(self, items: List[Any]) -> 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: - [prod, equations] = items - return Variant(prod, equations) - def prod(self, items: List[Sym]) -> List[Sym]: return items + # variants + def variants(self, items: List[Variant]) -> List[Variant]: return items + def variant(self, items: List[Any]) -> Variant: + [prod, equations] = items + return Variant(prod, equations) + 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 - def equations(self, items: List[Equation]) -> List[Equation]: return items - def equation_semi(self, items: List[Equation]) -> Equation: return items[0] - def equation(self, items: List[Expr]) -> Equation: return Equation(items[0], items[1]) + # equations + def equations(self, items: List[Equation]) -> List[Equation]: return items + def equation_semi(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[Any]) -> Expr: - [left, right] = items - return ExprDot(left, right) - def expr_add(self, items: List[Expr]) -> Expr: - [left, right] = items - return ExprAdd(left, right) - def expr_mul(self, items: List[Expr]) -> Expr: - [left, right] = items - return ExprMul(left, right) - def expr_call(self, items: List[Expr]) -> Expr: - [func, args] = items - # TODO: args should be a list of exprs -_ - - return ExprCall(func, [args]) - def expr_name(self, items: List[str]) -> Expr: - return ExprName(items[0]) + # expr + def expr_dot(self, items: List[Any]) -> Expr: + [left, right] = items + return ExprDot(left, right) + def expr_add(self, items: List[Expr]) -> Expr: + [left, right] = items + return ExprAdd(left, right) + def expr_mul(self, items: List[Expr]) -> Expr: + [left, right] = items + return ExprMul(left, right) + def expr_call(self, items: List[Expr]) -> Expr: + [func, args] = items + # TODO: args should be a list of exprs -_ - + return ExprCall(func, [args]) + def expr_name(self, items: List[str]) -> Expr: + return ExprName(items[0]) - def sep_trail(self, items: List[Tree]) -> List[T]: - return list(map(lambda it: cast(T, it), items)) + 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) + def ident(self, items: List[Token]) -> str: return cast(str, items[0].value) diff --git a/aggen.py b/aggen.py index d6b0b22..e7db731 100644 --- a/aggen.py +++ b/aggen.py @@ -9,132 +9,132 @@ global i i = 0 class GenResult: - def __init__(self, pd: str = "", ex: str = ""): - self.parser_data = pd - self.extra = ex + def __init__(self, pd: str = "", ex: str = ""): + self.parser_data = pd + self.extra = ex def gen(program: List[Decl]) -> GenResult: - res = GenResult() - def gen(prefix: str = "", suffix: str = "") -> str: - 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}" + res = GenResult() + def gen(prefix: str = "", suffix: str = "") -> str: + 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}" - # builtins - builtins: Dict[str, str] = { - "parseInt": "", - } + # builtins + builtins: Dict[str, str] = { + "parseInt": "", + } - # collect a list of name -> iface declarations - ifaces: Dict[str, Iface] = dict( - map(lambda c: (c.name, cast(Iface, c)), - filter(lambda c: isinstance(c, Iface), - program))) - - # list of node -> iface mappings - what_ifaces: Dict[str, Set[str]] = dict() - what_fields: Dict[str, Dict[str, str]] = dict() - for node in filter(lambda c: isinstance(c, Node), program): - node = cast(Node, node) - # all_fields = dict() - what_ifaces[node.name] = set(node.ifaces) - this_fields = dict() - for iface in node.ifaces: - fields = ifaces[iface].fields - for field in fields: - if field.name in this_fields: - raise Exception("duplicate field name") - this_fields[field.name] = field.ty - what_fields[node.name] = this_fields - print("what_ifaces:", what_ifaces) - print("what_fields:", what_fields) + # collect a list of name -> iface declarations + ifaces: Dict[str, Iface] = dict( + map(lambda c: (c.name, cast(Iface, c)), + filter(lambda c: isinstance(c, Iface), + program))) + + # list of node -> iface mappings + what_ifaces: Dict[str, Set[str]] = dict() + what_fields: Dict[str, Dict[str, str]] = dict() + for node in filter(lambda c: isinstance(c, Node), program): + node = cast(Node, node) + # all_fields = dict() + what_ifaces[node.name] = set(node.ifaces) + this_fields = dict() + for iface in node.ifaces: + fields = ifaces[iface].fields + for field in fields: + if field.name in this_fields: + raise Exception("duplicate field name") + this_fields[field.name] = field.ty + what_fields[node.name] = this_fields + print("what_ifaces:", what_ifaces) + print("what_fields:", what_fields) - # a high-level dictionary of productions; this has sub-productions - # that should be further expanded at a later step before converting - # into lark code - productions_hi: Dict[str, Union[str, List[str]]] = dict() + # a high-level dictionary of productions; this has sub-productions + # that should be further expanded at a later step before converting + # into lark code + productions_hi: Dict[str, Union[str, List[str]]] = dict() - # TODO: this should probably not be inlined here, but i'll move it - # out once i get more info into the 'env' - def collect_required_thunks(env: List[Tuple[str, NodeRef]], expr: Expr) -> Dict[str, str]: - names = dict(env) - print(f"collect_required_thunks({expr})", expr.__class__) - if isinstance(expr, ExprDot): - return collect_required_thunks(env, expr.left) - elif isinstance(expr, ExprMul): - a = collect_required_thunks(env, expr.left) - b = collect_required_thunks(env, expr.right) - a.update(b) - return a - elif isinstance(expr, ExprAdd): - a = collect_required_thunks(env, expr.left) - b = collect_required_thunks(env, expr.right) - a.update(b) - return a - elif isinstance(expr, ExprCall): - return collect_required_thunks(env, expr.func) - elif isinstance(expr, ExprName): - if expr.name not in names and expr.name not in builtins: - raise Exception(f"unbound name '{expr.name}'") - return dict() - raise Exception(f"unhandled {expr.__class__}") + # TODO: this should probably not be inlined here, but i'll move it + # out once i get more info into the 'env' + def collect_required_thunks(env: List[Tuple[str, NodeRef]], expr: Expr) -> Dict[str, str]: + names = dict(env) + print(f"collect_required_thunks({expr})", expr.__class__) + if isinstance(expr, ExprDot): + return collect_required_thunks(env, expr.left) + elif isinstance(expr, ExprMul): + a = collect_required_thunks(env, expr.left) + b = collect_required_thunks(env, expr.right) + a.update(b) + return a + elif isinstance(expr, ExprAdd): + a = collect_required_thunks(env, expr.left) + b = collect_required_thunks(env, expr.right) + a.update(b) + return a + elif isinstance(expr, ExprCall): + return collect_required_thunks(env, expr.func) + elif isinstance(expr, ExprName): + if expr.name not in names and expr.name not in builtins: + raise Exception(f"unbound name '{expr.name}'") + return dict() + raise Exception(f"unhandled {expr.__class__}") - for node in filter(lambda c: isinstance(c, Node), program): - 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 + for node in filter(lambda c: isinstance(c, Node), program): + 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 - print(node.name, node.ifaces) + 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 + 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) + prod_name = gen(node.name) + print(prod_name) - # create an environment for checking the equations based on - # the production - env: List[Tuple[str, NodeRef]] = list() - for sym in variant.prod: - if isinstance(sym, SymRename): - env.append((sym.name, sym.ty)) - print(env) - - # 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: - eq_name = gen(f"eq_{node.name}") - thunk_name = gen(f"thunk_{node.name}") + # create an environment for checking the equations based on + # the production + env: List[Tuple[str, NodeRef]] = list() + for sym in variant.prod: + if isinstance(sym, SymRename): + env.append((sym.name, sym.ty)) + print(env) + + # 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: + eq_name = gen(f"eq_{node.name}") + thunk_name = gen(f"thunk_{node.name}") - print("RHS", eq.rhs, eq.rhs.id) - collect_required_thunks(copy.deepcopy(env), eq.rhs) + print("RHS", eq.rhs, eq.rhs.id) + collect_required_thunks(copy.deepcopy(env), eq.rhs) - 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 + 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)}" + # 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 \ No newline at end of file + return res \ No newline at end of file diff --git a/agmain.py b/agmain.py index 4eb5614..ff08031 100644 --- a/agmain.py +++ b/agmain.py @@ -9,47 +9,47 @@ from aggen import * p = Lark(open("grammar.lark").read(), start="program", parser="lalr") if __name__ == "__main__": - with open("arith.ag") as f: - data = f.read() + with open("arith.ag") as f: + data = f.read() - cst = p.parse(data) + cst = p.parse(data) - trans = Parser() - ast = trans.transform(cst) - print("ast", ast) + trans = Parser() + ast = trans.transform(cst) + print("ast", ast) - res = gen(ast) + res = gen(ast) - if not os.path.exists("gen"): - os.makedirs("gen") - with open("gen/arith.py", "w") as f: - fmt_str = textwrap.dedent(""" - __all__ = ["parse"] - from typing import Generic, TypeVar, Optional, Callable, Dict, Any - from lark import Lark, Transformer - T = TypeVar('T') - builtins: Dict[str, Any] = {{ - "parseInt": lambda s: int(s) - }} - class Thunk(Generic[T]): - ''' A thunk represents a value that may be computed lazily. ''' - 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 - parser = Lark('''start: - {pd}''') - class Trans(Transformer[None]): - pass - {ex} - def parse(input: str) -> None: - print(input) - """) - f.write(fmt_str.format(pd=res.parser_data, ex=res.extra)) + if not os.path.exists("gen"): + os.makedirs("gen") + with open("gen/arith.py", "w") as f: + fmt_str = textwrap.dedent(""" + __all__ = ["parse"] + from typing import Generic, TypeVar, Optional, Callable, Dict, Any + from lark import Lark, Transformer + T = TypeVar('T') + builtins: Dict[str, Any] = {{ + "parseInt": lambda s: int(s) + }} + class Thunk(Generic[T]): + ''' A thunk represents a value that may be computed lazily. ''' + 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 + parser = Lark('''start: + {pd}''') + class Trans(Transformer[None]): + 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 + mod = importlib.import_module("gen.arith") + mod.parse("1 + 2 * 3") # type: ignore diff --git a/arith.ag b/arith.ag index a1008ac..f592fcd 100644 --- a/arith.ag +++ b/arith.ag @@ -1,13 +1,13 @@ iface HasValue { - val: int, + val: int, } node Expr : HasValue { - "+" => { - self.val = l.val + r.val * l.val; - } - "*" => { - self.val = l.val * r.val; - } - => { self.val = parseInt(n); } + "+" => { + self.val = l.val + r.val * l.val; + } + "*" => { + self.val = l.val * r.val; + } + => { self.val = parseInt(n); } } diff --git a/let.ag b/let.ag index 2139de7..ad02dc0 100644 --- a/let.ag +++ b/let.ag @@ -1,25 +1,25 @@ iface HasEnv { - env: Map, + env: Map, } iface HasVal { - val: str, + val: str, } alias Ident = /([a-zA-Z][a-zA-Z0-9_]*)|(_[a-zA-Z0-9_]+)/ node Expr : HasEnv + HasVal { - "let" "=" "in" => { - body.env = self.env.with(name, val); - self.val = body.val; - } - => { - // 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); - } - => { - self.val = string; - } + "let" "=" "in" => { + body.env = self.env.with(name, val); + self.val = body.val; + } + => { + // 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); + } + => { + self.val = string; + } } diff --git a/old.py b/old.py index 82e7ce0..cc7a5e3 100644 --- a/old.py +++ b/old.py @@ -3,33 +3,33 @@ from typing import Generic, TypeVar, Optional, Callable T = TypeVar("T") class Thunk(Generic[T]): - value: Optional[T] + value: Optional[T] - def __init__(self, func: Callable[[], T]): - self.func = func - self.value = None + 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 + def get(self) -> T: + if self.value is None: + self.value = self.func() + return self.value class Node: - value: Thunk[int] + value: Thunk[int] class Add(Node): - def __init__(self, left: Node, right: Node): - self.value = Thunk(lambda: left.value.get() + right.value.get()) + 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()) + 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) + 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()) + tree = Add(Mul(Lit(3), Lit(4)), Lit(5)) + print(tree.value.get())