Skip to content

Commit

Permalink
Merge pull request #168 from LibertyAces/refactoring/includedeclarative
Browse files Browse the repository at this point in the history
Implement IncludeNeeded strategy in declarative builder.
  • Loading branch information
PremyslCerny authored Apr 28, 2023
2 parents 4e3593f + 979f54f commit 9e1da46
Showing 1 changed file with 80 additions and 85 deletions.
165 changes: 80 additions & 85 deletions bspump/declarative/builder.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import logging
import inspect
import asyncio

import yaml

Expand All @@ -20,6 +19,13 @@
###


class IncludeNeeded(Exception):

def __init__(self, identifier):
super().__init__()
self.Identifier = identifier


class ExpressionBuilder(object):
"""
Builds an expression from configuration.
Expand All @@ -40,6 +46,9 @@ def __init__(self, app, library=None, include_paths=None):
self.IncludePaths = include_paths
assert isinstance(include_paths, list)

# Cache for loaded includes during the parsing
self.LoadedIncludes = {}

# Register the common expression module
from . import expression
self.register_module(expression)
Expand Down Expand Up @@ -80,84 +89,91 @@ async def parse(self, declaration, source_name=None):
:param source_name:
:return:
"""

self.Identifier = None

if isinstance(declaration, str) and declaration.startswith('---'):
pass

else:
self.Identifier = declaration
declaration = await self.read(declaration)

loader = yaml.Loader(declaration)
if source_name is not None:
loader.name = source_name
while True:

# Register the constructor for each registered expression class
for name in self.ExpressionClasses:
loader.add_constructor("!{}".format(name), self._constructor)
loader = yaml.Loader(declaration)
if source_name is not None:
loader.name = source_name

loader.add_constructor("!INCLUDE", self._construct_include)
loader.add_constructor("!CONFIG", self._construct_config)
# Register the constructor for each registered expression class
for name in self.ExpressionClasses:
loader.add_constructor("!{}".format(name), self._constructor)

loader.add_constructor("tag:yaml.org,2002:ui256", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:ui128", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:ui64", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:ui32", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:ui16", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:ui8", self._construct_scalar)
loader.add_constructor("!INCLUDE", self._construct_include)
loader.add_constructor("!CONFIG", self._construct_config)

loader.add_constructor("tag:yaml.org,2002:si256", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:si128", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:si64", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:si32", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:si16", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:si8", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:ui256", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:ui128", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:ui64", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:ui32", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:ui16", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:ui8", self._construct_scalar)

loader.add_constructor("tag:yaml.org,2002:fp128", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:fp64", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:fp32", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:fp16", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:si256", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:si128", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:si64", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:si32", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:si16", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:si8", self._construct_scalar)

loader.add_constructor("tag:yaml.org,2002:str", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:fp128", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:fp64", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:fp32", self._construct_scalar)
loader.add_constructor("tag:yaml.org,2002:fp16", self._construct_scalar)

expressions = []
try:
# Build syntax trees for each expression
while loader.check_data():
expression = loader.get_data()
expression = await self._load_includes(expression)
loader.add_constructor("tag:yaml.org,2002:str", self._construct_scalar)

try:
expressions = []

# Run initialize for the expression and any instance inside
for parent, key, obj in self._walk(expression):
# Build syntax trees for each expression
while loader.check_data():
expression = loader.get_data()

if isinstance(obj, str) and obj.startswith("<INCLUDE>"):
obj = (await self.parse(obj[9:], "<INCLUDE>"))[0]
setattr(parent, key, obj)
# Run initialize for the expression and any instance inside
for parent, key, obj in self._walk(expression):

if not isinstance(obj, Expression):
continue
if not isinstance(obj, Expression):
continue

if source_name != "<INCLUDE>":
if source_name != "<INCLUDE>":

if isinstance(obj, SELF):
# Implement a self-reference or Y-Combinator
obj.initialize(expression)
else:
obj.initialize()
if isinstance(obj, SELF):
# Implement a self-reference or Y-Combinator
obj.initialize(expression)
else:
obj.initialize()

expressions.append(expression)
expressions.append(expression)

except yaml.scanner.ScannerError as e:
raise DeclarationError("Syntax error in declaration: {}".format(e))
except yaml.scanner.ScannerError as e:
raise DeclarationError("Syntax error in declaration: {}".format(e))

except yaml.constructor.ConstructorError as e:
raise DeclarationError("Unknown declarative expression: {}".format(e))
except yaml.constructor.ConstructorError as e:
raise DeclarationError("Unknown declarative expression: {}".format(e))

finally:
loader.dispose()
except IncludeNeeded as e:
# If include is needed, load its declaration to the loaded include cache
include_declaration = await self.read(e.Identifier)
parsed_declaration = await self.parse(include_declaration, "<INCLUDE>")

return expressions
# Include can be only one expression
self.LoadedIncludes[e.Identifier] = parsed_declaration[0]
continue

finally:
loader.dispose()

return expressions


async def parse_ext(self, declaration, source_name=None):
Expand Down Expand Up @@ -223,40 +239,16 @@ def _walk(self, expression):
raise NotImplementedError("Walk not implemented for '{}'.".format(expression))


async def _load_includes(self, expression):

if isinstance(expression, Expression):
return expression

if isinstance(expression, str):

if expression.startswith("<INCLUDE>"):
expression = (await self.parse(expression[9:], "<INCLUDE>"))[0]

return expression

if isinstance(expression, dict):

for _key, _value in expression.items():
expression[_key] = await self._load_includes(_value)

return expression

if isinstance(expression, (list, set)):

for _n, _value in enumerate(expression):
expression[_n] = await self._load_includes(_value)

return expression

return expression


def _construct_include(self, loader: yaml.Loader, node: yaml.Node):
"""Include will be done later using await."""
"""Include file referenced at node."""

identifier = loader.construct_scalar(node)
return "<INCLUDE>{}".format(identifier)

try:
return self.LoadedIncludes[identifier]

except KeyError:
raise IncludeNeeded(identifier)


def _construct_config(self, loader: yaml.Loader, node: yaml.Node):
Expand Down Expand Up @@ -294,6 +286,9 @@ def _constructor(self, loader, node):
obj.Node = node
return obj

except IncludeNeeded as e:
raise e

except TypeError as e:
raise DeclarationError("Type error {}\n{}\n".format(e, node.start_mark))

Expand Down

0 comments on commit 9e1da46

Please sign in to comment.