from typing import Iterable, Union, Mapping, TypeVar, List import re from parser import parser class HeckException (Exception): ... class HeckParseException(HeckException): ... HeckValue = TypeVar("HeckElement") | str | int | float class HeckElement: name: str children: Iterable[TypeVar] values: Iterable[HeckValue] attributes: Mapping[str, HeckValue] def __init__(self): self.children = [] self.values = [] self.attributes = dict() self.name = "" self.unparsed = False def __str__(self): k='' if self.unparsed: k='Unparsed ' return f"" def __repr__(self): return self.__str__() # COMMENT ::= # .*$ # ATOM ::= [A-Za-z_][A-Za-z0-9_-]? # BASE10NUMBER ::= (-)?[0-9]+(\.)?[0-9]+([FLUIDCfluidc])? # BASE16NUMBER ::= 0x[0-9A-Fa-f]+ # NUMBER ::= () # STRING ::= "([^\"]*|(\\)|(\"))" # VALUE ::= (||) # VALUES ::= (\s+)? # ATTRIBUTENAME ::= # ATTRIBUTE ::= = # ATTRIBUTES ::= (\s+)? # SECTIONLABEL ::= # SECTION ::= %%%\s+\s+ # ELEMENTLABEL ::= [A-Za-z_][A-Za-z0-9!@#$%^&*()_+/\\-]? # ELEMENT ::= \s+(|) # LINE ::= ^(((>)*) |
| ) (|$) # ATOM = re.compile(r'[A-Za-z_][A-Za-z0-9_-]*') def get_element(ast: List) -> HeckElement: if not (ast[0] == 'element'): raise HeckParseException("Found a non-element where an element was expected.") elm = HeckElement() elm.name = ast[1]; for item in ast[2:]: if item[0] == 'values': elm.values = [x[1] for x in item[1:]] elif item[0] == 'attributes': elm.attributes.update({x[1]: x[2][1] for x in item[1:]}) return elm def load_heck(inp: Iterable[str]) -> HeckElement: MODE_INIT = 0 MODE_ELM = 1 MODE_UNPARSE = 2 rootelm = HeckElement() pelm = rootelm # parent for subelement rootelm.name = "__ROOT__" mode = MODE_INIT for idx, line in enumerate(inp): if mode == MODE_UNPARSE: if (line.startswith('%%%')): mode = MODE_INIT else: pelm.values.append(line) continue else: ast = parser.parse(line) if ast: if ast[0] == 'section': if ast[1] == 'heck': mode = MODE_ELM pelm = rootelm else: mode = MODE_UNPARSE pelm = HeckElement() rootelm.children.append(pelm) pelm.name = ast[1] pelm.unparsed = True else: if not mode == MODE_ELM: raise HeckParseException("Didn't find heck preamble, line {idx}") else: pelm.children.append(get_element(ast)) return rootelm TEST_HECK = """ %%% heck # Website! title "My Website" bold=True subtitle "Yep it's a website" scale 3.72 matrix 0 0 0 0 1 2 3 1 2 3 4 29394.2 tags hey man what are you doin %%% markdown # Some cheeky markdown to confuse our processing. All my page content goes here. """ if __name__ == "__main__": result = load_heck(TEST_HECK.split('\n')) print(result)