class_ = UNIVERSAL | APPLICATION | PRIVATE
class_number = Unique(number) # todo: consider defined values from 30.1
tag = Suppress('[') + Optional(class_) + class_number + Suppress(']')
- tag_default = Optional(EXPLICIT_TAGS | IMPLICIT_TAGS | AUTOMATIC_TAGS)
+ tag_default = EXPLICIT_TAGS | IMPLICIT_TAGS | AUTOMATIC_TAGS
# extensions
- extension_default = Optional(EXTENSIBILITY_IMPLIED)
+ extension_default = Unique(EXTENSIBILITY_IMPLIED)
# values
component_type_components_of = Suppress(COMPONENTS_OF) + type_
component_type = component_type_components_of | component_type_optional | component_type_default | named_type
- tagged_type = tag + Optional(IMPLICIT | EXPLICIT) + type_
+ tagged_type = tag + Optional(IMPLICIT | EXPLICIT, default=None) + type_
named_number_value = Suppress('(') + signed_number + Suppress(')')
named_number = identifier + named_number_value
imports = Optional(Suppress(IMPORTS) + symbols_imported + Suppress(';'))
module_body = (exports + imports + assignment_list)
- module_defaults = Suppress(tag_default + extension_default) # we don't want these in the AST
module_identifier = module_reference + definitive_identifier
- module_definition = module_identifier + DEFINITIONS + module_defaults + '::=' + BEGIN + module_body + END
+ module_definition = module_identifier + Suppress(DEFINITIONS) + Optional(tag_default, default=None) + \
+ Optional(extension_default, default=None) + Suppress('::=') + Suppress(BEGIN) + module_body + Suppress(END)
module_definition.ignore(comment)
def defn_tagged_type(self, class_name, t):
fragment = self.writer.get_fragment()
- tag_type = 'tagImplicitly' if t.implicit else 'tagExplicitly'
+ implicity = self.sema_module.resolve_tag_implicity(t.implicity, t.type_decl)
+ if implicity == TagImplicity.IMPLICIT:
+ tag_implicity = 'tagImplicitly'
+ elif implicity == TagImplicity.EXPLICIT:
+ tag_implicity = 'tagExplicitly'
+ else:
+ assert False, "Unexpected implicity: %s" % implicity
+
base_type = _translate_type(t.type_decl.type_name)
- fragment.write_line('%s.tagSet = %s.tagSet.%s(%s)' % (class_name, base_type, tag_type, self.build_tag_expr(t)))
+ fragment.write_line('%s.tagSet = %s.tagSet.%s(%s)' % (class_name, base_type, tag_implicity, self.build_tag_expr(t)))
nested_dfn = self.generate_defn(class_name, t.type_decl)
if nested_dfn:
fragment.write_line(nested_dfn)
return str(fragment)
def inline_tagged_type(self, t):
- tag_type = 'implicitTag' if t.implicit else 'explicitTag'
+ implicity = self.sema_module.resolve_tag_implicity(t.implicity, t.type_decl)
+ if implicity == TagImplicity.IMPLICIT:
+ tag_implicity = 'implicitTag'
+ elif implicity == TagImplicity.EXPLICIT:
+ tag_implicity = 'explicitTag'
+ else:
+ assert False, "Unexpected implicity: %s" % implicity
+
type_expr = self.generate_expr(t.type_decl)
- type_expr += '.subtype(%s=%s)' % (tag_type, self.build_tag_expr(t))
+ type_expr += '.subtype(%s=%s)' % (tag_implicity, self.build_tag_expr(t))
return type_expr
'registration-procedures': 17
}
+
+class TagImplicity(object):
+ """ Tag implicit/explicit enumeration """
+ IMPLICIT = 0
+ EXPLICIT = 1
+ AUTOMATIC = 2
+
+
"""
Sema nodes
class Module(SemaNode):
+
def __init__(self, elements):
self._user_types = {}
- module_reference, _, _, _, _, module_body, _ = elements
+ module_reference, definitive_identifier, tag_default, extension_default, module_body = elements
exports, imports, assignments = module_body.elements
self.name = module_reference.elements[0]
+
+ if tag_default == 'IMPLICIT TAGS':
+ self.tag_default = TagImplicity.IMPLICIT
+ elif tag_default == 'EXPLICIT TAGS':
+ self.tag_default = TagImplicity.EXPLICIT
+ elif tag_default == 'AUTOMATIC TAGS':
+ self.tag_default = TagImplicity.AUTOMATIC
+ else:
+ assert tag_default is None, 'Unexpected tag default: %s' % tag_default
+ # Tag default was not specified, default to explicit
+ self.tag_default = TagImplicity.EXPLICIT
+
self.assignments = [_create_sema_node(token) for token in assignments.elements]
def user_types(self):
return self._user_types
def resolve_type_decl(self, type_decl):
- """ Recursively resolve user-defined types to their
- built-in declaration.
+ """ Recursively resolve user-defined types to their built-in
+ declaration.
"""
user_types = self.user_types()
return None
+ def resolve_tag_implicity(self, tag_implicity, tagged_type_decl):
+ """ The implicity for a tag depends on three things:
+ * Any written implicity on the tag decl itself (``tag_implicity``)
+ * The module's tag default (kept in ``self.tag_default``)
+ * Details of the tagged type according to X.680, 30.6c (not implemented,
+ but should be doable based on ``tagged_type_decl``)
+ """
+ if tag_implicity is not None:
+ return tag_implicity
+
+ # No tag implicity specified, use module-default
+ if self.tag_default is None:
+ # Explicit is default if nothing
+ return TagImplicity.EXPLICIT
+ elif self.tag_default == TagImplicity.AUTOMATIC:
+ # TODO: Expand according to rules for automatic tagging.
+ return TagImplicity.IMPLICIT
+
+ return self.tag_default
+
def __str__(self):
return '%s DEFINITIONS ::=\n' % self.name \
+ 'BEGIN\n' \
class TaggedType(SemaNode):
def __init__(self, elements):
+ tag_token, implicity, type_token = elements
+
self.class_name = None
self.class_number = None
- self.implicit = False
-
- tag_token = elements[0]
- if type(elements[1]) is parser.AnnotatedToken:
- type_token = elements[1]
- else:
- self.implicit = elements[1] == 'IMPLICIT'
- type_token = elements[2]
-
for tag_element in tag_token.elements:
if tag_element.ty == 'TagClassNumber':
self.class_number = tag_element.elements[0]
else:
assert False, 'Unknown tag element: %s' % tag_element
+ if implicity == 'IMPLICIT':
+ self.implicity = TagImplicity.IMPLICIT
+ elif implicity == 'EXPLICIT':
+ self.implicity = TagImplicity.EXPLICIT
+ elif implicity is None:
+ self.implicity = None # Module-default or automatic
+
self.type_decl = _create_sema_node(type_token)
@property
class_spec.append(self.class_number)
result = '[%s] ' % ' '.join(class_spec)
- if self.implicit:
+ if self.implicity == TagImplicity.IMPLICIT:
result += 'IMPLICIT '
+ elif self.implicity == TagImplicity.EXPLICIT:
+ result += 'EXPLICIT '
+ else:
+ pass # module-default
result += str(self.type_decl)