mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
When the source code is invalid, this allows us to represent tokens that could not be used to form a valid syntax tree with more fidelity. This commit does not start using GarbageNodes yet, it just sets everything up for them.
122 lines
4.3 KiB
Python
122 lines
4.3 KiB
Python
from .Child import Child # noqa: I201
|
|
from .Utils import error
|
|
from .kinds import SYNTAX_BASE_KINDS, kind_to_type, lowercase_first_word
|
|
|
|
|
|
class Node(object):
|
|
"""
|
|
A Syntax node, possibly with children.
|
|
If the kind is "SyntaxCollection", then this node is considered a Syntax
|
|
Collection that will expose itself as a typedef rather than a concrete
|
|
subclass.
|
|
"""
|
|
|
|
def __init__(self, name, description=None, kind=None, traits=None,
|
|
children=[], element=None, element_name=None,
|
|
element_choices=None, omit_when_empty=False,
|
|
elements_separated_by_newline=False):
|
|
self.syntax_kind = name
|
|
self.element_name = element_name
|
|
self.swift_syntax_kind = lowercase_first_word(name)
|
|
self.name = kind_to_type(self.syntax_kind)
|
|
self.kind = kind
|
|
self.description = description
|
|
|
|
self.traits = traits or []
|
|
self.children = []
|
|
# Add implicitly generated GarbageNodes children in between any two
|
|
# defined children
|
|
if kind != 'SyntaxCollection':
|
|
for i in range(2 * len(children)):
|
|
if i % 2 == 0:
|
|
if i == 0:
|
|
name = 'GarbageBefore' + children[0].name
|
|
else:
|
|
name = 'GarbageBetween%sAnd%s' % \
|
|
(children[int(i / 2) - 1].name, children[int(i / 2)].name)
|
|
self.children.append(Child(
|
|
name,
|
|
kind='GarbageNodes',
|
|
collection_element_name=name,
|
|
is_optional=True
|
|
))
|
|
else:
|
|
self.children.append(children[int((i - 1) / 2)])
|
|
|
|
self.non_garbage_children = \
|
|
[child for child in children if not child.is_garbage_nodes()]
|
|
|
|
self.base_kind = kind
|
|
if self.base_kind == 'SyntaxCollection':
|
|
self.base_type = 'Syntax'
|
|
else:
|
|
self.base_type = kind_to_type(self.base_kind)
|
|
|
|
if self.base_kind not in SYNTAX_BASE_KINDS:
|
|
error("unknown base kind '%s' for node '%s'" %
|
|
(self.base_kind, self.syntax_kind))
|
|
|
|
self.omit_when_empty = omit_when_empty
|
|
self.collection_element = element or ""
|
|
# For SyntaxCollections make sure that the element_name is set.
|
|
assert(not self.is_syntax_collection() or element_name or element)
|
|
# If there's a preferred name for the collection element that differs
|
|
# from its supertype, use that.
|
|
self.collection_element_name = element_name or self.collection_element
|
|
self.collection_element_type = kind_to_type(self.collection_element)
|
|
self.collection_element_choices = element_choices or []
|
|
self.elements_separated_by_newline = elements_separated_by_newline
|
|
|
|
def is_base(self):
|
|
"""
|
|
Returns `True` if this node declares one of the base syntax kinds.
|
|
"""
|
|
return self.syntax_kind in SYNTAX_BASE_KINDS
|
|
|
|
def is_syntax_collection(self):
|
|
"""
|
|
Returns `True` if this node is a subclass of SyntaxCollection.
|
|
"""
|
|
return self.base_kind == "SyntaxCollection"
|
|
|
|
def requires_validation(self):
|
|
"""
|
|
Returns `True` if this node should have a `validate` method associated.
|
|
"""
|
|
return self.is_buildable()
|
|
|
|
def is_unknown(self):
|
|
"""
|
|
Returns `True` if this node is an `Unknown` syntax subclass.
|
|
"""
|
|
return "Unknown" in self.syntax_kind
|
|
|
|
def is_missing(self):
|
|
"""
|
|
Returns `True` if this node is a `Missing` syntax subclass.
|
|
"""
|
|
return "Missing" in self.syntax_kind
|
|
|
|
def is_buildable(self):
|
|
"""
|
|
Returns `True` if this node should have a builder associated.
|
|
"""
|
|
return not self.is_base() and \
|
|
not self.is_unknown() and \
|
|
not self.is_missing() and \
|
|
not self.is_syntax_collection()
|
|
|
|
def shall_be_omitted_when_empty(self):
|
|
"""
|
|
Returns 'True' if this node shall not be created while parsing if it
|
|
has no children.
|
|
"""
|
|
return self.omit_when_empty
|
|
|
|
def is_token(self):
|
|
"""
|
|
Returns true if this child has a token kind.
|
|
"""
|
|
return 'Token' in self.syntax_kind or \
|
|
'Token' in self.collection_element
|