Remove old version.

This commit is contained in:
Cassowary 2024-02-08 21:14:21 -08:00
parent 7c98e6e895
commit 9b2f9b706c
6 changed files with 0 additions and 533 deletions

View File

@ -1,20 +0,0 @@
"""
Exceptions for HECKfile processing.
"""
class HeckException (BaseException):
"""
Base exception for HECKfile processing.
"""
class HeckParseException(HeckException):
"""
Raised for parse errors specifically.
"""
class HeckLexException(HeckException):
"""
Raised for lex errors specifically.
"""

View File

@ -1,119 +0,0 @@
import ply.lex as lex
"""
Lexical analyzer for HECKformat lines using PLY Lex.
"""
from .exceptions import HeckLexException
from typing import List, Optional
import string
tokens = ('ATOM', 'BASE10', 'BASE16', 'COMMENT', 'STRING', 'SECTION', 'ATTRIB', 'DEEP', 'ELEMENT')
# COMMENT ::= # .*$
# ATOM ::= [A-Za-z_][A-Za-z0-9_-]?
# BASE10NUMBER ::= (-)?[0-9]+(\.)?[0-9]+([FLUIDCfluidc])?
# BASE16NUMBER ::= 0x[0-9A-Fa-f]+
# NUMBER ::= (<BASE10NUMBER|BASE16NUMBER>)
# STRING ::= "([^\"]*|(\\)|(\"))"
# VALUE ::= (<ATOM>|<STRING>|<NUMBER>)
# VALUES ::= <VALUE>(\s+<VALUES>)?
# ATTRIBUTENAME ::= <ATOM>
# ATTRIBUTE ::= <ATTRIBUTENAME>=<VALUE>
# ATTRIBUTES ::= <ATTRIBUTE>(\s+<ATTRIBUTES>)?
# SECTIONLABEL ::= <ATOM>
# SECTION ::= %%%\s+<SECTIONLABEL>\s+<ATTRIBUTES>
# ELEMENTLABEL ::= [A-Za-z_][A-Za-z0-9!@#$%^&*()_+/\\-]?
# ELEMENT ::= <ELEMENTLABEL>\s+(<VALUES>|<ATTRIBUTES>)
# LINE ::= ^(((>)*<ELEMENT>) | <SECTION> | <COMMENT>) (<COMMENT>|$)
t_ignore = string.whitespace
t_DEEP = r'^(>)+'
t_BASE16 = r'0x[0-9A-Fa-f]+'
t_SECTION = r'^%%%\s'
t_ATTRIB = '='
t_ELEMENT = r'[A-Za-z_.][A-Za-z0-9.!@\$%^&*()_+/\\-]*'
def t_ATOM(token: lex.LexToken):
r'[A-Za-z_$][A-Za-z0-9_.-]*'
if token.value in ('true', 'True'):
token.value = True
elif token.value in ('false', 'False'):
token.value = False
return token
def t_BASE10(token: lex.LexToken):
r'(-)?[0-9]+(\.?[0-9]+)?([FLUIDCfluidc])?(\b|$)'
# python numbers are Very Flexible so we ignore typespec
vstr = token.value
if vstr[-1] in 'FLUIDCfluidc':
vstr = vstr[:-1]
if '.' in vstr:
token.value = float(vstr)
else:
token.value = int(vstr)
return token
def t_COMMENT(token: lex.LexToken):
r'\#\s?.*$'
...
def t_STRING(token: lex.LexToken):
r'"[^"]*"'
token.value = token.value[1:-1] # substring to strip double quotes
return token
def t_error(token: lex.LexToken):
print(f"{token.lineno} Unexpected character '{token.value[0]}' at position {token.lexpos}.")
print('... ' + token.value)
print(' ^')
# token.lexer.skip(1)
lexer = lex.lex()
def lex_line(line: str, lineno: int=0) -> List[lex.LexToken]:
"""
Return a list of tokens for a particular HECKformat file line.
"""
lexer.lineno = lineno
try:
lexer.input(line)
tokens = []
while True:
tok = lexer.token()
if tok:
tokens.append(tok)
else:
break
return tokens
except lex.LexError as inst:
# fixme raise a HeckFormat exception
raise HeckLexException from inst
TEST_STRINGS = [
'"hi yo123 123xyz #foo" 123xyz 123.223 1f abcd123 123abc $foo "hello world" #foo',
'1.23f',
'"hello world!" atom utehuteu tnhoeun_etuhenuoh',
'"hi yo123 123xyz #foo" xyz 123.223 1f abcd123 abc $foo "hello world" #foo',
'%%% heck',
'%%% markdown foo=bar',
'element 1.2 1.3 1.4 attrib="string value for attribute"',
'> element 5 4 3 2.5',
]
if __name__ == "__main__":
for idx, test in enumerate(TEST_STRINGS):
print(f"Line {idx}: '{test}'")
try:
for token in lex_line(test, idx):
print(' ' + str(token))
except Exception as inst:
print(f'Error in line.')

View File

@ -1,226 +0,0 @@
from typing import Iterable, Union, Mapping, TypeVar, List, TextIO
import re
from .parser import parser
from .exceptions import HeckParseException
HeckValue = TypeVar("HeckElement") | str | int | float
class HeckElement:
"""
Container for a tree of HECKformat elements.
"""
name: str
"""The name of the element, either __ROOT__ for top level or whatever is specified in file."""
children: Iterable[TypeVar]
"""The children of the element."""
values: Iterable[HeckValue]
"""One or more values associated with the element."""
attributes: Mapping[str, HeckValue]
"""Zero or more attributes associated with the element as a key-value pair."""
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"<HeckElement {k}{self.name} c={self.children} v={self.values} a={self.attributes}>"
def __repr__(self):
return self.__str__()
def to_struct(self) -> Mapping[str, Union[int, float, str, Mapping, List]]:
"""
Convert this HeckElement tree to a Python structure. The structure is a dictionary keyed by element name, where
the values are a list of each tree under that name, in order of their declaration in the tree, and futher, a
list of values.
For example:
```
%%% heck
a b c
a c d
```
turns into:
{'a': [['b', 'c'], ['c', 'd']]}
Subelements are treated as a dictionary object added to the end of each value.
For example:
```
%%% heck
a b
> c d
a e
> f g
```
turns into:
{'a': [['b'], {'c': [['d']]}, ['e', {'f': [['g']]}]]}
"""
def to_dict(self, merge=False) -> Mapping[str, Union[int, float, str, Mapping, List]]:
"""
As with `to_struct`, but attempts to merge all keys together at each level.
For example:
```
%%% heck
a b c
a c d
```
turns into (with merge set to True):
{'a': ['b', 'c', 'c', 'd']}
or (with merge set to False):
{'a': ['c', 'd']}
For child elements, the list is replaced by a dictionary, and the values are stored in a special key '%%% values'
Thus:
```
%%% heck
a b
> c d
```
becomes:
{'a':{'%%%values': ['b'], 'c': ['d']}}
This cannot represent exactly the contents of the input tree, however it may be more convenient in many use
cases where repeated elements of the same key are not allowed, or if keys are being treated as unique.
"""
def _get_element(ast: List) -> HeckElement:
"""
Get an element from an element AST from the parser.
"""
if not (ast[0] == 'element'):
raise HeckParseException(f"Found a non-element where an element was expected. {ast}")
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:
"""
Load a HECKformat into a tree of HeckElements from a list of lines from the file.
"""
MODE_INIT = 0
MODE_ELM = 1
MODE_UNPARSE = 2
rootelm = HeckElement()
pelm = [rootelm] # parent for subelement
pdepth = 0
depth = 0
rootelm.name = "__ROOT__"
mode = MODE_INIT
for idx, line in enumerate(inp):
if mode == MODE_UNPARSE:
if (line.startswith('%%%')):
mode = MODE_INIT
else:
pelm[-1].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[-1])
pelm[-1].name = ast[1]
pelm[-1].unparsed = True
else:
if not mode == MODE_ELM:
raise HeckParseException("Didn't find heck preamble, line {idx}")
else:
if ast[0] == 'deep':
# we're in a subitem
depth = ast[1]
if (depth > pdepth):
# are we deeper than last time?
try:
pelm.append(pelm[-1].children[-1])
except:
raise HeckParseException("Tried to go deeper without a previous element, line {idx}")
elif (depth < pdepth):
# are we shallower than last time?
pelm.pop()
if (not len(pelm)):
raise HeckParseException("Tried to go shallower while already shallow, line {idx}")
ast = ast[2]
pdepth = depth
elif (pdepth > 0):
# we're no longer deep, just pop up to the top
pdepth = 0
pelm = [rootelm]
pelm[-1].children.append(_get_element(ast))
return rootelm
def load(infile: TextIO) -> HeckElement:
return load_heck(infile.readlines())
def loads(ins: str) -> HeckElement:
return load_heck(re.split(r'\n|\r|\r\n', ins))
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
> more tag tag tag 1 2 3
>> we can go deeper
>>> we can go even deeper
test
> _val 1
> _val 2
> _val 3
valueless
_more.orless complexelement
.yooooo
boolean True
%%% 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)

