from .Lexer import Lexer
from .cogs.LexerToken import Token
from refyre.graph import FileGraphNode
from pathlib import Path
from refyre.config import logger
# Utility stack (LIFO) data stucture methods
[docs]
def push(stack, item):
stack.append(item)
[docs]
def pop(stack):
return stack.pop()
[docs]
class Parser:
'''
Refyre's static parser
'''
[docs]
def parse(tokens, INF=-10, ):
# Ensure that the tokens spacing is proper, i.e no crazy tabs to the front
assert tokens[0].tab_level == 0, "There should be no tabs for the first line"
for i in range(1, len(tokens)):
assert tokens[i].tab_level - tokens[i -
1].tab_level <= 1, f"Tab difference {i} {tokens[i].tab_level} and {i - 1} {tokens[i - 1].tab_level} is too high."
stack = []
# Push our virtual top
push(stack, (FileGraphNode(is_root=True, children=[]), INF))
for tok in tokens:
cur = []
# Resolve all the nodes with tab_level lower
while tok.tab_level < stack[-1][1]:
top = pop(stack)
# Grab all the nodes with the same level
while stack[-1][1] == top[1]:
p = pop(stack)[0]
cur = [p] + cur
# Append top last to preserve ordering - THIS IS CRUCIAL TO PRESERVE USER INTENT
cur.append(top[0])
# Now, we know that the next node, whatever it is, must have a lower level
stack[-1][0].add_children(cur)
# Clear the list
cur.clear()
logger.debug(f'imports {tok.imports} {tok.link}')
push(stack, (FileGraphNode(children=list([]), pattern=tok.pattern, directory=tok.directory, type=tok.dirtype, name=tok.name, is_root=Path(tok.directory).exists(
), flags=tok.flags, serialize=tok.serialize, imports=tok.imports, mode=tok.mode, link=tok.link, alias=tok.alias, limit=tok.limit), tok.tab_level))
# Compress the remainder of the stack
while len(stack) > 1:
top = pop(stack)
cur = []
while top[1] == stack[-1][1]:
# Grab all the nodes with the same level
p = pop(stack)[0]
cur = [p] + cur
# Append top last to preserve ordering - THIS IS CRUCIAL TO PRESERVE USER INTENT
cur.append(top[0])
# Now, we know that the next node, whatever it is, must have a lower level
stack[-1][0].add_children(cur)
# Clear the list
cur.clear()
assert len(
stack) == 1 and stack[0][1] == INF, "Improper root node, something went wrong in the parsing algorithm"
return stack[0][0]
def __new__(self, tokens):
assert type(tokens) == list and all(
[type(t) == Token for t in tokens]), "Invalid type found from Lexer output; something's going wrong."
return Parser.parse(tokens)