Index: tools/nixysa/nixysa/cpp_header_generator.py |
=================================================================== |
--- tools/nixysa/nixysa/cpp_header_generator.py (revision 0) |
+++ tools/nixysa/nixysa/cpp_header_generator.py (revision 0) |
@@ -0,0 +1,363 @@ |
+#!/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. |
+ |
+"""C++ header file generator. |
+ |
+This module generates C++ header file for a javascript |
+documentation file from the parsed syntax tree. |
+""" |
+ |
+import cpp_utils |
+import gflags |
+import java_utils |
+import naming |
+ |
+ |
+class UndocumentedError(Exception): |
+ """Error raised when a member is undocumented.""" |
+ |
+ def __init__(self, obj): |
+ Exception.__init__(self) |
+ self.object = obj |
+ |
+ |
+class CPPHeaderGenerator(object): |
+ """Header generator class. |
+ |
+ This class takes care of the details of generating a C++ header file |
+ containing all the definitions from a syntax tree. This particular |
+ header generator does so with a slant on javascript. This means no |
+ virtual, static, void, etc. |
+ |
+ It contains a list of functions named after each of the Definition classes in |
+ syntax_tree, with a common signature. The appropriate function will be called |
+ for each definition, to generate the code for that definition. |
+ |
+ Attributes: |
+ _output_dir: output directory |
+ force_documentation: whether to force all members to have documentation |
+ """ |
+ |
+ def __init__(self, output_dir): |
+ self._output_dir = output_dir |
+ self.force_documentation = gflags.FLAGS['force-docs'].value |
+ |
+ def GetSectionFromAttributes(self, parent_section, defn): |
+ """Gets the code section appropriate for a given definition. |
+ |
+ Classes have 3 definition sections: private, protected and public. This |
+ function will pick one of the sections, based on the attributes of the |
+ definition, if its parent is a class. For other scopes (namespaces) it will |
+ return the parent scope main section. |
+ |
+ Args: |
+ parent_section: the main section for the parent scope. |
+ defn: the definition. |
+ |
+ Returns: |
+ the appropriate section. |
+ """ |
+ if defn.parent and defn.parent.defn_type == 'Class': |
+ if 'private' in defn.attributes: |
+ return parent_section.GetSection('private:') or parent_section |
+ elif 'protected' in defn.attributes: |
+ return parent_section.GetSection('protected:') or parent_section |
+ else: |
+ return parent_section.GetSection('public:') or parent_section |
+ else: |
+ return parent_section |
+ |
+ def Verbatim(self, parent_section, scope, obj): |
+ """Generates the code for a Verbatim definition. |
+ |
+ Verbatim definitions being written for a particular type of output file, |
+ this function will check the 'verbatim' attribute, and only emit the |
+ verbatim code if it is 'cpp_header'. |
+ |
+ Args: |
+ parent_section: the main section of the parent scope. |
+ scope: the parent scope. |
+ obj: the Verbatim definition. |
+ |
+ Returns: |
+ a list of (boolean, Definition) pairs, of all the types that need |
+ to be declared (boolean is False) or defined (boolean is True) before |
+ this definition. |
+ """ |
+ scope = scope # silence gpylint. |
+ try: |
+ if obj.attributes['verbatim'] == 'cpp_header': |
+ section = self.GetSectionFromAttributes(parent_section, obj) |
+ section.EmitCode(obj.text) |
+ except KeyError: |
+ source = obj.source |
+ print ('%s:%d ignoring verbatim with no verbatim attribute' % |
+ (source.file.source, source.line)) |
+ |
+ def Typedef(self, parent_section, scope, obj): |
+ """Generates the code for a Typedef definition. |
+ |
+ Args: |
+ parent_section: the main section of the parent scope. |
+ scope: the parent scope. |
+ obj: the Typedef definition. |
+ """ |
+ section = self.GetSectionFromAttributes(parent_section, obj) |
+ bm = obj.type_defn.binding_model |
+ type_string = bm.JavaMemberString(scope, obj.type_defn) |
+ section.EmitCode('typedef %s %s;' % (type_string, obj.name)) |
+ |
+ def Variable(self, parent_section, scope, obj): |
+ """Generates the code for a Variable definition. |
+ |
+ This function will generate the member/global variable declaration, as well |
+ as the setter/getter functions if specified in the attributes. |
+ |
+ Args: |
+ parent_section: the main section of the parent scope. |
+ scope: the parent scope. |
+ obj: the Variable definition. |
+ """ |
+ member_section = self.GetSectionFromAttributes(parent_section, obj) |
+ |
+ bm = obj.type_defn.binding_model |
+ type_string = bm.JavaMemberString(scope, obj.type_defn) |
+ # Note: There is no static in javascript |
+ field_name = naming.Normalize(obj.name, naming.Java) |
+ if 'getter' in obj.attributes and 'setter' not in obj.attributes: |
+ self.Documentation(member_section, obj, |
+ 'This property is read-only.') |
+ elif 'getter' not in obj.attributes and 'setter' in obj.attributes: |
+ self.Documentation(member_section, obj, |
+ 'This property is write-only.') |
+ else: |
+ self.Documentation(member_section, obj, '') |
+ member_section.EmitCode('%s %s;' % (type_string, field_name)) |
+ # Note: There are no getter/setter in javascript |
+ |
+ def Function(self, parent_section, scope, obj): |
+ """Generates the code for a Function definition. |
+ |
+ Args: |
+ parent_section: the main section of the parent scope. |
+ scope: the parent scope. |
+ obj: the Function definition. |
+ """ |
+ section = self.GetSectionFromAttributes(parent_section, obj) |
+ self.Documentation(section, obj, '') |
+ prototype = java_utils.GetFunctionPrototype(scope, obj) |
+ section.EmitCode(prototype + ';') |
+ |
+ def Callback(self, parent_section, scope, obj): |
+ """Generates the code for a Callback definition. |
+ |
+ Args: |
+ parent_section: the main section of the parent scope. |
+ scope: the parent scope. |
+ obj: the Class definition. |
+ """ |
+ parent_section, scope, obj = parent_section, scope, obj # silence gpylint |
+ # TODO: implement this. Do we want to generate the C++ callback object |
+ # (either through a CallbackN<A0, A1, ...> typedef, or explicitly), or |
+ # something else that could be more useful to generate CPP docs ? |
+ |
+ def Class(self, parent_section, scope, obj): |
+ """Generates the code for a Class definition. |
+ |
+ This function will recursively generate the code for all the definitions |
+ inside the class. These definitions will be output into one of 3 sections |
+ (private, protected, public), depending on their attributes. These |
+ individual sections will only be output if they are not empty. |
+ |
+ Args: |
+ parent_section: the main section of the parent scope. |
+ scope: the parent scope. |
+ obj: the Class definition. |
+ """ |
+ self.Documentation(parent_section, obj, '') |
+ section = self.GetSectionFromAttributes(parent_section, obj).CreateSection( |
+ obj.name) |
+ if obj.base_type: |
+ bm = obj.base_type.binding_model |
+ type_string = bm.JavaMemberString(scope, obj.base_type) |
+ section.EmitCode('class %s : public %s {' % (obj.name, type_string)) |
+ else: |
+ section.EmitCode('class %s {' % obj.name) |
+ public_section = section.CreateSection('public:') |
+ protected_section = section.CreateSection('protected:') |
+ private_section = section.CreateSection('private:') |
+ self.DefinitionList(section, obj, obj.defn_list) |
+ if not public_section.IsEmpty(): |
+ public_section.AddPrefix('public:') |
+ if not protected_section.IsEmpty(): |
+ protected_section.AddPrefix('protected:') |
+ if not private_section.IsEmpty(): |
+ private_section.AddPrefix('private:') |
+ section.EmitCode('};') |
+ |
+ def Namespace(self, parent_section, scope, obj): |
+ """Generates the code for a Namespace definition. |
+ |
+ This function will recursively generate the code for all the definitions |
+ inside the namespace. |
+ |
+ Args: |
+ parent_section: the main section of the parent scope. |
+ scope: the parent scope. |
+ obj: the Namespace definition. |
+ """ |
+ scope = scope # silence gpylint. |
+ self.Documentation(parent_section, obj, '') |
+ parent_section.PushNamespace(obj.name) |
+ self.DefinitionList(parent_section, obj, obj.defn_list) |
+ parent_section.PopNamespace() |
+ |
+ def Typename(self, parent_section, scope, obj): |
+ """Generates the code for a Typename definition. |
+ |
+ Since typenames (undefined types) cannot be expressed in C++, this function |
+ will not output code. The definition may be output with a verbatim section. |
+ |
+ Args: |
+ parent_section: the main section of the parent scope. |
+ scope: the parent scope. |
+ obj: the Typename definition. |
+ """ |
+ # silence gpylint. |
+ parent_section, scope, obj = parent_section, scope, obj |
+ |
+ def Enum(self, parent_section, scope, obj): |
+ """Generates the code for an Enum definition. |
+ |
+ Args: |
+ parent_section: the main section of the parent scope. |
+ scope: the parent scope. |
+ obj: the Enum definition. |
+ """ |
+ scope = scope # silence gpylint. |
+ section = self.GetSectionFromAttributes(parent_section, obj) |
+ self.Documentation(parent_section, obj, '') |
+ section.EmitCode('enum %s {' % obj.name) |
+ for value in obj.values: |
+ if value.value is None: |
+ section.EmitCode('%s,' % value.name) |
+ else: |
+ section.EmitCode('%s = %s,' % (value.name, value.value)) |
+ section.EmitCode('};') |
+ |
+ def DefinitionList(self, parent_section, scope, defn_list): |
+ """Generates the code for all the definitions in a list. |
+ |
+ Args: |
+ parent_section: the main section of the parent scope. |
+ scope: the parent scope. |
+ defn_list: the list of definitions. |
+ """ |
+ for obj in defn_list: |
+ if 'nojs' in obj.attributes: |
+ continue |
+ func = getattr(self, obj.defn_type) |
+ func(parent_section, scope, obj) |
+ |
+ def Documentation(self, parent_section, obj, extra_doc): |
+ """Generates the documentation code. |
+ |
+ Args: |
+ parent_section: the main section of the parent scope. |
+ obj: the object to be documented; may be class, function, enum or field. |
+ extra_doc: extra documenation information to be put in comments |
+ Raises: |
+ UndocumentedError: an error if there is no documentation |
+ """ |
+ try: |
+ section = self.GetSectionFromAttributes(parent_section, obj) |
+ comment_lines = obj.attributes['__docs'].splitlines() |
+ # Break up text and insert comment formatting |
+ section.EmitCode('/*! ') |
+ for line in comment_lines: |
+ section.EmitCode('%s' % (line)) |
+ section.EmitCode('%s' % (extra_doc)) |
+ section.EmitCode('*/') |
+ |
+ except KeyError: |
+ # catch the error when __docs does not exist |
+ if self.force_documentation: |
+ source = obj.source |
+ print ('%s:%d Documentation not found' % (source.file.source, |
+ source.line)) |
+ raise UndocumentedError('Documentation not found.') |
+ |
+ def FieldFunctionDocumentation(self, member_section, description, |
+ type_string, field_name): |
+ """Automatically generate the get/set function documentation code. |
+ |
+ Args: |
+ member_section: the main section of the getter/setter scope. |
+ description: describes the field function. |
+ type_string: string defining field type. |
+ field_name: getter/setter field name. |
+ """ |
+ member_section.EmitCode('/*!') |
+ member_section.EmitCode('* %s for %s %s' % |
+ (description, type_string, field_name)) |
+ member_section.EmitCode('*/') |
+ |
+ def Generate(self, idl_file, namespace, defn_list): |
+ """Generates the header file. |
+ |
+ Args: |
+ idl_file: the source IDL file containing the definitions, as a |
+ idl_parser.File instance. |
+ namespace: a Definition for the global namespace. |
+ defn_list: the list of top-level definitions. |
+ |
+ Returns: |
+ a cpp_utils.CppFileWriter that contains the C++ header file code. |
+ |
+ Raises: |
+ CircularDefinition: circular definitions were found in the file. |
+ """ |
+ writer = cpp_utils.CppFileWriter('%s/%s' % (self._output_dir, |
+ idl_file.header), True) |
+ code_section = writer.CreateSection('defns') |
+ self.DefinitionList(code_section, namespace, defn_list) |
+ return writer |
+ |
+ |
+def ProcessFiles(output_dir, pairs, namespace): |
+ """Generates the headers for all input files. |
+ |
+ Args: |
+ output_dir: the output directory. |
+ pairs: a list of (idl_parser.File, syntax_tree.Definition list) describing |
+ the list of top-level definitions in each source file. |
+ namespace: a syntax_tree.Namespace for the global namespace. |
+ |
+ Returns: |
+ a list of cpp_utils.CppFileWriter, one for each output header file. |
+ """ |
+ generator = CPPHeaderGenerator(output_dir) |
+ writer_list = [] |
+ for (f, defn) in pairs: |
+ writer_list.append(generator.Generate(f, namespace, defn)) |
+ return writer_list |
+ |
+ |
+def main(): |
+ pass |
+ |
+if __name__ == '__main__': |
+ main() |
Property changes on: tools/nixysa/nixysa/cpp_header_generator.py |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |