Index: tools/nixysa/nixysa/syntax_tree.py |
=================================================================== |
--- tools/nixysa/nixysa/syntax_tree.py (revision 0) |
+++ tools/nixysa/nixysa/syntax_tree.py (revision 0) |
@@ -0,0 +1,1359 @@ |
+#!/usr/bin/python2.4 |
+# |
+# Copyright 2008 Google Inc. |
+# |
+# Licensed under the Apache License, Version 2.0 (the "License"); |
+# you may not use this file except in compliance with the License. |
+# You may obtain a copy of the License at |
+# |
+# http://www.apache.org/licenses/LICENSE-2.0 |
+# |
+# Unless required by applicable law or agreed to in writing, software |
+# distributed under the License is distributed on an "AS IS" BASIS, |
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+# See the License for the specific language governing permissions and |
+# limitations under the License. |
+ |
+"""Classes describing the parsed IDL as a syntax tree. |
+ |
+This module contains all the classes that are used to describe the IDL as a |
+syntax tree. |
+""" |
+ |
+# TODO: this module has grown too big, it should be split. |
+ |
+ |
+class Error(Exception): |
+ """Base exception for the syntax_tree module.""" |
+ |
+ |
+class TypeNotFoundError(Error): |
+ """Raised when a type reference doesn't resolve to a definition.""" |
+ |
+ def __init__(self, type_defn, location=None): |
+ Error.__init__(self) |
+ self.type_defn = type_defn |
+ self.location = location |
+ |
+ def __str__(self): |
+ if self.location == None: |
+ return self.type_defn |
+ else: |
+ return '%s at %s' % (self.type_defn, self.location) |
+ |
+class DerivingFromNonClassError(Error): |
+ """Raised when a class derives from a non-class.""" |
+ |
+ def __init__(self, type_defn, base_type, location=None): |
+ Error.__init__(self) |
+ self.type_defn = type_defn |
+ self.base_type = base_type |
+ self.location = location |
+ |
+ |
+class ArrayOfNonTypeError(Error): |
+ """Raised when trying to reference an array of a non-type definition.""" |
+ |
+ def __init__(self, data_defn, size): |
+ Error.__init__(self) |
+ self.type_defn = data_defn |
+ self.size = size |
+ |
+ |
+class UnknownBindingModelError(Error): |
+ """Raised when a binding model cannot be found.""" |
+ |
+ def __init__(self, name): |
+ Error.__init__(self) |
+ self.name = name |
+ |
+ def __str__(self): |
+ return self.name |
+ |
+class CircularTypedefError(Error): |
+ """Raised when 2 typedefs reference each other (even indirectly).""" |
+ |
+ def __init__(self, type1, type2): |
+ Error.__init__(self) |
+ self.type1 = type1 |
+ self.type2 = type2 |
+ |
+ def __str__(self): |
+ return '%s and %s' % (self.type1, self.type2) |
+ |
+ |
+class UnimplementedMethodError(Error): |
+ """Raised when an "abstract" method is not implemented in a derived type.""" |
+ |
+ |
+class TypeReference(object): |
+ """Base class for type references. |
+ |
+ TypeReference objects are constructed while parsing the IDL file and provide |
+ a deferred lookup mechanism, removing the necessity to forward-declare all |
+ the types before using them. |
+ """ |
+ |
+ def __init__(self, location): |
+ """Inits a TypeReference instance. |
+ |
+ Args: |
+ location: idl_parser.SourceLocation object, describing the source |
+ location of the reference in the IDL. |
+ """ |
+ self.location = location |
+ |
+ def GetType(self, context): |
+ """Look-up the referenced type. |
+ |
+ Args: |
+ context: context in which to look-up named items (scopes, types). This |
+ must be a Definition instance. |
+ |
+ Returns: |
+ The type, as a Definition instance. |
+ |
+ Raises: |
+ TypeNotFoundError: the type wasn't found. |
+ """ |
+ type_defn = self.GetTypeInternal(context, False) |
+ if type_defn: |
+ return type_defn |
+ else: |
+ raise TypeNotFoundError(self, self.location) |
+ |
+ def GetTypeInternal(self, context, scoped): |
+ """Implements type look-up. |
+ |
+ This method should be implemented in derived classes to perform the |
+ reference-specific look-up. |
+ |
+ Args: |
+ context: context in which to look-up named items (scopes, types). This |
+ must be a Definition instance. |
+ scoped: boolean deciding whether or not the look-up is scoped by the |
+ context, or if parent context should be looked-up as well. |
+ |
+ Returns: |
+ The type, if found, or None if not. |
+ """ |
+ context, scoped = context, scoped # silence lint |
+ return None |
+ |
+ |
+class NameTypeReference(TypeReference): |
+ """Class representing a type reference by name. |
+ |
+ This class represents the reference to a type by name. Look-up will produce a |
+ type that has the specified name, within the specified look-up context - if |
+ it exists. |
+ |
+ Produced by the IDL construct 'Type' where Type is the name of a type |
+ (typedef, typename, class, enum). |
+ """ |
+ |
+ def __init__(self, location, name): |
+ """Inits a NameTypeReference instance. |
+ |
+ Args: |
+ location: idl_parser.SourceLocation object, describing the source |
+ location of the reference in the IDL. |
+ name: the name of the type to look for. |
+ """ |
+ TypeReference.__init__(self, location) |
+ self.name = name |
+ |
+ def GetTypeInternal(self, context, scoped): |
+ """Implementation of the type look-up for NameTypeReference.""" |
+ if scoped: |
+ type_defn = context.LookUpType(self.name) |
+ else: |
+ type_defn = context.LookUpTypeRecursive(self.name) |
+ return type_defn or None |
+ |
+ def __str__(self): |
+ return self.name |
+ |
+ |
+class ScopedTypeReference(TypeReference): |
+ """Class representing a scoped type reference. |
+ |
+ This class represents the reference to a type that is scoped by a particular |
+ name. Look-up will produce a type that can be referenced inside that |
+ particular scope. |
+ |
+ Produced by the IDL construct 'Scope::TypeRef' where Scope is the name of a |
+ scope, and TypeRef is a type reference. |
+ """ |
+ |
+ def __init__(self, location, scope_name, type_ref): |
+ """Inits a ScopedTypeReference instance. |
+ |
+ Args: |
+ location: idl_parser.SourceLocation object, describing the source |
+ location of the reference in the IDL. |
+ scope_name: the name of the scope to look inside. |
+ type_ref: the type reference to look for, inside the named scope. |
+ """ |
+ TypeReference.__init__(self, location) |
+ self.scope_name = scope_name |
+ self.type_ref = type_ref |
+ |
+ def GetTypeInternal(self, context, scoped): |
+ """Implementation of the type look-up for ScopedTypeReference.""" |
+ if scoped: |
+ scope_list = context.FindScopes(self.scope_name) |
+ else: |
+ scope_list = context.FindScopesRecursive(self.scope_name) |
+ |
+ for scope in scope_list: |
+ type_defn = self.type_ref.GetTypeInternal(scope, True) |
+ if type_defn: |
+ return type_defn |
+ return None |
+ |
+ def __str__(self): |
+ return '%s::%s' % (self.scope_name, self.type_ref) |
+ |
+ |
+class ArrayTypeReference(TypeReference): |
+ """Class representing an array type reference. |
+ |
+ This class represents the reference to a type that is an array of a referenced |
+ data type. |
+ The array can be either sized or unsized. |
+ |
+ Produced by the IDL constructs 'TypeRef[]' or 'TypeRef[size]' where TypeRef |
+ is a type reference. |
+ """ |
+ |
+ def __init__(self, location, type_ref, size): |
+ """Inits a ArrayTypeReference instance. |
+ |
+ Args: |
+ location: idl_parser.SourceLocation object, describing the source |
+ location of the reference in the IDL. |
+ type_ref: the type reference for the data type. |
+ size: the size of the array, or None if unsized. |
+ """ |
+ TypeReference.__init__(self, location) |
+ self.type_ref = type_ref |
+ self.size = size |
+ |
+ def GetTypeInternal(self, context, scoped): |
+ """Implementation of the type look-up for ArrayTypeReference.""" |
+ type_defn = self.type_ref.GetTypeInternal(context, scoped) |
+ if type_defn: |
+ return type_defn.GetArrayType(self.size) |
+ else: |
+ return None |
+ |
+ def __str__(self): |
+ if self.size == None: |
+ return '%s[]' % self.type_ref |
+ else: |
+ return '%s[%s]' % (self.type_ref, self.size) |
+ |
+ |
+class QualifiedTypeReference(TypeReference): |
+ """Class representing a type reference with a qualifier. |
+ |
+ This class represents the reference to a type that is specialized by a type |
+ qualifier, such as const or volatile or nullable. |
+ |
+ Produced by the IDL construct 'qualifier TypeRef' where qualifier is a type |
+ qualifier (const, restrict, volatile), and TypeRef is a type reference. |
+ """ |
+ |
+ def __init__(self, location, qualifier, type_ref): |
+ """Inits a QualifiedTypeReference instance. |
+ |
+ Args: |
+ location: idl_parser.SourceLocation object, describing the source |
+ location of the reference in the IDL. |
+ qualifier: the qualifier. |
+ type_ref: the type reference for the un-qualified type. |
+ """ |
+ TypeReference.__init__(self, location) |
+ self.qualifier = qualifier |
+ self.type_ref = type_ref |
+ |
+ def GetTypeInternal(self, context, scoped): |
+ """Implementation of the type look-up for QualifiedTypeReference.""" |
+ type_defn = self.type_ref.GetTypeInternal(context, scoped) |
+ if type_defn: |
+ if self.qualifier == 'nullable': |
+ return type_defn.GetNullableType() |
+ else: |
+ return type_defn |
+ else: |
+ return None |
+ |
+ def __str__(self): |
+ return '%s %s' % (self.qualifier, self.type_ref) |
+ |
+ |
+class Definition(object): |
+ """Base class for definitions. |
+ |
+ Definition objects represent all the items that are defined in the IDL, such |
+ as classes or functions. This class provides some common functionality, such |
+ as walking the syntax tree to look for types, and provide an interface that |
+ should be implemented by sub-classes, such as listing all the scopes the |
+ object may contain. |
+ |
+ Attributes: |
+ defn_type: a string representing the type of this definition |
+ source: idl_parser.SourceLocation object, describing the source location |
+ of this definition |
+ attributes: a dictionary of attributes associated with that definition |
+ name: (optional) the name of the definition. None if undefined |
+ is_type: this definition is a type, and should be found by LookUpType. e.g. |
+ Class, Typedef, Enum, ... |
+ is_scope: this definition is a scope, and should be found by FindScopes. |
+ e.g. Class, Namespace, ... |
+ parent: the parent scope of that definition |
+ array_defns: a dictionary of array definitions of this type, hashed by the |
+ array size. Empty for non-types |
+ nullable: the nullable form of this type. |
+ binding_model: the binding model module for this type. None for non-types |
+ """ |
+ defn_type = 'Definition' |
+ |
+ def __init__(self, source, attributes, name): |
+ """Inits a Definition instance. |
+ |
+ Args: |
+ source: idl_parser.SourceLocation object, describing the source location |
+ of this definition |
+ attributes: a dictionary of attributes associated with that definition |
+ name: (optional) the name of the definition |
+ """ |
+ self.source = source |
+ self.attributes = attributes |
+ self.name = name |
+ self.is_type = False |
+ self.is_scope = False |
+ self.parent = None |
+ self.array_defns = {} |
+ self.nullable = None |
+ self.binding_model = None |
+ |
+ def __repr__(self): |
+ return '%s(%s)' % (self.defn_type, self.name) |
+ |
+ def GetParentScopeStack(self): |
+ """Gets the stack of englobing scopes.""" |
+ stack = [] |
+ cursor = self.parent |
+ while cursor: |
+ stack = [cursor] + stack |
+ cursor = cursor.parent |
+ return stack |
+ |
+ def LookUpTypeRecursive(self, name): |
+ """Looks up a type by name, recursively. |
+ |
+ This method looks for a type by name, in the current definition and all |
+ the parent scopes recursively. The first type found will be returned. See |
+ LookUpType. |
+ |
+ Args: |
+ name: the name of the type looked for. |
+ |
+ Returns: |
+ The type that was found, or None if no type was found. |
+ """ |
+ lookup_context = self |
+ while lookup_context: |
+ type_defn = lookup_context.LookUpType(name) |
+ if type_defn: |
+ return type_defn |
+ lookup_context = lookup_context.parent |
+ return None |
+ |
+ def FindScopesRecursive(self, name): |
+ """Finds all scopes matching a name, recursively. |
+ |
+ This method finds all scopes matching a name, in the current definition |
+ and recursively in all the parent scopes. See FindScopes. |
+ |
+ Args: |
+ name: the name of the scope looked for. |
+ |
+ Returns: |
+ The list of all the scopes that were found, in traversal order. May be [] |
+ if no scope of that name was found. |
+ """ |
+ scopes = [] |
+ lookup_context = self |
+ while lookup_context: |
+ scopes.extend(lookup_context.FindScopes(name)) |
+ lookup_context = lookup_context.parent |
+ return scopes |
+ |
+ def GetDefinitionInclude(self): |
+ """Returns the include file that has the C++ definition of this type.""" |
+ if 'include' in self.attributes: |
+ return self.attributes['include'] |
+ else: |
+ return self.source.file.header |
+ |
+ def SetBindingModel(self, binding_models): |
+ """Assigns the binding model module to this description. |
+ |
+ This method assigns the binding model module to this description, and all |
+ its array types. Binding models are usually defined as the 'binding_model' |
+ attribute, but some types may inherit binding models from some other types |
+ (e.g. Classes inherit the binding model from their base class, and |
+ Typedefs inherit the binding model from their type). See |
+ LookUpBindingModel. |
+ |
+ Args: |
+ binding_models: a dictionary mapping binding model names to binding model |
+ modules |
+ |
+ Raises: |
+ UnknownBindingModelError if this description doesn't have a valid binding |
+ model. |
+ """ |
+ for k in self.array_defns: |
+ self.array_defns[k].SetBindingModel(binding_models) |
+ if self.nullable and self.nullable != self: |
+ self.nullable.SetBindingModel(binding_models) |
+ name = self.LookUpBindingModel() |
+ try: |
+ self.binding_model = binding_models[name] |
+ except KeyError: |
+ raise UnknownBindingModelError(name) |
+ |
+ def GetArrayType(self, size): |
+ """Returns a Definition representing an array of this type. |
+ |
+ This method returns a Description representing an array of this type. |
+ Arrays of the same data type and same size are shared. |
+ |
+ Args: |
+ size: the size of the array, or None for an unsized array. |
+ |
+ Returns: |
+ The array type description. |
+ |
+ Raises: |
+ ArrayOfNonTypeError: this description is not a type. |
+ """ |
+ if not self.is_type: |
+ raise ArrayOfNonTypeError(self, size) |
+ # An array is not a 'definition' per say, it is a construct that is |
+ # instanciated on use. For several purposes (looking up binding models for |
+ # example), we want to treat them as a definition, so hook a unique version |
+ # of each array (unsized, each size) in the type. |
+ if size in self.array_defns: |
+ return self.array_defns[size] |
+ else: |
+ array = Array(self, size) |
+ self.array_defns[size] = array |
+ return array |
+ |
+ def GetNullableType(self): |
+ """Returns a Definition representing a nullable version of this type.""" |
+ if not self.nullable: |
+ self.nullable = Nullable(self) |
+ return self.nullable |
+ |
+ # members to be overridden by sub-types |
+ def LookUpBindingModel(self): |
+ """Looks up the binding model name for this description. |
+ |
+ This method should be overridden by Description sub-types that are types. |
+ |
+ Returns: |
+ The binding model name, or None if not found. |
+ |
+ Raises: |
+ UnimplementedMethodError: the method was not overridden in the sub-type. |
+ """ |
+ raise UnimplementedMethodError |
+ |
+ def GetObjectsRecursive(self): |
+ """Gets the list of all objects defined in this description, recursively. |
+ |
+ This method gets the list of all objects defined within this description, |
+ going recursively through them. In this list, parent objects must be |
+ returned before their children. This method should be overridden by |
+ Description sub-types that are scopes, but the default behavior is valid |
+ for non-scopes. |
+ |
+ Returns: |
+ The list of objects. |
+ """ |
+ return [self] |
+ |
+ def ResolveTypeReferences(self): |
+ """Resolve all type references needed for this type. |
+ |
+ This method should be overridden by Description sub-types that have type |
+ references (like Functions or Classes). |
+ |
+ Raises: |
+ TypeNotFoundError: a type reference could not be resolved. |
+ CircularTypedefError: circular type references were found. |
+ DerivingFromNonClassError: a class definition derives from a non-class |
+ definition. |
+ """ |
+ pass |
+ |
+ def LookUpType(self, name): |
+ """Looks up a type by name, in the current definition. |
+ |
+ This method looks up a type by name, in the current definition. The first |
+ type found will be returned. Since this method may be used while resolving |
+ type references, it may raise the same exceptions as ResolveTypeReferences. |
+ This method should be overridden by Description sub-types that are scopes, |
+ but the default behavior is correct for non-scopes. |
+ |
+ Args: |
+ name: the name of the type looked for. |
+ |
+ Returns: |
+ The type that was found, or None if no type was found. |
+ |
+ Raises: |
+ TypeNotFoundError: a type reference could not be resolved. |
+ CircularTypedefError: circular type references were found. |
+ DerivingFromNonClassError: a class definition derives from a non-class |
+ definition. |
+ """ |
+ name = name # silence lint |
+ return None |
+ |
+ def FindScopes(self, name): |
+ """Finds all scopes matching a name, in the current definition. |
+ |
+ This method finds all scopes matching a name, in the current definition. |
+ Since this method may be used while resolving type references, it may raise |
+ the same exceptions as ResolveTypeReferences. This method should be |
+ overridden by Description sub-types that are scopes, but the default |
+ behavior is correct for non-scopes. |
+ |
+ Args: |
+ name: the name of the scope looked for. |
+ |
+ Returns: |
+ The list of all the scopes that were found, in traversal order. May be [] |
+ if no scope of that name was found. |
+ """ |
+ name = name # silence lint |
+ return [] |
+ |
+ def GetFinalType(self): |
+ """Returns the final type of this description, following Typedefs links. |
+ |
+ This method should be overridden by Description sub-types that are types, |
+ and represent links to other types (like Typedefs). |
+ |
+ Returns: |
+ The final type. |
+ """ |
+ return self |
+ |
+ |
+class Class(Definition): |
+ """Class definition. |
+ |
+ Class objects represent classes as defined in the IDL by the 'class Name {};' |
+ constructs. A Class is a type and a scope, it can contain definitions within |
+ itself, such as member fields and methods, or other types. Only single |
+ inheritance is supported. |
+ |
+ Attributes: |
+ base_type_ref: the reference to the base type of the class. |
+ base_type: the base type of the class, once the reference has been |
+ resolved. |
+ defn_list: the list of definitions contained in the class scope. |
+ """ |
+ defn_type = 'Class' |
+ |
+ def __init__(self, source, attributes, name, base_type_ref, defn_list): |
+ """Inits a Class instance. |
+ |
+ Args: |
+ source: idl_parser.SourceLocation object, describing the source location |
+ of this class. |
+ attributes: a dictionary of attributes associated with that class. |
+ name: the name of the class. |
+ base_type_ref: a TypeReference, referencing the base class if any, or |
+ None if this class doesn't derive from another class. |
+ defn_list: the list of definitions within the class scope. |
+ """ |
+ Definition.__init__(self, source, attributes, name) |
+ self.base_type_ref = base_type_ref |
+ self.base_type = None |
+ self.defn_list = defn_list |
+ self._scope = LookUpScope(defn_list) |
+ self.is_type = True |
+ self.is_scope = True |
+ self._types_resolved = False |
+ for o in defn_list: |
+ o.parent = self |
+ |
+ def GetObjectsRecursive(self): |
+ """Implementation of GetObjectsRecursive for Class.""" |
+ return [self] + GetObjectsRecursive(self.defn_list) |
+ |
+ def ResolveTypeReferences(self): |
+ """Implementation of ResolveTypeReferences for Class. |
+ |
+ This method will resolve the base class reference. |
+ |
+ Raises: |
+ DerivingFromNonClassError: a class definition derives from a non-class |
+ definition. |
+ """ |
+ if self._types_resolved: |
+ return |
+ self._types_resolved = True |
+ if self.base_type_ref is None: |
+ self.base_type = None |
+ else: |
+ base_type = self.base_type_ref.GetType(self.parent) |
+ CheckTypeInChain(self, base_type) |
+ self.base_type = base_type |
+ if self.base_type.GetFinalType().defn_type != 'Class': |
+ raise DerivingFromNonClassError(self, self.base_type, self.source) |
+ |
+ def GetBaseSafe(self): |
+ """Gets the base type safely, by making sure it is resolved if needed. |
+ |
+ Returns: |
+ The base type. |
+ |
+ Raises: |
+ TypeNotFoundError: a type reference could not be resolved. |
+ CircularTypedefError: circular type references were found. |
+ DerivingFromNonClassError: a class definition derives from a non-class |
+ definition. |
+ """ |
+ self.ResolveTypeReferences() |
+ return self.base_type |
+ |
+ def LookUpType(self, name): |
+ """Implementation of LookUpType for Class.""" |
+ type_defn = self._scope.LookUpType(name) |
+ if type_defn: |
+ return type_defn |
+ base = self.GetBaseSafe() |
+ if base: |
+ return base.LookUpType(name) |
+ return None |
+ |
+ def FindScopes(self, name): |
+ """Implementation of FindScopes for Class.""" |
+ scopes = self._scope.FindScopes(name) |
+ base = self.GetBaseSafe() |
+ if base: |
+ scopes.extend(base.FindScopes(name)) |
+ return scopes |
+ |
+ def LookUpBindingModel(self): |
+ """Implementation of LookUpBindingModel for Class.""" |
+ base = self.GetBaseSafe() |
+ if 'binding_model' in self.attributes: |
+ return self.attributes['binding_model'] |
+ elif base: |
+ return base.LookUpBindingModel() |
+ else: |
+ return None |
+ |
+ |
+class Namespace(Definition): |
+ """Namespace definition. |
+ |
+ Namespace objects represent namespaces as defined in the IDL by the |
+ 'namespace Name {}' constructs. A Namespace is a scope, it can contain |
+ definitions within itself, such as member fields and methods, or other types. |
+ Namespaces can be defined by parts, namespaces that have the same name, and |
+ are defined within the same outer scope are semantically merged for type and |
+ scope lookup purposes. See the MergeNamespacesRecursive function. |
+ |
+ Attributes: |
+ defn_list: the list of definitions contained in the namespace scope. |
+ scope: a LookUpScope object, that will be shared across namespaces that |
+ should be merged for lookup. |
+ """ |
+ defn_type = 'Namespace' |
+ |
+ def __init__(self, source, attributes, name, defn_list): |
+ """Inits a Namespace instance. |
+ |
+ Args: |
+ source: idl_parser.SourceLocation object, describing the source location |
+ of this namespace. |
+ attributes: a dictionary of attributes associated with that namespace. |
+ name: the name of the namespace. |
+ defn_list: the list of definitions within the namespace scope. |
+ """ |
+ Definition.__init__(self, source, attributes, name) |
+ self.defn_list = defn_list |
+ self.scope = LookUpScope(defn_list) |
+ self.is_scope = True |
+ for o in defn_list: |
+ o.parent = self |
+ |
+ def GetObjectsRecursive(self): |
+ """Implementation of GetObjectsRecursive for Namespace.""" |
+ return [self] + GetObjectsRecursive(self.defn_list) |
+ |
+ def MergeLookUpScope(self, other): |
+ """Merges the LookUpScope object from another Namespace into this one. |
+ |
+ See the MergeNamespacesRecursive function. |
+ |
+ Args: |
+ other: the other Namespace to merge into this one. |
+ """ |
+ self.scope.ResetCache() |
+ # self.scope.list may be a reference to the namespace defn_list, so create |
+ # a copy before modifying the list. |
+ self.scope.list = self.scope.list[:] |
+ self.scope.list.extend(other.scope.list) |
+ other.scope = self.scope |
+ |
+ def LookUpType(self, name): |
+ """Implementation of LookUpType for Namespace.""" |
+ return self.scope.LookUpType(name) |
+ |
+ def FindScopes(self, name): |
+ """Implementation of FindScopes for Namespace.""" |
+ return self.scope.FindScopes(name) |
+ |
+ |
+class Enum(Definition): |
+ """Enum definition. |
+ |
+ Enum objects represent enums as defined in the IDL by the |
+ 'enum Name {VALUE1, VALUE2};' constructs. An Enum is a type. |
+ |
+ Attributes: |
+ values: the list of values defined in the enum, as Enum.Value objects. |
+ """ |
+ |
+ class Value(object): |
+ """Enum value description. |
+ |
+ This is simple structure, with a name and an optional value. |
+ |
+ Attributes: |
+ name: the name of the value. |
+ value: the value, or None for the default value. |
+ """ |
+ |
+ def __init__(self, name, value): |
+ """Inits an Enum.Value instance. |
+ |
+ Args: |
+ name: the name of the value. |
+ value: the value, or None for the default value. |
+ """ |
+ self.name = name |
+ self.value = value |
+ |
+ defn_type = 'Enum' |
+ |
+ def __init__(self, source, attributes, name, values): |
+ """Inits an Enum instance. |
+ |
+ Args: |
+ source: idl_parser.SourceLocation object, describing the source location |
+ of this enum. |
+ attributes: a dictionary of attributes associated with that enum. |
+ name: the name of the enum. |
+ values: the list of values defined for this enum, as Enum.Value objects. |
+ """ |
+ Definition.__init__(self, source, attributes, name) |
+ self.values = values |
+ self.is_type = True |
+ |
+ def LookUpBindingModel(self): |
+ """Implementation of LookUpBindingModel for Enum.""" |
+ return 'enum' |
+ |
+ |
+class Function(Definition): |
+ """Function definition. |
+ |
+ Function objects represent functions, methods and constructors/destructors, as |
+ defined in the IDL by the 'Type Function(Type param1, Type param2);' |
+ constructs. |
+ |
+ Attributes: |
+ type_ref: the reference to the return type of the function, or None for |
+ constructors/destructors. |
+ type: the return type of the function, once the reference has been |
+ resolved, or None for constructors/destructors. |
+ params: the list of the function parameters, as Function.Param objects. |
+ """ |
+ |
+ class Param(object): |
+ """Function parameter description. |
+ |
+ This represents any of the function parameter, with its name and type. |
+ |
+ Attributes: |
+ type_ref: the reference to the type of the parameter. |
+ type: the type of the parameter, once the reference has been resolved. |
+ name: the name of the parameter. |
+ mutable: a boolean indicating whether the parameter is mutable. While |
+ (currently) there is no mechanism to specify it in the IDL, code |
+ generation internals use this flag to generate functions with a mutable |
+ 'this' parameter for methods. |
+ """ |
+ |
+ def __init__(self, type_ref, name): |
+ """Inits a Function.Param instance. |
+ |
+ Args: |
+ type_ref: the reference to the type of the parameter. |
+ name: the name of the parameter. |
+ """ |
+ self.type_ref = type_ref |
+ self.type_defn = None |
+ self.name = name |
+ self.mutable = False |
+ |
+ defn_type = 'Function' |
+ |
+ def __init__(self, source, attributes, name, type_ref, params): |
+ """Inits a Function instance. |
+ |
+ Args: |
+ source: idl_parser.SourceLocation object, describing the source location |
+ of this function. |
+ attributes: a dictionary of attributes associated with that function. |
+ name: the name of the function. |
+ type_ref: a TypeReference, referencing the return type if any, or |
+ None for constructors/destructors. |
+ params: the list of parameters, as (TypeReference, name) pairs. |
+ """ |
+ Definition.__init__(self, source, attributes, name) |
+ self.type_ref = type_ref |
+ self.type_defn = None |
+ self.params = [self.Param(type_ref, name) for type_ref, name in params] |
+ |
+ def ResolveTypeReferences(self): |
+ """Implementation of ResolveTypeReferences for Function.""" |
+ if self.type_ref is None: |
+ self.type_defn = None |
+ else: |
+ self.type_defn = self.type_ref.GetType(self.parent) |
+ for param in self.params: |
+ param.type_defn = param.type_ref.GetType(self.parent) |
+ |
+ |
+class Callback(Definition): |
+ """Callback definition. |
+ |
+ Callback objects represent callback functions as defined in the IDL by the |
+ 'callback Type Function(Type param1, Type param2);' constructs. Callbacks are |
+ meant to behave like function objects. Callbacks are types. |
+ |
+ Attributes: |
+ type_ref: the reference to the return type of the callback. |
+ type: the return type of the callback, once the reference has been |
+ resolved. |
+ params: the list of the function parameters, as Function.Param objects. |
+ """ |
+ |
+ defn_type = 'Callback' |
+ |
+ def __init__(self, source, attributes, name, type_ref, params): |
+ """Inits a Callback instance. |
+ |
+ Args: |
+ source: idl_parser.SourceLocation object, describing the source location |
+ of this callback. |
+ attributes: a dictionary of attributes associated with that callback. |
+ name: the name of the callback. |
+ type_ref: a TypeReference, referencing the return type if any, or |
+ None for constructors/destructors. |
+ params: the list of parameters, as (TypeReference, name) pairs. |
+ """ |
+ Definition.__init__(self, source, attributes, name) |
+ self.type_ref = type_ref |
+ self.type_defn = None |
+ self.params = [Function.Param(type_ref, name) for type_ref, name in params] |
+ self.is_type = True |
+ |
+ def ResolveTypeReferences(self): |
+ """Implementation of ResolveTypeReferences for Callback.""" |
+ if self.type_ref is None: |
+ self.type_defn = None |
+ else: |
+ self.type_defn = self.type_ref.GetType(self.parent) |
+ for param in self.params: |
+ param.type_defn = param.type_ref.GetType(self.parent) |
+ |
+ def LookUpBindingModel(self): |
+ """Implementation of LookUpBindingModel for Callback.""" |
+ if 'binding_model' in self.attributes: |
+ return self.attributes['binding_model'] |
+ else: |
+ return 'callback' |
+ |
+ |
+class Variable(Definition): |
+ """Variable definition. |
+ |
+ Variable objects represent variables, whether global, or class member fields, |
+ as defined in the IDL by the 'Type variable;' constructs. |
+ |
+ Attributes: |
+ type_ref: the reference to the type of the variable |
+ type: the type of the variable, once the reference has been resolved. |
+ """ |
+ defn_type = 'Variable' |
+ |
+ def __init__(self, source, attributes, name, type_ref): |
+ """Inits a Variable instance. |
+ |
+ Args: |
+ source: idl_parser.SourceLocation object, describing the source location |
+ of this variable. |
+ attributes: a dictionary of attributes associated with that variable. |
+ name: the name of the variable. |
+ type_ref: a TypeReference, referencing the type of the variable. |
+ """ |
+ Definition.__init__(self, source, attributes, name) |
+ self.type_ref = type_ref |
+ self.type_defn = None |
+ |
+ def ResolveTypeReferences(self): |
+ """Implementation of ResolveTypeReferences for Variable.""" |
+ self.type_defn = self.type_ref.GetType(self.parent) |
+ |
+ def MakeGetter(self, attributes, name): |
+ """Creates a Function for the getter for the variable. |
+ |
+ Args: |
+ attributes: the attributes for the getter function. |
+ name: the name of the getter function. |
+ |
+ Returns: |
+ the getter definition. |
+ """ |
+ func = Function(self.source, attributes, name, self.type_ref, []) |
+ func.parent = self.parent |
+ func.ResolveTypeReferences() |
+ return func |
+ |
+ def MakeSetter(self, attributes, name): |
+ """Creates a Function for the setter for the variable. |
+ |
+ Args: |
+ attributes: the attributes for the setter function. |
+ name: the name of the setter function. |
+ |
+ Returns: |
+ the setter definition. |
+ """ |
+ void_ref = NameTypeReference(self.source, 'void') |
+ func = Function(self.source, attributes, name, void_ref, [(self.type_ref, |
+ self.name)]) |
+ func.parent = self.parent |
+ func.ResolveTypeReferences() |
+ return func |
+ |
+ |
+class Typedef(Definition): |
+ """Typedef definition. |
+ |
+ Typedef objects represent type 'symbolic links', defining a new name for an |
+ existing type, as defined in the IDL by the 'typedef Type NewType;' |
+ constructs. Typedefs are types, and scopes. |
+ |
+ Attributes: |
+ type_ref: the reference to the original type of the typedef |
+ type: the original type of the typedef, once the reference has been |
+ resolved. |
+ """ |
+ defn_type = 'Typedef' |
+ |
+ def __init__(self, source, attributes, name, type_ref): |
+ """Inits a Typedef instance. |
+ |
+ Args: |
+ source: idl_parser.SourceLocation object, describing the source location |
+ of this typedef. |
+ attributes: a dictionary of attributes associated with that typedef. |
+ name: the name of the typedef. |
+ type_ref: a TypeReference, referencing the original type of the typedef. |
+ """ |
+ Definition.__init__(self, source, attributes, name) |
+ self.type_ref = type_ref |
+ self.type_defn = None |
+ self.is_type = True |
+ self.is_scope = True |
+ self._types_resolved = False |
+ |
+ def ResolveTypeReferences(self): |
+ """Implementation of ResolveTypeReferences for Typedef.""" |
+ if self._types_resolved: |
+ return |
+ self._types_resolved = True |
+ type_defn = self.type_ref.GetType(self.parent) |
+ CheckTypeInChain(self, type_defn) |
+ self.type_defn = type_defn |
+ |
+ def GetTypeSafe(self): |
+ """Gets the original type safely, by making sure it is resolved if needed. |
+ |
+ Returns: |
+ The original type. |
+ |
+ Raises: |
+ TypeNotFoundError: a type reference could not be resolved. |
+ CircularTypedefError: circular type references were found. |
+ DerivingFromNonClassError: a class definition derives from a non-class |
+ definition. |
+ """ |
+ self.ResolveTypeReferences() |
+ return self.type_defn |
+ |
+ def LookUpBindingModel(self): |
+ """Implementation of LookUpBindingModel for Typedef.""" |
+ if 'binding_model' in self.attributes: |
+ return self.attributes['binding_model'] |
+ else: |
+ return self.GetTypeSafe().LookUpBindingModel() |
+ |
+ def GetFinalType(self): |
+ """Implementation of GetFinalType for Typedef.""" |
+ return self.GetTypeSafe().GetFinalType() |
+ |
+ def LookUpType(self, name): |
+ """Implementation of LookUpType for Typedef.""" |
+ return self.GetTypeSafe().LookUpType(name) |
+ |
+ def FindScopes(self, name): |
+ """Implementation of FindScopes for Typedef.""" |
+ return self.GetTypeSafe().FindScopes(name) |
+ |
+ |
+class Typename(Definition): |
+ """Typename definition. |
+ |
+ Typename objects represent unknown types, whose definition cannot be |
+ expressed in IDL, but still need to be referenced in the IDL. They are |
+ declared in IDL with the 'typename Type;' constructs. Typenames are types. |
+ |
+ Attributes: |
+ None |
+ """ |
+ defn_type = 'Typename' |
+ |
+ def __init__(self, source, attributes, name): |
+ """Inits a Typename instance. |
+ |
+ Args: |
+ source: idl_parser.SourceLocation object, describing the source location |
+ of this typename. |
+ attributes: a dictionary of attributes associated with that typename. |
+ name: the name of the typename. |
+ """ |
+ Definition.__init__(self, source, attributes, name) |
+ self.is_type = True |
+ |
+ def LookUpBindingModel(self): |
+ """Implementation of LookUpBindingModel for Typename.""" |
+ try: |
+ return self.attributes['binding_model'] |
+ except KeyError: |
+ return None |
+ |
+ |
+class Verbatim(Definition): |
+ """Verbatim definition. |
+ |
+ Verbatim objects represent text that needs to be included as is into the |
+ generated code. Attributes control in which context the code should be |
+ included. They are defined in IDL within '%{' and '%}' quotes. |
+ |
+ Attributes: |
+ text: the verbatim text. |
+ """ |
+ defn_type = 'Verbatim' |
+ |
+ def __init__(self, source, attributes, text): |
+ """Inits a Verbatim instance. |
+ |
+ Args: |
+ source: idl_parser.SourceLocation object, describing the source location |
+ of this verbatim. |
+ attributes: a dictionary of attributes associated with that verbatim. |
+ text: the text of the verbatim. |
+ """ |
+ Definition.__init__(self, source, attributes, None) |
+ self.text = text |
+ |
+ |
+class Array(Definition): |
+ """Array definition. |
+ |
+ Array objects represent sized and unsized arrays of a data type. They are not |
+ defined explicitly in IDL, but implicitly through array references. Arrays |
+ are types. |
+ |
+ Attributes: |
+ data_type: the type of individual elements of the array |
+ size: the size of the array, as an integer, or None for an unsized array |
+ """ |
+ defn_type = 'Array' |
+ |
+ def __init__(self, data_type, size): |
+ """Inits an Array instance. |
+ |
+ Args: |
+ data_type: the type of individual elements of the array |
+ size: the size of the array, as an integer, or None for an unsized array |
+ """ |
+ Definition.__init__(self, data_type.source, [], None) |
+ self.data_type = data_type |
+ self.size = size |
+ self.is_type = True |
+ |
+ def __repr__(self): |
+ return '%s[]' % str(self.data_type) |
+ |
+ def LookUpBindingModel(self): |
+ """Implementation of LookUpBindingModel for Array.""" |
+ if self.size: |
+ return 'sized_array' |
+ else: |
+ return 'unsized_array' |
+ |
+ |
+class Nullable(Definition): |
+ """Nullable definition. |
+ |
+ Nullable objects are those that can have a null value. They are not |
+ defined explicitly in IDL, but implicitly through nullable references. |
+ Nullables are types. |
+ |
+ Attributes: |
+ data_type: the type this Nullable has when it is not null. |
+ """ |
+ defn_type = 'Nullable' |
+ |
+ def __init__(self, data_type): |
+ """Inits an Array instance. |
+ |
+ Args: |
+ data_type: the type this Nullable has when it is not null. |
+ """ |
+ Definition.__init__(self, data_type.source, [], None) |
+ self.data_type = data_type |
+ self.is_type = True |
+ self.nullable = self |
+ |
+ def __repr__(self): |
+ return '%s?' % str(self.data_type) |
+ |
+ def LookUpBindingModel(self): |
+ """Implementation of LookUpBindingModel for Nullable.""" |
+ return 'nullable' |
+ |
+ |
+def CheckTypeInChain(type_defn, chain_head): |
+ """Checks that a type isn't in a type chain. |
+ |
+ Circular references of types shouldn't happen within typedefs, base class or |
+ array chains. For example the following IDL constructs should be forbidden: |
+ |
+ typedef Typedef1 Typedef2; |
+ typedef Typedef2 Typedef1; |
+ |
+ class Class1: Class2 {}; |
+ class Class2: Class1 {}; |
+ |
+ typedef Typedef1[] Typedef1; |
+ |
+ typedef Class Typedef; |
+ class Class: Typedef {}; |
+ |
+ and so on. This function checks that a particular type doesn't already exists |
+ in a chain, defined by following typedefs, base classes and array data types. |
+ |
+ Args: |
+ type_defn: the type to look for. |
+ chain_head: the head of the chain to look into. |
+ |
+ Raises: |
+ CircularTypedefError: a circular reference was found, that is 'type' was |
+ found in the chain. |
+ """ |
+ current = chain_head |
+ while current: |
+ if type_defn == current: |
+ raise CircularTypedefError(type_defn, current) |
+ if current.defn_type == 'Typedef': |
+ # Don't use GetTypeSafe, just break if the type hasn't been set |
+ # using GetTypeSafe would produce an infinite loop... |
+ # It is ok to break if the type hasn't been set yet. If there is a |
+ # cycle, it will be detected when that other type calls GetTypeSafe |
+ current = current.type_defn |
+ elif current.defn_type == 'Class': |
+ # same as above, don't use GetBaseTypeSafe |
+ current = current.base_type |
+ elif current.defn_type == 'Array': |
+ current = current.data_type |
+ else: |
+ break |
+ |
+ |
+class LookUpScope(object): |
+ """Helper class for lookup in scope definitions. |
+ |
+ This class provides basic functionality for LookUpType and FindScope |
+ implementations, when the definition is a scope, like classes and namespaces. |
+ Caching and such is implemented here. Currently, only type lookups is cached |
+ with a name -> definition dictionary. |
+ |
+ Attributes: |
+ list: the list of definition the lookup operates on. |
+ """ |
+ |
+ def __init__(self, definition_list): |
+ """Inits a LookUpScope instance. |
+ |
+ Args: |
+ definition_list: the list of definition the lookup operates on. |
+ """ |
+ self.list = definition_list |
+ self.ResetCache() |
+ |
+ def ResetCache(self): |
+ """Resets all caches. To be used if the definition list changes.""" |
+ self._types = None |
+ |
+ def MakeCache(self): |
+ """Initializes caches.""" |
+ if not self._types: |
+ self._types = dict([(i.name, i) for i in self.list if i.is_type]) |
+ |
+ def LookUpType(self, name): |
+ """Looks up a type by name within the definition list. |
+ |
+ Args: |
+ name: the name of the type looked for. |
+ |
+ Returns: |
+ The type definition if found, None otherwise. |
+ """ |
+ self.MakeCache() |
+ try: |
+ return self._types[name] |
+ except KeyError: |
+ return None |
+ |
+ def FindScopes(self, name): |
+ """Finds all socpes matching a name, in the definition list. |
+ |
+ Args: |
+ name: the name of the scopes looked for. |
+ |
+ Returns: |
+ The list of all the scopes that were found. May be [] if no scope of that |
+ name was found. |
+ """ |
+ return [i for i in self.list if i.is_scope and i.name == name] |
+ |
+ |
+def GetObjectsRecursive(object_list): |
+ """Gets the list of all objects recursively defined in a list of objects. |
+ |
+ This method gets the list of all objects defined within a list of top-level |
+ objects, going recursively through them. |
+ |
+ Args: |
+ object_list: the list of top-level objects. |
+ |
+ Returns: |
+ The list of objects. |
+ """ |
+ return sum([obj.GetObjectsRecursive() for obj in object_list], []) |
+ |
+ |
+def MergeNamespacesRecursive(namespace): |
+ """Merges scopes described by namespaces constructs. |
+ |
+ Namespaces can be defined by parts, this function merges scopes of namespaces |
+ that have the same name, and are defined within the same outer scope. E.g. |
+ the following: |
+ namespace Foo { |
+ namespace Bar { |
+ class Class1 {}; |
+ void Function2(); |
+ } |
+ |
+ namespace Bar { |
+ int my_variable; |
+ } |
+ } |
+ will create within the namespace 'Foo' two Namespace objects, both named |
+ 'Bar', each containing different definitions, and different inner LookUpScope |
+ objects. |
+ This function will merge the LookUpScope objects between these namespaces, for |
+ it to contain all the definitions. The Namespace objects will still exist as |
+ separate entities, only their scope member changes. |
+ |
+ Args: |
+ namespace: the root namespace containing namespace definitions to merge. |
+ """ |
+ namespaces = [o for o in namespace.scope.list if o.defn_type == 'Namespace'] |
+ namespace_dict = {} |
+ for o in namespaces: |
+ if o.name in namespace_dict: |
+ namespace_dict[o.name].MergeLookUpScope(o) |
+ else: |
+ namespace_dict[o.name] = o |
+ for name in namespace_dict: |
+ MergeNamespacesRecursive(namespace_dict[name]) |
+ |
+ |
+def FinalizeObjects(namespace, binding_models): |
+ """Finalize all objects after parsing. |
+ |
+ When objects are first parsed, they are not completely ready for code |
+ generation. This functions takes care of finalizing objects: |
+ - merging namespace scopes that have the same name in the same outer scope. |
+ - resolving type references. |
+ - setting binding models on types. |
+ |
+ Args: |
+ namespace: 'global' namespace, containing all the definitions. |
+ binding_models: a dictionary that maps binding model name -> binding model |
+ module. |
+ |
+ Raises: |
+ TypeNotFoundError: a type reference could not be resolved. |
+ CircularTypedefError: circular type references were found. |
+ DerivingFromNonClassError: a class definition derives from a non-class |
+ definition. |
+ UnknownBindingModelError: a type definition doesn't have a valid binding |
+ model. |
+ """ |
+ MergeNamespacesRecursive(namespace) |
+ all_defns = namespace.GetObjectsRecursive() |
+ for defn in all_defns: |
+ defn.ResolveTypeReferences() |
+ for defn in all_defns: |
+ if defn.is_type: |
+ defn.SetBindingModel(binding_models) |
+ |
+ |
+def main(): |
+ pass |
+ |
+ |
+if __name__ == '__main__': |
+ main() |
Property changes on: tools/nixysa/nixysa/syntax_tree.py |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |