Source code for fbrelation.syntax.node
'''
Defines classes for parsing and compiling node declarations, which consist of
either a plain box name (indicating a macro input or output) or a box name and
node name separated by a dot::
<boxname.nodename|boxname>
'''
from fbrelation.utility import find
from fbrelation.exceptions import ParsingError, CompilationError
[docs]class NodeSyntax(object):
'''
Represents the abstract syntax for an animation node reference within a
connection declaration. Consists of a box name and an optional node name to
clarify which of the box's nodes is involved in the connection. If the node
name is blank, it is assumed that the box name by itself is sufficient to
deduce the node, as in the case of a macro input or output box.
'''
[docs] def __init__(self, boxName, nodeName):
'''
Initializes a new node syntax object to refer to some optionally named
node in a box with the given name.
'''
self.boxName = boxName
self.nodeName = nodeName
[docs] def __str__(self):
'''
Converts the syntax object into its raw string representation.
'''
if self.nodeName:
return '%s.%s' % (self.boxName, self.nodeName)
return self.boxName
[docs] def compile(self, boxes, isSrc):
'''
Compiles this node syntax structure into a :class:`.NodeDeclaration`
object as either a source or a destination node.
:param boxes: The list of compiled box declarations.
:param isSrc: If True, the node is a source node (i.e., on the left
side of the arrow in the connection declaration).
:returns: The newly created node declaration.
:raises: a :class:`.CompilationError` if any static checks fail.
'''
# Find the box declaration object that owns the node in question
box = find(lambda b: b.name == self.boxName, boxes)
if not box:
raise CompilationError(
'"%s" is not a valid box name.' % self.boxName)
# Ensure that the given box will compile with a node of the given name
if not box.supportsNode(self.nodeName):
raise CompilationError(
'"%s" is not a valid node name for the box named "%s".' %
(self.nodeName, self.boxName))
# Finally, create and return node declaration of the appropriate type
# based upon the type of box it belongs to
return box.createNodeDeclaration(self.nodeName, isSrc)
@classmethod
[docs] def parse(cls, text):
'''
Parses the given input text to produce a new NodeSyntax object.
:returns: the newly created syntax object.
:raises: a :class:`.ParsingError` if the syntax is invalid.
'''
# If we're given a non-dotted string, treat it as a macro input or
# output box with no explicitly specified node name
if '.' not in text:
return cls(text.strip(), '')
# Otherwise, split the string on the dot, which should result in a
# list with exactly two elements
tokens = text.split('.')
if len(tokens) != 2 or not tokens[0] or not tokens[1]:
raise ParsingError(
'"%s": Invalid syntax for a connection declaration. Expected '
'box name dot attribute name.' % text.strip())
# Construct a new NodeSyntax object from the pair
boxName, nodeName = tokens
return cls(boxName.strip(), nodeName.strip())