a
This commit is contained in:
parent
e43175c53b
commit
d63dc1292f
4 changed files with 75 additions and 26 deletions
15
docs/default.nix
Normal file
15
docs/default.nix
Normal 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
|
||||||
|
'';
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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}
|
||||||
return res
|
{assigns_str}
|
||||||
return Thunk(inner)
|
return res
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
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
|
||||||
|
|
Loading…
Reference in a new issue