This commit is contained in:
Michael Zhang 2021-10-04 10:40:28 -05:00
parent e43175c53b
commit d63dc1292f
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
4 changed files with 75 additions and 26 deletions

15
docs/default.nix Normal file
View file

@ -0,0 +1,15 @@
{ stdenvNoCC, nix-gitignore, sphinx, furo }:
stdenvNoCC.mkDerivation {
name = "agtest-docs";
src = nix-gitignore.gitignoreSource [ ../.gitignore ] ./..;
buildInputs = [ sphinx furo ];
buildPhase = ''
make -C docs html
'';
installPhase = ''
cp -r docs/_build/html $out
'';
}

View file

@ -13,11 +13,14 @@
myPkgs = rec { myPkgs = rec {
agtest = pythonPkgs.callPackage ./. {}; agtest = pythonPkgs.callPackage ./. {};
agtest-docs = pythonPkgs.callPackage ./docs {};
}; };
in in
{ rec {
packages = flake-utils.lib.flattenTree myPkgs; packages = flake-utils.lib.flattenTree myPkgs;
defaultPackage = packages.agtest;
devShell = pkgs.mkShell { devShell = pkgs.mkShell {
packages = with pythonPkgs; [ packages = with pythonPkgs; [
black black

View file

@ -5,6 +5,7 @@ from re import Pattern
def unescape(s: str) -> str: def unescape(s: str) -> str:
""" Extracts the contents out of a quoted string """
q = s[0] q = s[0]
t = "" t = ""
i = 1 i = 1

View file

@ -4,12 +4,13 @@ import re
import copy import copy
import json import json
import sys import sys
import copy
from collections import defaultdict from collections import defaultdict
from agtest.ast import * from agtest.ast import *
def eprint(*args, **kwargs): def eprint(*args: Any, **kwargs: Any) -> None:
print(*args, file=sys.stderr, **kwargs) print(*args, file=sys.stderr, **kwargs)
@ -33,10 +34,11 @@ class NodeDesc:
class ParseEquation: class ParseEquation:
def __init__(self, name: str, syms: List[str], pyty: str, pycode: str): def __init__(self, name: str, syms: List[str], pyty: str, assigns: List[str], pycode: str):
self.name = name self.name = name
self.syms = syms self.syms = syms
self.pyty = pyty self.pyty = pyty
self.assigns = assigns
self.pycode = pycode self.pycode = pycode
@ -74,15 +76,23 @@ class GenResult:
s.append(code) s.append(code)
for equation in rules: for equation in rules:
assigns = []
for name, value in equation.assigns:
assigns.append(f"res.{name} = {value}")
assigns_str = "\n".join(assigns)
assigns_str = textwrap.indent(assigns_str, " ")
pycode = textwrap.indent(equation.pycode, " ")
code = textwrap.dedent( code = textwrap.dedent(
f""" """
def {equation.name}(self, items: Any) -> Thunk[{equation.pyty}]: def {equation.name}(self, items: Any) -> {equation.pyty}:
def inner() -> {equation.pyty}:
res = {equation.pyty}() res = {equation.pyty}()
{pycode}
{assigns_str}
return res return res
return Thunk(inner)
""" """
) )
code = code.format(equation=equation, assigns_str=assigns_str, pycode=pycode)
s.append(code) s.append(code)
if not s: if not s:
s = ["pass"] s = ["pass"]
@ -200,7 +210,7 @@ class GenResult:
class_fields = [] class_fields = []
for field_name, field_ty in self.what_fields[node_desc.name].items(): for field_name, field_ty in self.what_fields[node_desc.name].items():
class_fields.append(f"{field_name}: Thunk[{field_ty}]") class_fields.append(f"{field_name}: Thunk[{field_ty}]")
g = textwrap.indent("\n".join(class_fields), " ") class_fields_str = textwrap.indent("\n".join(class_fields), " ")
class_decl = textwrap.dedent( class_decl = textwrap.dedent(
""" """
@ -208,13 +218,45 @@ class GenResult:
{g} {g}
pass pass
""" """
).format(nonterminal=node_desc.nonterminal, g=g) ).format(nonterminal=node_desc.nonterminal, g=class_fields_str)
self.extra += class_decl self.extra += class_decl
# print(node_desc.name, node_desc.node.ifaces) # print(node_desc.name, node_desc.node.ifaces)
for variant in node_desc.node.variants: for variant in node_desc.node.variants:
v_class_name = gensym(f"{node_desc.nonterminal}_var") v_class_name = gensym(f"{node_desc.nonterminal}_var")
prod_name = gensym(node_desc.nonterminal + "_")
# figure out which of the symbols are inputs (aka contain data)
# vs. literals which only parse
# TODO: probably should also just make literals return their values
seq = []
inputs = []
renamed = dict()
for i, sym in enumerate(variant.prod):
isInput, n = self._resolve_production(sym)
var_name = f"inp_{n}_idx{i}"
if isInput:
inputs.append((i, n, var_name))
seq.append(n)
if isinstance(sym, SymRename):
renamed[sym.name] = i
for field in class_fields:
eprint("FIELD", field)
# generate assignments for codegen
input_fields = copy.deepcopy(class_fields)
assigns = []
for i, inp, var_name in inputs:
name = gensym(f"{v_class_name}_inp")
input_fields.append(f"{var_name}: Any = 0")
assigns.append((var_name, f"items[{i}]"))
class_fields_str = textwrap.indent("\n".join(input_fields), " ")
class_decl = textwrap.dedent( class_decl = textwrap.dedent(
""" """
class {v_class_name}({nonterminal}): class {v_class_name}({nonterminal}):
@ -222,25 +264,13 @@ class GenResult:
pass pass
""" """
).format( ).format(
v_class_name=v_class_name, nonterminal=node_desc.nonterminal, g=g v_class_name=v_class_name, nonterminal=node_desc.nonterminal, g=class_fields_str
) )
self.extra += class_decl self.extra += class_decl
prod_name = gensym(node_desc.nonterminal + "_")
# print("PRODUCTION", prod_name, variant.prod)
seq = []
inputs = []
for i, sym in enumerate(variant.prod):
isInput, n = self._resolve_production(sym)
if isInput:
inputs.append((i, n))
seq.append(n)
eprint("INPUTS", node_desc.nonterminal, inputs)
pycode = "" pycode = ""
self.parse_rules[node_desc.nonterminal].append( self.parse_rules[node_desc.nonterminal].append(
ParseEquation(prod_name, seq, v_class_name, pycode) ParseEquation(prod_name, seq, v_class_name, assigns, pycode)
) )
# create an environment for checking the equations based on the # create an environment for checking the equations based on the