View File

@ -1,118 +0,0 @@
import ply.yacc as yacc
"""
Parser for HECKformat lines using PLY Parser.
"""
from .lexer import tokens
def p_value(p):
"""
value : BASE16
| BASE10
| STRING
| ATOM
"""
#print(p[0], p[1])
p[0] = ("value", p[1])
def p_elm(p):
"""
elm : ATOM
| ELEMENT
"""
p[0] = p[1]
def p_attribute(p):
"""attribute : ATOM ATTRIB value"""
# print(p[0], p[1])
p[0] = ("attribute", p[1], p[3])
def p_attributes(p):
"""
attributes : attributes attribute
attributes : attribute
"""
if len(p) == 2:
p[0] = ["attributes", p[1]]
else:
p[0] = p[1]
p[0].append(p[2])
def p_section(p):
"""
section : SECTION elm
| SECTION elm attributes
"""
if (len(p) == 3):
p[0] = ("section", p[2])
else:
p[0] = ("section", p[2], p[3])
def p_values(p):
"""
values : values value
values : value
"""
if len(p) == 2:
p[0] = ["values", p[1]]
else:
p[0] = p[1]
p[0].append(p[2])
def p_element(p):
"""
element : elm values
| elm values attributes
| elm attributes
| elm
"""
# print(len(p))
if len(p) <= 2:
p[0] = ["element", p[1]]
else:
p[0] = ["element", p[1], p[2]]
if (len(p) == 4):
p[0].append(p[3])
def p_statement(p):
"""
statement : element
| DEEP element
| section
"""
if (len(p) > 2):
p[0] = ('deep', len(p[1]), p[2])
else:
p[0] = p[1]
def p_error(p):
if not p:
return
else:
print(f"Syntax error {p}")
parser = yacc.yacc(start="statement")
TEST_STRING = [
'%%% heck',
'%%% heck foo=bar',
'%%% heck bar=-5l quux="hello! how are you today?" fred=69 barney=nice',
'title "My website!"',
'zoom 5.73',
'tags yo fresh',
'dumper 1 2 3 4 5 6 7 8 9 dumpped=True',
'> big_dumper 32 23 384848',
'>> deep_dumper 1 2 3 a=false'
]
if __name__ == "__main__":
for test in TEST_STRING:
print(parser.parse(test))

View File

@ -1,50 +0,0 @@
# parsetab.py
# This file is automatically generated. Do not edit.
# pylint: disable=W,C,R
_tabversion = '3.10'
_lr_method = 'LALR'
_lr_signature = 'statementATOM ATTRIB BASE10 BASE16 COMMENT DEEP ELEMENT SECTION STRING\n value : BASE16\n | BASE10\n | STRING\n | ATOM\n \n elm : ATOM\n | ELEMENT\n attribute : ATOM ATTRIB value\n attributes : attributes attribute\n attributes : attribute\n \n section : SECTION elm\n | SECTION elm attributes\n \n values : values value\n values : value\n \n element : elm values\n | elm values attributes\n | elm attributes\n | elm\n \n statement : element\n | DEEP element\n | section\n '
_lr_action_items = {'DEEP':([0,],[3,]),'SECTION':([0,],[6,]),'ATOM':([0,3,5,6,7,8,10,11,12,13,14,15,16,17,18,19,20,21,23,24,25,26,],[7,7,17,7,-5,-6,17,22,-13,-9,-1,-2,-3,-4,22,22,-12,-8,25,22,-4,-7,]),'ELEMENT':([0,3,6,],[8,8,8,]),'$end':([1,2,4,5,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,24,25,26,],[0,-18,-20,-17,-5,-6,-19,-14,-16,-13,-9,-1,-2,-3,-4,-10,-15,-12,-8,-11,-4,-7,]),'BASE16':([5,7,8,10,12,14,15,16,17,20,23,],[14,-5,-6,14,-13,-1,-2,-3,-4,-12,14,]),'BASE10':([5,7,8,10,12,14,15,16,17,20,23,],[15,-5,-6,15,-13,-1,-2,-3,-4,-12,15,]),'STRING':([5,7,8,10,12,14,15,16,17,20,23,],[16,-5,-6,16,-13,-1,-2,-3,-4,-12,16,]),'ATTRIB':([17,22,],[23,23,]),}
_lr_action = {}
for _k, _v in _lr_action_items.items():
for _x,_y in zip(_v[0],_v[1]):
if not _x in _lr_action: _lr_action[_x] = {}
_lr_action[_x][_k] = _y
del _lr_action_items
_lr_goto_items = {'statement':([0,],[1,]),'element':([0,3,],[2,9,]),'section':([0,],[4,]),'elm':([0,3,6,],[5,5,18,]),'values':([5,],[10,]),'attributes':([5,10,18,],[11,19,24,]),'value':([5,10,23,],[12,20,26,]),'attribute':([5,10,11,18,19,24,],[13,13,21,13,21,21,]),}
_lr_goto = {}
for _k, _v in _lr_goto_items.items():
for _x, _y in zip(_v[0], _v[1]):
if not _x in _lr_goto: _lr_goto[_x] = {}
_lr_goto[_x][_k] = _y
del _lr_goto_items
_lr_productions = [
("S' -> statement","S'",1,None,None,None),
('value -> BASE16','value',1,'p_value','parser.py',11),
('value -> BASE10','value',1,'p_value','parser.py',12),
('value -> STRING','value',1,'p_value','parser.py',13),
('value -> ATOM','value',1,'p_value','parser.py',14),
('elm -> ATOM','elm',1,'p_elm','parser.py',22),
('elm -> ELEMENT','elm',1,'p_elm','parser.py',23),
('attribute -> ATOM ATTRIB value','attribute',3,'p_attribute','parser.py',27),
('attributes -> attributes attribute','attributes',2,'p_attributes','parser.py',34),
('attributes -> attribute','attributes',1,'p_attributes','parser.py',35),
('section -> SECTION elm','section',2,'p_section','parser.py',46),
('section -> SECTION elm attributes','section',3,'p_section','parser.py',47),
('values -> values value','values',2,'p_values','parser.py',56),
('values -> value','values',1,'p_values','parser.py',57),
('element -> elm values','element',2,'p_element','parser.py',68),
('element -> elm values attributes','element',3,'p_element','parser.py',69),
('element -> elm attributes','element',2,'p_element','parser.py',70),
('element -> elm','element',1,'p_element','parser.py',71),
('statement -> element','statement',1,'p_statement','parser.py',84),
('statement -> DEEP element','statement',2,'p_statement','parser.py',85),
('statement -> section','statement',1,'p_statement','parser.py',86),
]