Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Unified Diff: tools/nixysa/nixysa/npapi_generator.py

Issue 2043006: WTF NPAPI extension. Early draft. Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/nixysa/nixysa/naming_test.py ('k') | tools/nixysa/nixysa/npapi_utils.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/nixysa/nixysa/npapi_generator.py
===================================================================
--- tools/nixysa/nixysa/npapi_generator.py (revision 0)
+++ tools/nixysa/nixysa/npapi_generator.py (revision 0)
@@ -0,0 +1,2386 @@
+#!/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.
+
+"""NPAPI glue generator.
+
+This module implements the generator for NPAPI glue code.
+
+For each class, the generator will create two NPObject classes:
+ - one for the class instances, exposing all the member functions and
+ properties, that wraps C++ instances. This one is created by the binding
+ model module - this is called the 'instance object'
+ - one for all the static members, like static functions and properties, but
+ also inner types. Only one instance of this one will be created. This one
+ is common to all the binding models, and is defined in static_object.h
+ (glue::globals::NPAPIObject) - this is called the 'static object'
+
+For namespaces, one of the second type is created as well (containing global
+functions and properties, and inner namespaces/classes).
+
+That way if the IDL contains something like:
+
+ namespace A {
+ class B {
+ static void C();
+ };
+ }
+
+then one can access C in JavaScript through plugin.A.B.C();
+
+The tricky part in this is that for namespaces, the definition of all the
+members spans across multiple namespace definitions, possibly across multiple
+files, but only one NPObject should exist, gathering all the members from all
+the namespace definitions - that means the glue has to be generated for all the
+definitions at once, generating the glue for each file separately will not
+work. By convention, the NPAPI glue for a namespace will be defined in the
+first file encountered that has a part of the namespace definition.
+
+Because of that, the code generation happens in 2 passes. The first one
+generates the code for all the definitions except the namespaces, and gather
+all the data for the namespace generation. Then the second pass generates the
+code for the namespaces.
+"""
+
+import string
+import cpp_utils
+import globals_binding
+import idl_parser
+import naming
+import npapi_utils
+import pod_binding
+import syntax_tree
+
+
+# default includes to add to the generated glue files
+
+_cpp_includes = [('plugin_main.h', False)]
+
+_header_includes = [('string.h', True),
+ ('string', True),
+ ('npapi.h', True),
+ ('npruntime.h', True),
+ ('common.h', False),
+ ('static_object.h', False)]
+
+
+# glue templates and helper strings
+
+_enumerate_static_property_entries = """
+ memcpy(output, static_property_ids,
+ NUM_STATIC_PROPERTY_IDS * sizeof(NPIdentifier));
+ output += NUM_STATIC_PROPERTY_IDS;
+"""
+
+_enumerate_static_method_entries = """
+ memcpy(output, static_method_ids,
+ NUM_STATIC_METHOD_IDS * sizeof(NPIdentifier));
+ output += NUM_STATIC_METHOD_IDS;
+"""
+
+_enumerate_namespace_entries = """
+ memcpy(output, namespace_ids,
+ NUM_NAMESPACE_IDS * sizeof(NPIdentifier));
+ output += NUM_NAMESPACE_IDS;
+"""
+
+_enumerate_property_entries = """
+ memcpy(output, property_ids,
+ NUM_PROPERTY_IDS * sizeof(NPIdentifier));
+ output += NUM_PROPERTY_IDS;
+"""
+
+_enumerate_method_entries = """
+ memcpy(output, method_ids,
+ NUM_METHOD_IDS * sizeof(NPIdentifier));
+ output += NUM_METHOD_IDS;
+"""
+
+_class_glue_header_static = """
+void InitializeGlue(NPP npp);
+NPClass *GetStaticNPClass(void);
+glue::globals::NPAPIObject *CreateRawStaticNPObject(NPP npp);
+void RegisterObjectBases(glue::globals::NPAPIObject *namespace_object,
+ glue::globals::NPAPIObject *root_object);
+glue::globals::NPAPIObject *GetStaticNPObject(
+ glue::globals::NPAPIObject *root_object);
+void StaticEnumeratePropertyHelper(NPIdentifier *output);
+uint32_t GetStaticPropertyCount();
+bool StaticInvoke(glue::globals::NPAPIObject *object,
+ NPP npp,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result,
+ const char **error_handle);
+bool StaticGetProperty(glue::globals::NPAPIObject *object,
+ NPP npp,
+ NPIdentifier name,
+ NPVariant *variant,
+ const char **error_handle);
+bool StaticSetProperty(glue::globals::NPAPIObject *object,
+ NPP npp,
+ NPIdentifier name,
+ const NPVariant *variant,
+ const char **error_handle);
+"""
+
+_class_glue_header_member = """
+NPClass *GetNPClass(void);
+bool Invoke(${ClassMutableParamType} object,
+ NPP npp,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result,
+ const char **error_handle);
+bool GetProperty(${ClassParamType} object,
+ NPP npp,
+ NPIdentifier name,
+ NPVariant *variant,
+ const char **error_handle);
+bool SetProperty(${ClassMutableParamType} object,
+ NPP npp,
+ NPIdentifier name,
+ const NPVariant *variant,
+ const char **error_handle);
+bool EnumeratePropertyEntries(NPObject *header,
+ NPIdentifier **value,
+ uint32_t *count);
+void EnumeratePropertyEntriesHelper(NPIdentifier *output);
+uint32_t GetPropertyCount();
+
+${BindingGlueHeader}
+"""
+
+_class_glue_header_template = string.Template(_class_glue_header_static +
+ _class_glue_header_member)
+
+_class_glue_cpp_common_head_static = """
+static bool StaticHasMethod(NPObject *header, NPIdentifier name);
+static bool StaticInvokeEntry(NPObject *header,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result);
+static bool StaticInvokeDefault(NPObject *header,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result);
+static bool StaticHasProperty(NPObject *header, NPIdentifier name);
+static bool StaticGetPropertyEntry(NPObject *header,
+ NPIdentifier name,
+ NPVariant *variant);
+static bool StaticSetPropertyEntry(NPObject *header,
+ NPIdentifier name,
+ const NPVariant *variant);
+static bool StaticEnumeratePropertyEntries(NPObject *header,
+ NPIdentifier **value,
+ uint32_t *count);
+void StaticEnumeratePropertyHelper(NPIdentifier *output);
+uint32_t GetStaticPropertyCount();
+
+static NPClass static_npclass = {
+ NP_CLASS_STRUCT_VERSION,
+ glue::globals::Allocate,
+ glue::globals::Deallocate,
+ 0,
+ StaticHasMethod,
+ StaticInvokeEntry,
+ StaticInvokeDefault,
+ StaticHasProperty,
+ StaticGetPropertyEntry,
+ StaticSetPropertyEntry,
+ 0,
+ StaticEnumeratePropertyEntries,
+};
+
+NPClass *GetStaticNPClass(void)
+{
+ return &static_npclass;
+}
+
+${StaticPropertyTable}
+${StaticMethodTable}
+${NamespaceTable}
+
+uint32_t GetStaticPropertyCount() {
+ return ${StaticPropertyCount} + ${StaticMethodCount} + ${NamespaceCount};
+}
+
+static bool StaticEnumeratePropertyEntries(NPObject *header,
+ NPIdentifier **value,
+ uint32_t *count) {
+ *count = 0;
+ glue::globals::NPAPIObject *object =
+ static_cast<glue::globals::NPAPIObject *>(header);
+ NPP npp = object->npp();
+ GLUE_SCOPED_PROFILE(npp, "${Class}::StaticEnumeratePropertyEntries", prof);
+ ${AddStaticPropertyCount}
+ ${AddStaticMethodCount}
+ ${AddNamespaceCount}
+ if (*count) {
+ GLUE_PROFILE_START(npp, "memalloc");
+ *value = static_cast<NPIdentifier *>(
+ NPN_MemAlloc(*count * sizeof(NPIdentifier)));
+ GLUE_PROFILE_STOP(npp, "memalloc");
+ StaticEnumeratePropertyHelper(*value);
+ } else {
+ *value = NULL;
+ }
+ return true;
+}
+
+// This is broken out into a separate function so that the plugin object can
+// call it on the global namespace without extra memory allocation.
+// The caller is responsible for making sure there's sufficient space in output.
+void StaticEnumeratePropertyHelper(NPIdentifier *output) {
+ ${EnumerateStaticPropertyEntries}
+ ${EnumerateStaticMethodEntries}
+ ${EnumerateNamespaceEntries}
+}
+
+static void InitializeStaticIds(NPP npp) {
+ ${StaticPropertyInit}
+ ${StaticMethodInit}
+ ${NamespaceInit}
+ ${#InitNamespaceGlues}
+}
+
+glue::globals::NPAPIObject *CreateRawStaticNPObject(NPP npp) {
+ GLUE_PROFILE_START(npp, "createobject");
+ glue::globals::NPAPIObject *object =
+ static_cast<glue::globals::NPAPIObject *>(
+ NPN_CreateObject(npp, &static_npclass));
+ GLUE_PROFILE_STOP(npp, "createobject");
+ ${#CreateNamespaces}
+ return object;
+}
+
+void RegisterObjectBases(glue::globals::NPAPIObject *namespace_object,
+ glue::globals::NPAPIObject *root_object) {
+ ${#RegisterBases}
+}
+
+${#GetStaticObjects}
+
+bool StaticInvokeDefault(NPObject *header,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result) {
+ const char *error=NULL;
+ const char **error_handle = &error;
+ bool success = true;
+ glue::globals::NPAPIObject *object =
+ static_cast<glue::globals::NPAPIObject *>(header);
+ NPP npp = object->npp();
+ GLUE_SCOPED_PROFILE(npp, "${Class}::StaticInvokeDefault", prof);
+ ${#StaticInvokeDefaultCode}
+ // Skip out early on the profiling, so as not to count error callback time.
+ GLUE_SCOPED_PROFILE_STOP(prof);
+ if (!success && error) {
+ glue::globals::SetLastError(npp, error);
+ }
+ return false;
+}
+
+static bool StaticInvokeEntry(NPObject *header,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result) {
+ // Chrome transforms InvokeDefault into Invoke with null parameter:
+ // http://code.google.com/p/chromium/issues/detail?id=5110
+ if (name == NULL)
+ return StaticInvokeDefault(header, args, argCount, result);
+ const char *error=NULL;
+ DebugScopedId id(name); // debug helper
+ glue::globals::NPAPIObject *object =
+ static_cast<glue::globals::NPAPIObject *>(header);
+ NPP npp = object->npp();
+ GLUE_PROFILE_START(npp, std::string("${Class}::StaticInvokeEntry(") +
+ (id.text() ? id.text() : "") + ")");
+ bool success = StaticInvoke(object, npp, name, args, argCount, result,
+ &error);
+ GLUE_PROFILE_STOP(npp, std::string("${Class}::StaticInvokeEntry(") +
+ (id.text() ? id.text() : "") + ")");
+ if (!success && error) {
+ glue::globals::SetLastError(npp, error);
+ }
+ return success;
+}
+
+static bool StaticGetPropertyEntry(NPObject *header,
+ NPIdentifier name,
+ NPVariant *variant) {
+ const char *error=NULL;
+ DebugScopedId id(name); // debug helper
+ glue::globals::NPAPIObject *object =
+ static_cast<glue::globals::NPAPIObject *>(header);
+ NPP npp = object->npp();
+ GLUE_PROFILE_START(npp, std::string("${Class}::StaticGetPropertyEntry(") +
+ (id.text() ? id.text() : "") + ")");
+ bool success = StaticGetProperty(object, npp, name, variant, &error);
+ GLUE_PROFILE_STOP(npp, std::string("${Class}::StaticGetPropertyEntry(") +
+ (id.text() ? id.text() : "") + ")");
+ if (!success && error) {
+ glue::globals::SetLastError(npp, error);
+ }
+ return success;
+}
+
+static bool StaticSetPropertyEntry(NPObject *header,
+ NPIdentifier name,
+ const NPVariant *variant) {
+ const char *error=NULL;
+ DebugScopedId id(name); // debug helper
+ glue::globals::NPAPIObject *object =
+ static_cast<glue::globals::NPAPIObject *>(header);
+ NPP npp = object->npp();
+ GLUE_PROFILE_START(npp, std::string("${Class}::StaticSetPropertyEntry(") +
+ (id.text() ? id.text() : "") + ")");
+ bool success = StaticSetProperty(object, npp, name, variant, &error);
+ GLUE_PROFILE_STOP(npp, std::string("${Class}::StaticSetPropertyEntry(") +
+ (id.text() ? id.text() : "") + ")");
+ if (!success && error) {
+ glue::globals::SetLastError(npp, error);
+ }
+ return success;
+}
+
+"""
+
+_class_glue_cpp_common_head_member = """
+static NPObject *Allocate(NPP npp, NPClass *theClass);
+static void Deallocate(NPObject *header);
+static bool HasMethod(NPObject *header, NPIdentifier name);
+static bool InvokeEntry(NPObject *header,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result);
+static bool HasProperty(NPObject *header, NPIdentifier name);
+static bool GetPropertyEntry(NPObject *header,
+ NPIdentifier name,
+ NPVariant *variant);
+static bool SetPropertyEntry(NPObject *header,
+ NPIdentifier name,
+ const NPVariant *variant);
+bool EnumeratePropertyEntries(NPObject *header,
+ NPIdentifier **value,
+ uint32_t *count);
+void EnumeratePropertyEntriesHelper(NPIdentifier *output);
+uint32_t GetPropertyCount();
+static uint32_t GetLocalPropertyCount();
+
+
+
+static NPClass npclass = {
+ NP_CLASS_STRUCT_VERSION,
+ Allocate,
+ Deallocate,
+ 0,
+ HasMethod,
+ InvokeEntry,
+ 0,
+ HasProperty,
+ GetPropertyEntry,
+ SetPropertyEntry,
+ 0,
+ EnumeratePropertyEntries
+};
+
+NPClass *GetNPClass(void)
+{
+ return &npclass;
+}
+
+${PropertyTable}
+${MethodTable}
+
+uint32_t GetPropertyCount() {
+ return GetLocalPropertyCount() + ${BaseGetPropertyCount};
+}
+
+static uint32_t GetLocalPropertyCount() {
+ return ${PropertyCount} + ${MethodCount};
+}
+
+bool EnumeratePropertyEntries(NPObject *header,
+ NPIdentifier **value,
+ uint32_t *count) {
+ glue::globals::NPAPIObject *object =
+ static_cast<glue::globals::NPAPIObject *>(header);
+ NPP npp = object->npp();
+ GLUE_PROFILE_START(npp, "${Class}::EnumeratePropertyEntries");
+ *count = GetPropertyCount();
+ GLUE_PROFILE_START(npp, "memalloc");
+ *value = static_cast<NPIdentifier *>(
+ NPN_MemAlloc(*count * sizeof(NPIdentifier)));
+ GLUE_PROFILE_STOP(npp, "memalloc");
+ EnumeratePropertyEntriesHelper(*value);
+ GLUE_PROFILE_STOP(npp, "${Class}::EnumeratePropertyEntries");
+ return true;
+}
+
+// This is broken out into a separate function so that derived classes can
+// call it as well without extra memory allocation.
+// The caller is responsible for making sure there's sufficient space in output.
+void EnumeratePropertyEntriesHelper(NPIdentifier *output) {
+ ${EnumeratePropertyEntries}
+ ${EnumerateMethodEntries}
+ ${EnumeratePropertyEntriesHelperBaseCall}
+}
+
+static void InitializeMemberIds(NPP npp) {
+ ${PropertyInit}
+ ${MethodInit}
+}
+
+static void InitializeIds(NPP npp) {
+ InitializeMemberIds(npp);
+ InitializeStaticIds(npp);
+}
+
+static bool InvokeEntry(NPObject *header,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result) {
+ const char *error=NULL;
+ const char **error_handle = &error;
+ DebugScopedId id(name); // debug helper
+ bool success = true;
+ ${DispatchFunctionHeader}
+ // Profile is a bit late, but it makes npp lookup easier.
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::InvokeEntry(") + (id.text() ?
+ id.text() : "") + ")", prof);
+ if (!success) return false;
+ bool ret = Invoke(${Object}, npp, name, args, argCount, result, error_handle);
+ GLUE_SCOPED_PROFILE_STOP(prof);
+ if (!ret && error) {
+ glue::globals::SetLastError(npp, error);
+ return false;
+ }
+ return ret;
+}
+
+static bool GetPropertyEntry(NPObject *header,
+ NPIdentifier name,
+ NPVariant *variant) {
+ const char *error=NULL;
+ const char **error_handle = &error;
+ DebugScopedId id(name); // debug helper
+ bool success = true;
+ ${DispatchFunctionHeader}
+ // Profile is a bit late, but it makes npp lookup easier.
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::GetPropertyEntry(") +
+ (id.text() ? id.text() : "") + ")", prof);
+ if (!success) return false; // A rare error case.
+ bool ret = GetProperty(${ObjectNonMutable}, npp, name, variant, error_handle);
+ GLUE_SCOPED_PROFILE_STOP(prof);
+ if (!ret && error) {
+ glue::globals::SetLastError(npp, error);
+ return false;
+ }
+ return ret;
+}
+
+static bool SetPropertyEntry(NPObject *header,
+ NPIdentifier name,
+ const NPVariant *variant) {
+ const char *error=NULL;
+ const char **error_handle = &error;
+ DebugScopedId id(name); // debug helper
+ bool success = true;
+ ${DispatchFunctionHeader}
+ // Profile is a bit late, but it makes npp lookup easier.
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::SetPropertyEntry(") +
+ (id.text() ? id.text() : "") + ")", prof);
+ if (!success) return false; // A rare error case.
+ bool ret = SetProperty(${Object}, npp, name, variant, error_handle);
+ GLUE_SCOPED_PROFILE_STOP(prof);
+ if (!ret && error) {
+ glue::globals::SetLastError(npp, error);
+ return false;
+ }
+ return ret;
+}
+
+${BindingGlueCpp}
+"""
+
+_class_glue_cpp_base_member = """
+bool Invoke(${ClassMutableParamType} object,
+ NPP npp,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result,
+ const char **error_handle) {
+ DebugScopedId id(name); // debug helper
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::Invoke(") + (id.text() ?
+ id.text() : "") + ")", prof);
+ bool success = true;
+ ${#InvokeCode}
+ return ${BaseClassNamespace}::Invoke(object, npp, name, args, argCount,
+ result, error_handle);
+}
+
+bool GetProperty(${ClassParamType} object,
+ NPP npp,
+ NPIdentifier name,
+ NPVariant *variant,
+ const char **error_handle) {
+ DebugScopedId id(name); // debug helper
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::GetProperty(") + (id.text() ?
+ id.text() : "") + ")", prof);
+ ${#GetPropertyCode}
+ return ${BaseClassNamespace}::GetProperty(object, npp, name, variant,
+ error_handle);
+}
+
+bool SetProperty(${ClassMutableParamType} object,
+ NPP npp,
+ NPIdentifier name,
+ const NPVariant *variant,
+ const char **error_handle) {
+ DebugScopedId id(name); // debug helper
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::SetProperty(") + (id.text() ?
+ id.text() : "") + ")", prof);
+ ${#SetPropertyCode}
+ return ${BaseClassNamespace}::SetProperty(object, npp, name, variant,
+ error_handle);
+}
+
+static bool HasMethod(NPObject *header, NPIdentifier name) {
+ DebugScopedId id(name); // debug helper
+ glue::globals::NPAPIObject *object =
+ static_cast<glue::globals::NPAPIObject *>(header);
+ NPP npp = object->npp();
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::HasMethod(") + (id.text() ?
+ id.text() : "") + ")", prof);
+ ${MethodCheck}
+ return ${BaseClassNamespace}::GetNPClass()->hasMethod(header, name);
+}
+
+static bool HasProperty(NPObject *header, NPIdentifier name) {
+ DebugScopedId id(name); // debug helper
+ glue::globals::NPAPIObject *object =
+ static_cast<glue::globals::NPAPIObject *>(header);
+ NPP npp = object->npp();
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::HasProperty(") + (id.text() ?
+ id.text() : "") + ")", prof);
+ ${PropertyCheck}
+ return ${BaseClassNamespace}::GetNPClass()->hasProperty(header, name);
+}
+"""
+
+_class_glue_cpp_base_static = """
+bool StaticInvoke(glue::globals::NPAPIObject *object,
+ NPP npp,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result,
+ const char **error_handle) {
+ GLUE_SCOPED_PROFILE(npp, "${Class}::StaticInvoke", prof);
+ bool success = true;
+ ${#StaticInvokeCode}
+ return ${BaseClassNamespace}::StaticInvoke(
+ object->base(), npp, name, args, argCount, result, error_handle);
+}
+
+bool StaticGetProperty(glue::globals::NPAPIObject *object,
+ NPP npp,
+ NPIdentifier name,
+ NPVariant *variant,
+ const char **error_handle) {
+ GLUE_SCOPED_PROFILE(npp, "${Class}::StaticGetProperty", prof);
+ bool success = true;
+ ${#StaticGetPropertyCode}
+ if (glue::globals::GetProperty(object, name, variant)) return true;
+ return ${BaseClassNamespace}::StaticGetProperty(
+ object->base(), npp, name, variant, error_handle);
+}
+
+bool StaticSetProperty(glue::globals::NPAPIObject *object,
+ NPP npp,
+ NPIdentifier name,
+ const NPVariant *variant,
+ const char **error_handle) {
+ GLUE_SCOPED_PROFILE(npp, "${Class}::StaticSetProperty", prof);
+ bool success = true;
+ ${#StaticSetPropertyCode}
+ if (glue::globals::SetProperty(object, name, variant)) return true;
+ return ${BaseClassNamespace}::StaticSetProperty(
+ object->base(), npp, name, variant, error_handle);
+}
+
+static bool StaticHasMethod(NPObject *header, NPIdentifier name) {
+ DebugScopedId id(name); // debug helper
+ glue::globals::NPAPIObject *object =
+ static_cast<glue::globals::NPAPIObject *>(header);
+ NPP npp = object->npp();
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::StaticHasMethod(") +
+ (id.text() ? id.text() : "") + ")", prof);
+ ${StaticMethodCheck}
+ GLUE_SCOPED_PROFILE(npp, "hasmethod", prof1);
+ return NPN_HasMethod(npp, object->base(), name);
+}
+
+static bool StaticHasProperty(NPObject *header, NPIdentifier name) {
+ DebugScopedId id(name); // debug helper
+ glue::globals::NPAPIObject *object =
+ static_cast<glue::globals::NPAPIObject *>(header);
+ NPP npp = object->npp();
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::StaticHasProperty(") +
+ (id.text() ? id.text() : "") + ")", prof);
+ ${StaticPropertyCheck}
+ bool success = glue::globals::HasProperty(header, name);
+ if (success) {
+ return success;
+ }
+ GLUE_SCOPED_PROFILE(npp, "hasproperty", prof1);
+ return NPN_HasProperty(npp, object->base(), name);
+}
+
+"""
+_class_glue_cpp_no_base_member = """
+bool Invoke(${ClassMutableParamType} object,
+ NPP npp,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result,
+ const char **error_handle) {
+ DebugScopedId id(name); // debug helper
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::Invoke(") + (id.text() ?
+ id.text() : "") + ")", prof);
+ bool success = true;
+ ${#InvokeCode}
+ if (!*error_handle) {
+ *error_handle =
+ "Method not found; perhaps it doesn't take that number of arguments?";
+ }
+ return false;
+}
+
+bool GetProperty(${ClassParamType} object,
+ NPP npp,
+ NPIdentifier name,
+ NPVariant *variant,
+ const char **error_handle) {
+ DebugScopedId id(name); // debug helper
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::GetProperty(") + (id.text() ?
+ id.text() : "") + ")", prof);
+ ${#GetPropertyCode}
+ if (!*error_handle) {
+ *error_handle = "Property not found.";
+ }
+ return false;
+}
+
+bool SetProperty(${ClassMutableParamType} object,
+ NPP npp,
+ NPIdentifier name,
+ const NPVariant *variant,
+ const char **error_handle) {
+ DebugScopedId id(name); // debug helper
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::SetProperty(") + (id.text() ?
+ id.text() : "") + ")", prof);
+ ${#SetPropertyCode}
+ if (!*error_handle) {
+ *error_handle = "Property not found.";
+ }
+ return false;
+}
+
+static bool HasMethod(NPObject *header, NPIdentifier name) {
+ DebugScopedId id(name); // debug helper
+ glue::globals::NPAPIObject *object =
+ static_cast<glue::globals::NPAPIObject *>(header);
+ NPP npp = object->npp();
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::HasMethod(") + (id.text() ?
+ id.text() : "") + ")", prof);
+ ${MethodCheck}
+ return false;
+}
+
+static bool HasProperty(NPObject *header, NPIdentifier name) {
+ DebugScopedId id(name); // debug helper
+ glue::globals::NPAPIObject *object =
+ static_cast<glue::globals::NPAPIObject *>(header);
+ NPP npp = object->npp();
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::HasProperty(") + (id.text() ?
+ id.text() : "") + ")", prof);
+ ${PropertyCheck}
+ return false;
+}
+"""
+
+_class_glue_cpp_no_base_static = """
+bool StaticInvoke(glue::globals::NPAPIObject *object,
+ NPP npp,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result,
+ const char **error_handle) {
+ GLUE_SCOPED_PROFILE(npp, "${Class}::StaticInvoke", prof);
+ bool success = true;
+ ${#StaticInvokeCode}
+ return false;
+}
+
+bool StaticGetProperty(glue::globals::NPAPIObject *object,
+ NPP npp,
+ NPIdentifier name,
+ NPVariant *variant,
+ const char **error_handle) {
+ GLUE_SCOPED_PROFILE(npp, "${Class}::StaticGetProperty", prof);
+ bool success = true;
+ ${#StaticGetPropertyCode}
+ success = glue::globals::GetProperty(object, name, variant);
+ return success;
+}
+
+bool StaticSetProperty(glue::globals::NPAPIObject *object,
+ NPP npp,
+ NPIdentifier name,
+ const NPVariant *variant,
+ const char **error_handle) {
+ GLUE_SCOPED_PROFILE(npp, "${Class}::StaticSetProperty", prof);
+ bool success = true;
+ ${#StaticSetPropertyCode}
+ if (glue::globals::SetProperty(object, name, variant)) return true;
+ return false;
+}
+
+static bool StaticHasMethod(NPObject *header, NPIdentifier name) {
+ DebugScopedId id(name); // debug helper
+ glue::globals::NPAPIObject *object =
+ static_cast<glue::globals::NPAPIObject *>(header);
+ NPP npp = object->npp();
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::StaticHasMethod(") +
+ (id.text() ? id.text() : "") + ")", prof);
+ ${StaticMethodCheck}
+ return false;
+}
+
+static bool StaticHasProperty(NPObject *header, NPIdentifier name) {
+ DebugScopedId id(name); // debug helper
+ glue::globals::NPAPIObject *object =
+ static_cast<glue::globals::NPAPIObject *>(header);
+ NPP npp = object->npp();
+ GLUE_SCOPED_PROFILE(npp, std::string("${Class}::StaticHasProperty(") +
+ (id.text() ? id.text() : "") + ")", prof);
+ ${StaticPropertyCheck}
+ return glue::globals::HasProperty(header, name);
+}
+"""
+
+_namespace_glue_cpp_tail = """
+void InitializeGlue(NPP npp) {
+ InitializeStaticIds(npp);
+}
+"""
+
+_class_glue_cpp_base_template = string.Template(''.join([
+ _class_glue_cpp_common_head_static,
+ _class_glue_cpp_common_head_member,
+ _class_glue_cpp_base_static,
+ _class_glue_cpp_base_member]))
+
+_class_glue_cpp_no_base_template = string.Template(''.join([
+ _class_glue_cpp_common_head_static,
+ _class_glue_cpp_common_head_member,
+ _class_glue_cpp_no_base_static,
+ _class_glue_cpp_no_base_member]))
+
+_namespace_glue_header = _class_glue_header_static
+
+_namespace_glue_cpp_template = string.Template(''.join([
+ _class_glue_cpp_common_head_static,
+ _class_glue_cpp_no_base_static,
+ _namespace_glue_cpp_tail]))
+
+_callback_glue_cpp_template = string.Template("""
+${RunCallback} {
+${StartException}
+ const char *error=NULL;
+ const char **error_handle = &error;
+ bool success = true;
+ NPVariant args[${ArgCount}];
+ NPVariant result;
+ NULL_TO_NPVARIANT(result);
+ ${ParamsToVariantsPre}
+ if (success) {
+ ${ParamsToVariantsPost}
+ if (async && NPCallback::SupportsAsync()) {
+ NPCallback* callback = NPCallback::Create(npp);
+ if (callback) {
+ callback->Set(npobject, args, ${ArgCount});
+ callback->CallAsync();
+ NPN_ReleaseObject(callback);
+ success = true;
+ } else {
+ success = false;
+ }
+ } else {
+ GLUE_PROFILE_START(npp, "invokeDefault");
+ success = NPN_InvokeDefault(npp,
+ npobject,
+ args,
+ ${ArgCount},
+ &result);
+ GLUE_PROFILE_STOP(npp, "invokeDefault");
+ if (success) {
+ GLUE_PROFILE_START(npp, "NPN_ReleaseVariantValue");
+ NPN_ReleaseVariantValue(&result);
+ GLUE_PROFILE_STOP(npp, "NPN_ReleaseVariantValue");
+ }
+ }
+ }
+ for (int i = 0; i != ${ArgCount}; ++i) {
+ NPN_ReleaseVariantValue(&args[i]);
+ }
+ ${ReturnEval}
+ return ${ReturnValue};
+${EndException}
+}
+""")
+
+_callback_no_param_glue_cpp_template = string.Template("""
+${RunCallback} {
+${StartException}
+ const char *error=NULL;
+ const char **error_handle = &error;
+ bool success = true;
+ NPVariant result;
+ NULL_TO_NPVARIANT(result);
+ if (success) {
+ if (async && NPCallback::SupportsAsync()) {
+ NPCallback* callback = NPCallback::Create(npp);
+ if (callback) {
+ callback->Set(npobject, NULL, 0);
+ callback->CallAsync();
+ NPN_ReleaseObject(callback);
+ success = true;
+ } else {
+ success = false;
+ }
+ } else {
+ GLUE_PROFILE_START(npp, "invokeDefault");
+ success = NPN_InvokeDefault(npp,
+ npobject,
+ NULL,
+ 0,
+ &result);
+ GLUE_PROFILE_STOP(npp, "invokeDefault");
+ if (success) {
+ GLUE_PROFILE_START(npp, "NPN_ReleaseVariantValue");
+ NPN_ReleaseVariantValue(&result);
+ GLUE_PROFILE_STOP(npp, "NPN_ReleaseVariantValue");
+ }
+ }
+ }
+ ${ReturnEval}
+ return ${ReturnValue};
+${EndException}
+}
+""")
+
+
+_initialize_glue_template = string.Template(
+ '${Namespace}::InitializeGlue(npp);')
+
+_create_namespace_template = string.Template("""
+object->SetNamespaceObject(${PROPERTY},
+ ${Namespace}::CreateRawStaticNPObject(npp));""")
+
+_register_base_template = string.Template("""
+{
+ glue::globals::NPAPIObject *object =
+ namespace_object->GetNamespaceObjectByIndex(${PROPERTY});
+ object->set_base(${BaseClassNamespace}::GetStaticNPObject(root_object));
+ ${Namespace}::RegisterObjectBases(object, root_object);
+}""")
+
+_register_no_base_template = string.Template("""
+{
+ glue::globals::NPAPIObject *object =
+ namespace_object->GetNamespaceObjectByIndex(${PROPERTY});
+ ${Namespace}::RegisterObjectBases(object, root_object);
+}""")
+
+_get_ns_object_template = string.Template("""
+namespace ${Namespace} {
+glue::globals::NPAPIObject *GetStaticNPObject(
+ glue::globals::NPAPIObject *root_object) {
+ glue::globals::NPAPIObject *parent =
+ ${ParentNamespace}::GetStaticNPObject(root_object);
+ return parent->GetNamespaceObjectByIndex(${PROPERTY});
+}
+} // namespace ${Namespace}""")
+
+_globals_glue_header_tail = """
+glue::globals::NPAPIObject *CreateStaticNPObject(NPP npp);
+"""
+
+_globals_glue_cpp_tail = """
+glue::globals::NPAPIObject *GetStaticNPObject(
+ glue::globals::NPAPIObject *root_object) {
+ return root_object;
+}
+
+glue::globals::NPAPIObject *CreateStaticNPObject(NPP npp) {
+ glue::globals::NPAPIObject *root_object = CreateRawStaticNPObject(npp);
+ RegisterObjectBases(root_object, root_object);
+ return root_object;
+}
+"""
+
+# code pieces templates
+
+_method_invoke_template = string.Template("""
+ if (name == ${table}[${method_id}] && argCount == ${argCount}) do {
+ bool success = true;
+ ${code}
+ } while(false);""")
+
+_method_default_invoke_template = string.Template("""
+ if (argCount == ${argCount}) do {
+ bool success = true;
+ ${code}
+ } while(false);""")
+
+_property_template = string.Template("""
+ if (name == ${table}[${property_id}]) do {
+ bool success = true;
+ ${code}
+ } while(false);""")
+
+_failure_test_string = ' if (!success) break;'
+
+_exception_context_start_template = string.Template(
+ """#define ${exception_macro_name} "${type} '${name}'" """)
+
+_exception_context_end_template = string.Template(
+ """#undef ${exception_macro_name}""")
+
+_exception_macro_name = 'NPAPI_GLUE_EXCEPTION_CONTEXT'
+
+def GenExceptionContext(exception_macro_name, type, name):
+ """Create code to define the context for exception error messages.
+
+ Args:
+ exception_macro_name: the name to use for the macro
+ type: the type of access that name represents (field, parameter, etc.)
+ name: the name of the variable
+
+ Returns:
+ a tuple of 2 strings; the first #defines the text to stick in the
+ exception, and the second #undefs the string to clean up the namespace.
+ """
+ start = _exception_context_start_template.substitute(type=type,
+ name=name,
+ exception_macro_name=
+ exception_macro_name)
+ end = _exception_context_end_template.substitute(exception_macro_name=
+ exception_macro_name)
+ return (start, end)
+
+def GenEndExceptionContext(exception_macro_name):
+ """Create code to clean up the context definition for exception error
+ messages.
+
+ Args:
+ exception_macro_name: the name to use for the macro
+
+ Returns:
+ the string to #undef the macro
+ """
+
+def GetGlueHeader(idl_file):
+ """Gets the name of the glue header file.
+
+ Args:
+ idl_file: an idl_parser.File, the source IDL file.
+
+ Returns:
+ the name of the header file.
+ """
+ if 'npapi_header' in idl_file.__dict__:
+ return idl_file.npapi_header
+ else:
+ return idl_file.basename + '_glue.h'
+
+
+def GetGlueCpp(idl_file):
+ """Gets the name of the glue implementation file.
+
+ Args:
+ idl_file: an idl_parser.File, the source IDL file.
+
+ Returns:
+ the name of the implementation file.
+ """
+ if 'npapi_cpp' in idl_file.__dict__:
+ return idl_file.npapi_cpp
+ else:
+ return idl_file.basename + '_glue.cc'
+
+
+class MethodWithoutReturnType(Exception):
+ """Raised when finding a function without return type."""
+
+ def __init__(self, obj):
+ Exception.__init__(self)
+ self.object = obj
+
+
+def GenNamespaceCode(context):
+ """Generates the code for namespace glue.
+
+ This function generates the necessary code to initialize the
+ globals::NPAPIObject instance with the inner namespace objects.
+
+ Args:
+ context: the NpapiGenerator.CodeGenContext for generating the glue.
+
+ Returns:
+ a dict is generated by npapi_utils.MakeIdTableDict, and contains the
+ substitution strings for the namespace ids.
+ """
+ namespace_ids = []
+ if context.namespace_list:
+ context.namespace_create_section.EmitCode(
+ 'object->AllocateNamespaceObjects(NUM_NAMESPACE_IDS);')
+ context.namespace_create_section.EmitCode(
+ 'object->set_names(namespace_ids);')
+ for ns_obj in context.namespace_list:
+ id_enum = 'SCOPE_%s' % naming.Normalize(ns_obj.name, naming.Upper)
+ namespace_ids.append((id_enum, '"%s"' % ns_obj.name))
+ full_namespace = npapi_utils.GetGlueFullNamespace(ns_obj)
+ context.namespace_init_section.EmitCode(
+ _initialize_glue_template.substitute(Namespace=full_namespace))
+ context.namespace_create_section.EmitCode(
+ _create_namespace_template.substitute(PROPERTY=id_enum,
+ Namespace=full_namespace))
+ if ns_obj.defn_type == 'Class' and ns_obj.base_type:
+ base_class_namespace = npapi_utils.GetGlueFullNamespace(
+ ns_obj.base_type.GetFinalType())
+ context.namespace_register_base_section.EmitCode(
+ _register_base_template.substitute(
+ PROPERTY=id_enum,
+ BaseClassNamespace=base_class_namespace,
+ Namespace=full_namespace))
+ else:
+ context.namespace_register_base_section.EmitCode(
+ _register_no_base_template.substitute(PROPERTY=id_enum,
+ Namespace=full_namespace))
+
+ context.namespace_get_static_object_section.EmitCode(
+ _get_ns_object_template.substitute(
+ Namespace=npapi_utils.GetGlueNamespace(ns_obj.GetFinalType()),
+ ParentNamespace=npapi_utils.GetGlueFullNamespace(
+ ns_obj.parent.GetFinalType()),
+ PROPERTY=id_enum))
+ return npapi_utils.MakeIdTableDict(namespace_ids, 'namespace')
+
+
+def MakePodType(name):
+ """Creates a pod type with reasonable attributes.
+
+ This function is used to be able to generate parameters that are not directly
+ referenced in the IDL
+
+ Args:
+ name: the name of the pod type.
+
+ Returns:
+ a Definition for the type.
+ """
+ source_file = idl_parser.File('<internal>')
+ source_file.header = None
+ source_file.npapi_cpp = None
+ source_file.npapi_header = None
+ source = idl_parser.SourceLocation(source_file, 0)
+ attributes = {'binding_model': 'pod'}
+ type_defn = syntax_tree.Typename(source, attributes, name)
+ type_defn.binding_model = pod_binding
+ type_defn.podtype = 'variant'
+ return type_defn
+
+
+class NpapiGenerator(object):
+ """Main generator class."""
+
+ def __init__(self, output_dir):
+ """Inits a NpapiGenerator instance.
+
+ Args:
+ output_dir: the output directory for generated files.
+ """
+ self._output_dir = output_dir
+ self._namespace_map = {}
+ self._finalize_functions = []
+ # TODO: instead of passing a raw void *, it would be better to define a
+ # PluginInstance class. Needs a fair amount of refactoring in the C++ code.
+ self._plugin_data_type = MakePodType('void *')
+
+ class CodeGenContext(object):
+ """Code generation context.
+
+ This class gathers all the data that needs to be passed around in code
+ generation functions.
+
+ Note: the section fields of this class are generated programatically.
+
+ Attributes:
+ type: the container type (can be a Class or a Namespace).
+ binding_model: the binding model for the containing type.
+ is_namespace: whether or not the container is a namespace.
+ scope: current code generation scope, to generate properly qualified type
+ references.
+ header_section: the current code section in the header file.
+ cpp_section: the current code section in the implementation file.
+ static_prop_ids: the list of (enum_name, JS name) for properties in the
+ static object for the container type.
+ static_method_ids: the list of (enum_name, JS name) for methods in the
+ static object for the container type.
+ namespace_list: the list of inner namespace and classes of the container
+ type (to generate the static object)
+ prop_ids: the list of (enum_name, JS name) for properties in the
+ instance object for the container type.
+ method_ids: the list of (enum_name, JS name) for methods in the
+ instance object for the container type.
+ namespace_init_section: a section where the initialization code for the
+ namespaces in the static object will go.
+ namespace_create_section: a section where the globals::NPAPIObject
+ creation code will go.
+ namespace_register_base_section: a section where the class bases get
+ registered into their corresponding globals::NPAPIObject.
+ namespace_get_static_object_section: a section where the
+ GetStaticNPObject functions get defined.
+ static_invoke_section: a section where the Invoke implementation for the
+ static object will go (for static functions).
+ static_invoke_default_section: a section where the InvokeDefault
+ implementation for the static object will go (for constructors).
+ static_get_prop_section: a section where the GetProperty implementation
+ for the static object will go (for static members, enum values, and
+ inner namespaces).
+ static_set_prop_section: a section where the SetProperty implementation
+ for the static object will go (for static members).
+ invoke_section: a section where the Invoke implementation for the
+ instance object will go (for non-static methods).
+ get_prop_section: a section where the GetProperty implementation for the
+ instance object will go (for non-static members).
+ set_prop_section: a section where the SetProperty implementation for the
+ instance object will go (for non-static members).
+ """
+
+ _sections = [('namespace_init_section', 'InitNamespaceGlues'),
+ ('namespace_create_section', 'CreateNamespaces'),
+ ('namespace_register_base_section', 'RegisterBases'),
+ ('namespace_get_static_object_section', 'GetStaticObjects'),
+ ('static_invoke_section', 'StaticInvokeCode'),
+ ('static_invoke_default_section', 'StaticInvokeDefaultCode'),
+ ('static_get_prop_section', 'StaticGetPropertyCode'),
+ ('static_set_prop_section', 'StaticSetPropertyCode')]
+
+ _class_sections = [('invoke_section', 'InvokeCode'),
+ ('get_prop_section', 'GetPropertyCode'),
+ ('set_prop_section', 'SetPropertyCode')]
+
+ def __init__(self, type_defn, scope, header_section, cpp_section,
+ share_context):
+ """Inits a CodeGenContext.
+
+ Args:
+ type_defn: the container type.
+ scope: current code generation scope, to generate properly qualified
+ type references.
+ header_section: the current code section in the header file.
+ cpp_section: the current code section in the implementation file.
+ share_context: share the definition sections and the id lists with that
+ context (can be None) - used when encountering namespaces defined
+ previously.
+ """
+ self.type_defn = type_defn
+ self.binding_model = type_defn.binding_model or globals_binding
+ self.is_namespace = type_defn.defn_type == 'Namespace'
+ self.scope = scope
+ self.header_section = header_section
+ self.cpp_section = cpp_section
+ if self.is_namespace:
+ all_sections = self._sections
+ else:
+ all_sections = self._sections + self._class_sections
+ if share_context:
+ self.static_prop_ids = share_context.static_prop_ids
+ self.static_method_ids = share_context.static_method_ids
+ self.namespace_list = share_context.namespace_list
+ if not share_context.is_namespace:
+ self.prop_ids = share_context.prop_ids
+ self.method_ids = share_context.method_ids
+ # programmatically copy fields
+ for field_name, section_name in all_sections:
+ setattr(self, field_name, getattr(share_context, field_name))
+ else:
+ self.static_prop_ids = []
+ self.static_method_ids = []
+ self.namespace_list = []
+ if not self.is_namespace:
+ self.prop_ids = []
+ self.method_ids = []
+ # programmatically create fields
+ for field_name, section_name in all_sections:
+ setattr(self, field_name,
+ cpp_section.CreateUnlinkedSection(section_name))
+ getattr(self, field_name).needed_glue = cpp_section.needed_glue
+
+ def GetParamInputStrings(self, scope, param_list):
+ """Gets the code to retrieve parameters from an array of NPVariants.
+
+ Args:
+ scope: the code generation scope.
+ param_list: a list of Function.Param.
+
+ Returns:
+ a 3-uple. The first element is a list of strings that contains the code
+ to retrieve the parameter values. The second element is a list of
+ expressions to access each of the parameters. The third element is the set
+ of all the types whose glue header is needed.
+ """
+ strings = []
+ param_names = []
+ needed_glue = set()
+ for i in range(len(param_list)):
+ param = param_list[i]
+ needed_glue.add(param.type_defn)
+ param_binding = param.type_defn.binding_model
+ start_exception, end_exception = GenExceptionContext(
+ _exception_macro_name, "parameter",
+ naming.Normalize(param.name, naming.Java))
+ code, param_access = param_binding.NpapiFromNPVariant(
+ scope, param.type_defn, 'args[%d]' % i, 'param_%s' % param.name,
+ 'success', _exception_macro_name, 'npp')
+ strings.append(start_exception)
+ strings.append(code)
+ strings.append(_failure_test_string)
+ strings.append(end_exception)
+ param_names.append(param_access)
+ return strings, param_names, needed_glue
+
+ def GetReturnStrings(self, scope, type_defn, expression, result):
+ """Gets the code to set a return value into a NPVariant.
+
+ Args:
+ scope: the code generation scope.
+ type_defn: the type of the return value.
+ expression: the expression that evaluates to the return value.
+ result: the expression that evaluates to a pointer to the NPVariant.
+
+ Returns:
+ a 3-uple. The first element is the code to generate the
+ NPVariant-compatible value (that can fail). The second element is the
+ code to set the NPVariant. The third element is the set of all the types
+ whose glue header is needed.
+ """
+ binding_model = type_defn.binding_model
+ pre, post = binding_model.NpapiExprToNPVariant(scope, type_defn, 'retval',
+ expression, result,
+ 'success', 'npp')
+ return pre, post, set([type_defn])
+
+ def GetVoidReturnStrings(self, type_defn, result):
+ """Gets the code to return a void value for a write-only member.
+
+ Args:
+ type_defn: the type of the return value.
+ result: the expression that evaluates to a pointer to the NPVariant.
+
+ Returns:
+ a 3-uple. The first element is empty, and is needed only to mimic the
+ return of GetReturnStrings. The second element is the code to set the
+ NPVariant. The third element is the set of all the types whose glue
+ header is needed.
+ """
+ post = "VOID_TO_NPVARIANT(*%s);\n" % result
+ return "", post, set([type_defn])
+
+ def GenerateCppFunction(self, section, scope, function):
+ """Generates a function header.
+
+ Args:
+ section: the code section to generate the function header into.
+ scope: the code generation scope.
+ function: the Function to generate.
+ """
+ prototype, unused_val = cpp_utils.GetFunctionPrototype(scope, function, '')
+ section.EmitCode(prototype + ';')
+
+ def GetUserGlueMethodFunc(self, scope, type_defn, method):
+ """Creates a definition for the user glue function for a non-static method.
+
+ Args:
+ scope: the code generation scope.
+ type_defn: the type of the method container.
+ method: the method for which to create the user glue function.
+
+ Returns:
+ a syntax_tree.Function for the user glue function.
+ """
+ glue_function = syntax_tree.Function(method.source, [],
+ 'userglue_method_%s' % method.name,
+ None, [])
+ glue_function.type_defn = method.type_defn
+ glue_function.parent = scope
+ this_param = syntax_tree.Function.Param(type_defn.name, '_this')
+ this_param.type_defn = type_defn
+ this_param.mutable = True
+ glue_function.params = [this_param] + method.params
+ return glue_function
+
+ def GetUserGlueStaticMethodFunc(self, scope, method):
+ """Creates a definition for the user glue function for a static function.
+
+ Args:
+ scope: the code generation scope.
+ method: the method for which to create the user glue function.
+
+ Returns:
+ a syntax_tree.Function for the user glue function.
+ """
+ glue_function = syntax_tree.Function(method.source, [],
+ 'userglue_static_%s' % method.name,
+ None, [])
+ glue_function.type_defn = method.type_defn
+ glue_function.params = method.params[:]
+ glue_function.parent = scope
+ return glue_function
+
+ def GetUserGlueConstructorFunc(self, scope, type_defn, method):
+ """Creates a definition for the user glue function for a constructor.
+
+ Args:
+ scope: the code generation scope.
+ type_defn: the type of the method container.
+ method: the constructor for which to create the user glue function.
+
+ Returns:
+ a syntax_tree.Function for the user glue function.
+ """
+ glue_function = syntax_tree.Function(method.source, [],
+ 'userglue_construct_%s' % method.name,
+ None, [])
+ glue_function.type_defn = type_defn
+ glue_function.params = method.params[:]
+ glue_function.parent = scope
+ return glue_function
+
+ def GetUserGlueSetterFunc(self, scope, type_defn, field):
+ """Creates a definition for the user glue function for a setter method.
+
+ For a field name 'myField' of type "FieldType" in an object of type
+ 'ObjectType', this creates a function like:
+ void userglue_setter_myField(ObjectType _this, FieldType param_myField)
+
+ Args:
+ scope: the code generation scope.
+ type_defn: the type of the method container.
+ method: the method for which to create the user glue function.
+
+ Returns:
+ a syntax_tree.Function for the user glue function.
+ """
+ glue_function = syntax_tree.Function(field.source, [],
+ 'userglue_setter_%s' % field.name,
+ None, [])
+ glue_function.type_defn = scope.LookUpTypeRecursive('void')
+ glue_function.parent = scope
+ this_param = syntax_tree.Function.Param(type_defn.name, '_this')
+ this_param.type_defn = type_defn
+ this_param.mutable = True
+ value_param = syntax_tree.Function.Param(type_defn.name, 'param_' +
+ field.name)
+ value_param.type_defn = field.type_defn
+ glue_function.params = [this_param, value_param]
+ return glue_function
+
+ def GetUserGlueGetterFunc(self, scope, type_defn, field):
+ """Creates a definition for the user glue function for a getter method.
+
+ For a field name 'myField' of type "FieldType" in an object of type
+ 'ObjectType', this creates a function like:
+ FieldType userglue_getter_myField(ObjectType _this)
+
+ Args:
+ scope: the code generation scope.
+ type_defn: the type of the method container.
+ method: the method for which to create the user glue function.
+
+ Returns:
+ a syntax_tree.Function for the user glue function.
+ """
+ glue_function = syntax_tree.Function(field.source, [],
+ 'userglue_getter_%s' % field.name,
+ None, [])
+ glue_function.type_defn = field.type_defn
+ glue_function.parent = scope
+ this_param = syntax_tree.Function.Param(type_defn.name, '_this')
+ this_param.type_defn = type_defn
+ this_param.mutable = True
+ glue_function.params = [this_param]
+ return glue_function
+
+ def AddPluginDataParam(self, scope, func, param_exprs):
+ """Adds the plugin data parameter to a function and parameter list.
+
+ Args:
+ scope: the scope for the parameter type.
+ func: the function to which we add a parameter.
+ param_exprs: the list of parameters exressions to which the plugin data
+ is added
+ """
+ scope = scope # silence gpylint
+ plugin_data_param = syntax_tree.Function.Param(
+ self._plugin_data_type.name, 'plugin_data')
+ plugin_data_param.type_defn = self._plugin_data_type
+ func.params.insert(0, plugin_data_param)
+ param_exprs.insert(0, 'npp->pdata')
+
+ def EmitMemberCall(self, context, func):
+ """Emits the glue for a non-static member function call.
+
+ Args:
+ context: the code generation context.
+ func: the method to call.
+ """
+ scope = context.scope
+ type_defn = context.type_defn
+ binding_model = context.binding_model
+ section = context.invoke_section
+ id_enum = 'METHOD_%s' % naming.Normalize(func.name, naming.Upper)
+ name = '"%s"' % naming.Normalize(func.name, naming.Java)
+ context.method_ids.append((id_enum, name))
+ strings, param_exprs, needed_glue = self.GetParamInputStrings(scope,
+ func.params)
+ section.needed_glue.update(needed_glue)
+ if 'userglue' in func.attributes:
+ glue_func = self.GetUserGlueMethodFunc(scope, type_defn, func)
+ param_exprs.insert(0, 'object')
+ if 'plugin_data' in func.attributes:
+ self.AddPluginDataParam(context.scope, glue_func, param_exprs)
+ self.GenerateCppFunction(context.header_section, scope, glue_func)
+ expression = globals_binding.CppCallStaticMethod(scope, scope, glue_func,
+ param_exprs)
+ else:
+ expression = binding_model.CppCallMethod(scope, type_defn, 'object',
+ True, func, param_exprs)
+ pre, post, needed_glue = self.GetReturnStrings(scope, func.type_defn,
+ expression, 'result')
+ section.needed_glue.update(needed_glue)
+ strings += [pre, _failure_test_string, post, 'return true;']
+ self.EmitInvokeCode(section, 'method_ids', id_enum, len(func.params),
+ '\n'.join(strings))
+
+ def EmitStaticCall(self, context, func):
+ """Emits the glue for a static function call.
+
+ Args:
+ context: the code generation context.
+ func: the function to call.
+ """
+ scope = context.scope
+ type_defn = context.type_defn
+ binding_model = context.binding_model
+ section = context.static_invoke_section
+ id_enum = 'STATIC_METHOD_%s' % naming.Normalize(func.name, naming.Upper)
+ name = '"%s"' % naming.Normalize(func.name, naming.Java)
+ context.static_method_ids.append((id_enum, name))
+
+ strings, param_exprs, needed_glue = self.GetParamInputStrings(scope,
+ func.params)
+ section.needed_glue.update(needed_glue)
+ if 'userglue' in func.attributes:
+ glue_func = self.GetUserGlueStaticMethodFunc(scope, func)
+ if 'plugin_data' in func.attributes:
+ self.AddPluginDataParam(context.scope, glue_func, param_exprs)
+ self.GenerateCppFunction(context.header_section, scope, glue_func)
+ expression = globals_binding.CppCallStaticMethod(scope, scope, glue_func,
+ param_exprs)
+ else:
+ expression = binding_model.CppCallStaticMethod(scope, type_defn, func,
+ param_exprs)
+ pre, post, needed_glue = self.GetReturnStrings(scope, func.type_defn,
+ expression, 'result')
+ section.needed_glue.update(needed_glue)
+ strings += [pre, _failure_test_string, post, 'return true;']
+ self.EmitInvokeCode(section, 'static_method_ids', id_enum,
+ len(func.params), '\n'.join(strings))
+
+ def EmitConstructorCall(self, context, func):
+ """Emits the glue for a constructor call.
+
+ Args:
+ context: the code generation context.
+ func: the constructor to call.
+ """
+ scope = context.scope
+ type_defn = context.type_defn
+ binding_model = context.binding_model
+ section = context.static_invoke_default_section
+ strings, param_exprs, needed_glue = self.GetParamInputStrings(scope,
+ func.params)
+ section.needed_glue.update(needed_glue)
+ if 'userglue' in func.attributes:
+ glue_func = self.GetUserGlueConstructorFunc(scope, type_defn, func)
+ if 'plugin_data' in func.attributes:
+ self.AddPluginDataParam(context.scope, glue_func, param_exprs)
+ self.GenerateCppFunction(context.header_section, scope, glue_func)
+ expression = globals_binding.CppCallStaticMethod(scope, scope, glue_func,
+ param_exprs)
+ else:
+ expression = binding_model.CppCallConstructor(scope, type_defn, func,
+ param_exprs)
+ pre, post, needed_glue = self.GetReturnStrings(scope, type_defn, expression,
+ 'result')
+ section.needed_glue.update(needed_glue)
+ strings += [pre, _failure_test_string, post, 'return true;']
+ self.EmitInvokeDefaultCode(section, len(func.params), '\n'.join(strings))
+
+ def EmitMemberProp(self, context, field):
+ """Emits the glue for a non-static member field access.
+
+ Args:
+ context: the code generation context.
+ field: the field to access.
+ """
+ scope = context.scope
+ type_defn = context.type_defn
+ binding_model = context.binding_model
+ id_enum = 'PROPERTY_%s' % naming.Normalize(field.name, naming.Upper)
+ prop_name = '"%s"' % naming.Normalize(field.name, naming.Java)
+ context.prop_ids.append((id_enum, prop_name))
+ if 'getter' in field.attributes:
+ if 'userglue_getter' in field.attributes:
+ glue_func = self.GetUserGlueGetterFunc(scope, type_defn, field)
+ param_exprs = ['object']
+ if 'plugin_data' in field.attributes:
+ self.AddPluginDataParam(scope, glue_func, param_exprs)
+ self.GenerateCppFunction(context.header_section, scope, glue_func)
+ expression = globals_binding.CppCallStaticMethod(scope, scope,
+ glue_func, param_exprs)
+ else:
+ expression = binding_model.CppGetField(scope, type_defn, 'object',
+ field)
+ pre, post, needed_glue = self.GetReturnStrings(scope, field.type_defn,
+ expression, 'variant')
+ else:
+ # Return a void value for write-only members.
+ pre, post, needed_glue = self.GetVoidReturnStrings(field.type_defn,
+ 'variant')
+
+ section = context.get_prop_section
+ section.needed_glue.update(needed_glue)
+ get_string = '\n'.join([pre, _failure_test_string, post, 'return true;'])
+ self.EmitPropertyCode(section, 'property_ids', id_enum, get_string)
+
+ if 'setter' in field.attributes:
+ # TODO: Add a specific error for trying to set a read-only prop.
+ field_binding = field.type_defn.binding_model
+ start_exception, end_exception = GenExceptionContext(
+ _exception_macro_name, "field",
+ naming.Normalize(field.name, naming.Java))
+ code, param_expr = field_binding.NpapiFromNPVariant(
+ scope, field.type_defn, '(*variant)', 'param_%s' % field.name,
+ 'success', _exception_macro_name, 'npp')
+ section = context.set_prop_section
+ section.needed_glue.add(field.type_defn)
+ if 'userglue_setter' in field.attributes:
+ glue_func = self.GetUserGlueSetterFunc(scope, type_defn, field)
+ param_exprs = ['object', param_expr]
+ if 'plugin_data' in field.attributes:
+ self.AddPluginDataParam(scope, glue_func, param_exprs)
+ self.GenerateCppFunction(context.header_section, scope, glue_func)
+ expression = globals_binding.CppCallStaticMethod(scope, scope,
+ glue_func, param_exprs)
+ else:
+ expression = binding_model.CppSetField(scope, type_defn, 'object',
+ field, param_expr)
+ strings = [start_exception, code, _failure_test_string,
+ '%s;' % expression, 'return true;', end_exception]
+ self.EmitPropertyCode(section, 'property_ids', id_enum,
+ '\n'.join(strings))
+
+ def EmitStaticMemberProp(self, context, field):
+ """Emits the glue for a static field access.
+
+ Args:
+ context: the code generation context.
+ field: the field to access.
+ """
+ scope = context.scope
+ type_defn = context.type_defn
+ binding_model = context.binding_model
+ id_enum = 'STATIC_PROPERTY_%s' % naming.Normalize(field.name, naming.Upper)
+ prop_name = '"%s"' % naming.Normalize(field.name, naming.Java)
+ context.static_prop_ids.append((id_enum, prop_name))
+ if 'getter' in field.attributes:
+ expression = binding_model.CppGetStatic(scope, type_defn, field)
+ pre, post, needed_glue = self.GetReturnStrings(scope, field.type_defn,
+ expression, 'variant')
+ else:
+ # Return a void value for write-only members.
+ pre, post, needed_glue = self.GetVoidReturnStrings(field.type_defn,
+ 'variant')
+ section = context.static_get_prop_section
+ section.needed_glue.update(needed_glue)
+ get_string = '\n'.join([pre, _failure_test_string, post, 'return true;'])
+ self.EmitPropertyCode(section, 'static_property_ids', id_enum,
+ get_string)
+
+ if 'setter' in field.attributes:
+ # TODO: Add a specific error for trying to set a read-only prop.
+ field_binding = field.type_defn.binding_model
+ start_exception, end_exception = GenExceptionContext(
+ _exception_macro_name, "field",
+ naming.Normalize(field.name, naming.Java))
+ code, param_expr = field_binding.NpapiFromNPVariant(
+ scope, field.type_defn, '(*variant)', 'param_%s' % field.name,
+ 'success', _exception_macro_name, 'npp')
+ section = context.static_set_prop_section
+ section.needed_glue.add(field.type_defn)
+ expression = binding_model.CppSetStatic(scope, type_defn, field,
+ param_expr)
+ strings = [start_exception, code, _failure_test_string,
+ '%s;' % expression, 'return true;', end_exception]
+ self.EmitPropertyCode(section, 'static_property_ids', id_enum,
+ '\n'.join(strings))
+
+ def EmitEnumValue(self, context, enum, enum_value):
+ """Emits the glue for an enum value access.
+
+ Args:
+ context: the code generation context.
+ enum: the enum definition.
+ enum_value: the enum value to access.
+ """
+ enum = enum # silence gpylint.
+ scope = context.scope
+ type_defn = context.type_defn
+ section = context.static_get_prop_section
+ name = naming.Normalize(enum_value.name, naming.Upper)
+ id_enum = 'ENUM_%s' % name
+ prop_name = '"%s"' % name
+ context.static_prop_ids.append((id_enum, prop_name))
+ strings = ['INT32_TO_NPVARIANT(%s::%s, *variant);' %
+ (cpp_utils.GetScopedName(scope, type_defn), enum_value.name),
+ 'return true;']
+ self.EmitPropertyCode(section, 'static_property_ids', id_enum,
+ '\n'.join(strings))
+
+ def EmitInvokeCode(self, section, table, id_enum, arg_count, code):
+ """Emits glue code in an 'Invoke' dispatch function.
+
+ Args:
+ section: the code section of the dispatch function.
+ table: the table in which the method identifier is defined.
+ id_enum: the method identifier enum.
+ arg_count: the number of arguments for the function.
+ code: the glue code.
+ """
+ section.EmitCode(_method_invoke_template.substitute(table=table,
+ method_id=id_enum,
+ argCount=arg_count,
+ code=code))
+
+ def EmitInvokeDefaultCode(self, section, arg_count, code):
+ """Emits glue code in an 'InvokeDefault' dispatch function.
+
+ Args:
+ section: the code section of the dispatch function.
+ arg_count: the number of arguments for the function.
+ code: the glue code.
+ """
+ section.EmitCode(_method_default_invoke_template.substitute(
+ argCount=arg_count, code=code))
+
+ def EmitPropertyCode(self, section, table, id_enum, code):
+ """Emits glue code in a 'GetProperty' or 'SetProperty' dispatch function.
+
+ Args:
+ section: the code section of the dispatch function.
+ table: the table in which the property identifier is defined.
+ id_enum: the property identifier enum.
+ code: the glue code.
+ """
+ section.EmitCode(_property_template.substitute(table=table,
+ property_id=id_enum,
+ code=code))
+
+ def Variable(self, context, obj):
+ """Emits the glue code for a Variable definition.
+
+ Args:
+ context: the code generation context.
+ obj: the Variable definition.
+ """
+ if 'private' in obj.attributes or 'protected' in obj.attributes:
+ return
+ if 'static' in obj.attributes or context.is_namespace:
+ self.EmitStaticMemberProp(context, obj)
+ else:
+ self.EmitMemberProp(context, obj)
+
+ def Enum(self, context, obj):
+ """Emits the glue code for an Enum definition.
+
+ Args:
+ context: the code generation context.
+ obj: the Enum definition.
+ """
+ if 'private' in obj.attributes or 'protected' in obj.attributes:
+ return
+ for value in obj.values:
+ self.EmitEnumValue(context, obj, value)
+
+ def Function(self, context, obj):
+ """Emits the glue code for a Function definition.
+
+ Args:
+ context: the code generation context.
+ obj: the Function definition.
+
+ Raises:
+ MethodWithoutReturnType: a non-constructor function doesn't have a return
+ type.
+ """
+ if 'private' in obj.attributes or 'protected' in obj.attributes:
+ return
+ if 'static' in obj.attributes or context.is_namespace:
+ self.EmitStaticCall(context, obj)
+ else:
+ if not obj.type_defn:
+ if obj.name == context.type_defn.name:
+ # constructor
+ self.EmitConstructorCall(context, obj)
+ elif obj.name == '~' + context.type_defn.name:
+ # destructor (ignore)
+ return
+ else:
+ # method without return type: error
+ raise MethodWithoutReturnType(obj)
+ else:
+ self.EmitMemberCall(context, obj)
+
+ def Callback(self, context, obj):
+ """Emits the glue code for a Callback definition.
+
+ Args:
+ context: the code generation context.
+ obj: the Callback definition.
+ """
+ if 'private' in obj.attributes or 'protected' in obj.attributes:
+ return
+
+ binding_model = obj.binding_model
+ namespace_name = npapi_utils.GetGlueNamespace(obj)
+
+ scope = syntax_tree.Namespace(None, [], namespace_name, [])
+ scope.parent = context.scope
+
+ context.header_section.PushNamespace(namespace_name)
+ header_section = context.header_section.CreateSection(namespace_name)
+ header_section.needed_defn = context.header_section.needed_defn
+ context.header_section.PopNamespace()
+
+ context.cpp_section.PushNamespace(namespace_name)
+ cpp_section = context.cpp_section.CreateSection(namespace_name)
+ cpp_section.needed_glue = context.cpp_section.needed_glue
+ context.cpp_section.PopNamespace()
+
+ param_to_variant_pre = []
+ param_to_variant_post = []
+ param_strings = []
+ for i in xrange(len(obj.params)):
+ p = obj.params[i]
+ param_string, unused_val = cpp_utils.GetFunctionParamPrototype(scope, p)
+ header_section.needed_defn.add(p.type_defn)
+ cpp_section.needed_glue.add(p.type_defn)
+ param_strings += [param_string]
+ bm = p.type_defn.binding_model
+ pre, post = bm.NpapiExprToNPVariant(scope, p.type_defn, 'var_' + p.name,
+ p.name, '(args + %d)' % i, 'success',
+ 'npp')
+ param_to_variant_pre.append(pre)
+ param_to_variant_post.append(post)
+
+ if param_strings:
+ param_strings = [''] + param_strings
+
+ return_type = obj.type_defn
+ header_section.needed_defn.add(return_type)
+ cpp_section.needed_glue.add(return_type)
+ bm = return_type.binding_model
+ return_type_string, unused_val = bm.CppReturnValueString(scope,
+ return_type)
+ run_callback = ('%s RunCallback(NPP npp, NPObject *npobject, bool async%s)'
+ % (return_type_string, ', '.join(param_strings)))
+
+ return_eval, return_value = bm.NpapiFromNPVariant(scope, return_type,
+ 'result', 'retval',
+ 'success',
+ _exception_macro_name,
+ 'npp')
+ start_exception, end_exception = GenExceptionContext(
+ _exception_macro_name, "callback return value", "<no name>")
+ subst_dict = {'RunCallback': run_callback,
+ 'ArgCount': str(len(obj.params)),
+ 'ParamsToVariantsPre': '\n'.join(param_to_variant_pre),
+ 'ParamsToVariantsPost': '\n'.join(param_to_variant_post),
+ 'ReturnEval': return_eval,
+ 'ReturnValue': return_value,
+ 'StartException': start_exception,
+ 'EndException': end_exception}
+ if obj.params:
+ glue_template = _callback_glue_cpp_template
+ else:
+ glue_template = _callback_no_param_glue_cpp_template
+ cpp_section.EmitCode(glue_template.substitute(subst_dict))
+ cpp_section.EmitCode(binding_model.NpapiBindingGlueCpp(scope, obj))
+ header_section.EmitCode(binding_model.NpapiBindingGlueHeader(scope, obj))
+
+ def GetDictForEnumerations(self, context, has_base):
+ """Creates a dictionary used to fill in the gaps in the property
+ enumeration functions. Note that this dictionary will in some cases cause
+ the insertion of the string ${BaseClassNamespace}, so it must be used
+ *before* the dictionary that fills in that macro. This only happens when
+ the context is a derived class.
+
+ Args:
+ context: the code generation context
+ has_base: whether this is a class that has a base class
+
+ Returns:
+ a dictionary containing definitions for the code generation templates
+ """
+ dict = {}
+ if not context.is_namespace:
+ if context.prop_ids:
+ dict.update({
+ 'PropertyCount': 'NUM_PROPERTY_IDS',
+ 'EnumeratePropertyEntries': _enumerate_property_entries,
+ })
+ else:
+ dict.update({
+ 'PropertyCount': '0',
+ 'EnumeratePropertyEntries': '',
+ })
+ if context.method_ids:
+ dict.update({
+ 'MethodCount': 'NUM_METHOD_IDS',
+ 'EnumerateMethodEntries': _enumerate_method_entries,
+ })
+ else:
+ dict.update({
+ 'MethodCount': '0',
+ 'EnumerateMethodEntries': '',
+ })
+ if has_base:
+ dict.update({
+ 'BaseGetPropertyCount': '${BaseClassNamespace}::GetPropertyCount()',
+ 'EnumeratePropertyEntriesHelperBaseCall':
+ """${BaseClassNamespace}::EnumeratePropertyEntriesHelper(
+ output);\n""",
+ })
+ else:
+ dict.update({
+ 'BaseGetPropertyCount': '0',
+ 'EnumeratePropertyEntriesHelperBaseCall': '',
+ })
+
+ if context.static_prop_ids:
+ dict.update({
+ 'AddStaticPropertyCount': '*count += NUM_STATIC_PROPERTY_IDS;',
+ 'EnumerateStaticPropertyEntries': _enumerate_static_property_entries,
+ 'StaticPropertyCount': 'NUM_STATIC_PROPERTY_IDS',
+ })
+ else:
+ dict.update({
+ 'AddStaticPropertyCount': '',
+ 'EnumerateStaticPropertyEntries': '',
+ 'StaticPropertyCount': '0',
+ })
+ if context.static_method_ids:
+ dict.update({
+ 'AddStaticMethodCount': '*count += NUM_STATIC_METHOD_IDS;',
+ 'EnumerateStaticMethodEntries': _enumerate_static_method_entries,
+ 'StaticMethodCount': 'NUM_STATIC_METHOD_IDS',
+ })
+ else:
+ dict.update({
+ 'AddStaticMethodCount': '',
+ 'EnumerateStaticMethodEntries': '',
+ 'StaticMethodCount': '0',
+ })
+ if context.namespace_list:
+ dict.update({
+ 'AddNamespaceCount': '*count += NUM_NAMESPACE_IDS;',
+ 'EnumerateNamespaceEntries': _enumerate_namespace_entries,
+ 'NamespaceCount': 'NUM_NAMESPACE_IDS',
+ })
+ else :
+ dict.update({
+ 'AddNamespaceCount': '',
+ 'EnumerateNamespaceEntries': '',
+ 'NamespaceCount': '0',
+ })
+ return dict
+
+ def Class(self, parent_context, obj):
+ """Emits the glue code for a Class definition.
+
+ Args:
+ parent_context: the code generation context.
+ obj: the Class definition.
+ """
+ if 'private' in obj.attributes or 'protected' in obj.attributes:
+ return
+
+ binding_model = obj.binding_model
+
+ namespace_name = npapi_utils.GetGlueNamespace(obj)
+ parent_context.namespace_list.append(obj)
+
+ scope = syntax_tree.Namespace(None, [], namespace_name, [])
+ scope.parent = parent_context.scope
+
+ parent_context.header_section.PushNamespace(namespace_name)
+ header_section = parent_context.header_section.CreateSection(namespace_name)
+ header_section.needed_defn = parent_context.header_section.needed_defn
+ parent_context.header_section.PopNamespace()
+
+ parent_context.cpp_section.PushNamespace(namespace_name)
+ cpp_section = parent_context.cpp_section.CreateSection(namespace_name)
+ cpp_section.needed_glue = parent_context.cpp_section.needed_glue
+ parent_context.cpp_section.PopNamespace()
+
+ context = self.CodeGenContext(obj, scope, header_section, cpp_section, None)
+ header_section.needed_defn.add(obj)
+ cpp_section.needed_glue.add(obj)
+
+ self.GenerateList(context, obj.defn_list)
+
+ class_name_list = naming.SplitWords(obj.name)
+ class_capitalized = naming.Capitalized(class_name_list)
+ class_param_type, unused_need_defn = binding_model.CppParameterString(scope,
+ obj)
+ class_mutable_param_type, unused_need_defn = (
+ binding_model.CppMutableParameterString(scope, obj))
+ binding_glue_header = binding_model.NpapiBindingGlueHeader(scope, obj)
+ binding_glue_cpp = binding_model.NpapiBindingGlueCpp(scope, obj)
+ function_header, object_access = binding_model.NpapiDispatchFunctionHeader(
+ scope, obj, 'object', 'npp', 'success')
+ object_non_mutable = binding_model.CppMutableToNonMutable(scope, obj,
+ object_access)
+ static_dict = {'Class': class_capitalized,
+ 'ClassParamType': class_param_type,
+ 'ClassMutableParamType': class_mutable_param_type,
+ 'Object': object_access,
+ 'ObjectNonMutable': object_non_mutable,
+ 'BindingGlueCpp': binding_glue_cpp,
+ 'BindingGlueHeader': binding_glue_header,
+ 'DispatchFunctionHeader': function_header}
+
+ enum_dict = self.GetDictForEnumerations(context, obj.base_type)
+ if obj.base_type:
+ parent_context.cpp_section.needed_glue.add(obj.base_type)
+ static_dict['BaseClassNamespace'] = npapi_utils.GetGlueFullNamespace(
+ obj.base_type.GetFinalType())
+ cpp_template = _class_glue_cpp_base_template.safe_substitute(enum_dict)
+ else:
+ cpp_template = _class_glue_cpp_no_base_template.safe_substitute(enum_dict)
+
+ cpp_template = string.Template(cpp_template).safe_substitute(static_dict)
+
+ header_section.EmitCode(
+ _class_glue_header_template.safe_substitute(static_dict))
+
+ namespace_id_dict = GenNamespaceCode(context)
+ parent_context.cpp_section.needed_glue.update(context.namespace_list)
+ substitution_dict = {}
+ substitution_dict.update(npapi_utils.MakeIdTableDict(
+ context.method_ids, 'method'))
+ substitution_dict.update(npapi_utils.MakeIdTableDict(
+ context.static_method_ids, 'static_method'))
+ substitution_dict.update(npapi_utils.MakeIdTableDict(
+ context.prop_ids, 'property'))
+ substitution_dict.update(npapi_utils.MakeIdTableDict(
+ context.static_prop_ids, 'static_property'))
+ substitution_dict.update(namespace_id_dict)
+
+ cpp_section.EmitTemplate(string.Template(cpp_template).safe_substitute(
+ substitution_dict))
+
+ def Verbatim(self, context, obj):
+ """Emits the glue code for a Verbatim definition.
+
+ Args:
+ context: the code generation context.
+ obj: the Verbatim definition.
+ """
+ if 'verbatim' in obj.attributes:
+ if obj.attributes['verbatim'] == 'cpp_glue':
+ context.cpp_section.EmitCode(obj.text)
+ elif obj.attributes['verbatim'] == 'header_glue':
+ context.header_section.EmitCode(obj.text)
+
+ def Namespace(self, parent_context, obj):
+ """Emits the glue code for a Namespace definition.
+
+ Since a namespace can be defined through several Namespace definitions,
+ this function doesn't generate all the glue for the namespace until all the
+ namespaces definitions have been processed (second pass).
+
+ Args:
+ parent_context: the code generation context.
+ obj: the Namespace definition.
+ """
+ namespace_name = npapi_utils.GetGlueNamespace(obj)
+ # namespaces that span across multiple files are different objects
+ # we keep definitions inside the namespace separate, but all the 'static'
+ # glue needs to be gathered. So we create a code generation context that
+ # will be re-used when a different part of the namespace will be
+ # encountered
+ # all the different namespaces share the same scope member, so use that as
+ # a key into a dict that maps the context
+ if obj.scope in self._namespace_map:
+ old_context = self._namespace_map[obj.scope]
+
+ parent_context.header_section.PushNamespace(namespace_name)
+ header_section = parent_context.header_section.CreateSection(
+ namespace_name)
+ header_section.needed_defn = parent_context.header_section.needed_defn
+ parent_context.header_section.PopNamespace()
+
+ parent_context.cpp_section.PushNamespace(namespace_name)
+ cpp_section = parent_context.cpp_section.CreateSection(namespace_name)
+ cpp_section.needed_glue = parent_context.cpp_section.needed_glue
+ parent_context.cpp_section.PopNamespace()
+
+ context = self.CodeGenContext(old_context.type_defn, old_context.scope,
+ header_section, cpp_section, old_context)
+ else:
+ parent_context.namespace_list.append(obj)
+
+ scope = syntax_tree.Namespace(None, [], namespace_name, [])
+ scope.parent = parent_context.scope
+
+ parent_context.header_section.PushNamespace(namespace_name)
+ header_section = parent_context.header_section.CreateSection(
+ namespace_name)
+ header_section.needed_defn = parent_context.header_section.needed_defn
+ parent_context.header_section.PopNamespace()
+
+ parent_context.cpp_section.PushNamespace(namespace_name)
+ cpp_section = parent_context.cpp_section.CreateSection(namespace_name)
+ cpp_section.needed_glue = parent_context.cpp_section.needed_glue
+ parent_context.cpp_section.PopNamespace()
+
+ context = self.CodeGenContext(obj, scope, header_section,
+ cpp_section, None)
+ self._namespace_map[obj.scope] = context
+
+ def _Finalize():
+ # This part can only be finalized after all files have been processed,
+ # because later files can still add definitions to the namespace.
+ # So do this work in a function that will get called at the end.
+ namespace_id_dict = GenNamespaceCode(context)
+ parent_context.cpp_section.needed_glue.update(context.namespace_list)
+
+ substitution_dict = {}
+ substitution_dict.update(npapi_utils.MakeIdTableDict(
+ context.static_method_ids, 'static_method'))
+ substitution_dict.update(npapi_utils.MakeIdTableDict(
+ context.static_prop_ids, 'static_property'))
+ substitution_dict.update(namespace_id_dict)
+
+ header_section.EmitCode(_namespace_glue_header)
+
+ enum_dict = self.GetDictForEnumerations(context, False)
+ temp_string = _namespace_glue_cpp_template.safe_substitute(enum_dict)
+ temp_template = string.Template(temp_string)
+
+ cpp_section.EmitTemplate(temp_template.safe_substitute(
+ substitution_dict))
+
+ self._finalize_functions.append(_Finalize)
+
+ context.cpp_section.needed_glue.add(obj)
+ self.GenerateList(context, obj.defn_list)
+
+ def Typedef(self, context, obj):
+ """Emits the glue code for a Typedef definition.
+
+ Args:
+ context: the code generation context.
+ obj: the Typedef definition.
+ """
+ # TODO: implement this.
+ pass
+
+ def Typename(self, context, obj):
+ """Emits the glue code for a Typename definition.
+
+ Typename being unknown types, no glue is generated for them.
+
+ Args:
+ context: the code generation context.
+ obj: the Typename definition.
+ """
+ pass
+
+ def GenerateList(self, context, defn_list):
+ """Emits the glue code for a list of definitions.
+
+ Args:
+ context: the code generation context.
+ defn_list: the definition list.
+ """
+ for obj in defn_list:
+ if 'nojs' in obj.attributes:
+ continue
+ if 'include' in obj.attributes:
+ context.header_section.needed_defn.add(obj)
+ func = getattr(self, obj.defn_type)
+ func(context, obj)
+
+ def CreateGlueWriters(self, idl_file):
+ """Creates CppFileWriter instances for glue header and implementation.
+
+ Args:
+ idl_file: an idl_parser.File for the source file.
+
+ Returns:
+ a pair of CppFileWriter, the first being the glue header writer, the
+ second one being the glue implementation writer.
+ """
+ cpp_writer = cpp_utils.CppFileWriter(
+ '%s/%s' % (self._output_dir, GetGlueCpp(idl_file)), False)
+ for include, system in _cpp_includes:
+ cpp_writer.AddInclude(include, system)
+ cpp_writer.AddInclude(GetGlueHeader(idl_file), False)
+
+ header_writer = cpp_utils.CppFileWriter(
+ '%s/%s' % (self._output_dir, GetGlueHeader(idl_file)), True)
+ for include, system in _header_includes:
+ header_writer.AddInclude(include, system)
+ return header_writer, cpp_writer
+
+ def CreateGlueSection(self, writer):
+ """Utility function to create a 'glue' section in a writer.
+
+ This function will create a new section inside a 'glue' namespace.
+
+ Args:
+ writer: a CppFileWriter in which to create the section.
+
+ Returns:
+ the created section.
+ """
+ writer.PushNamespace('glue')
+ section = writer.CreateSection('glue')
+ writer.PopNamespace()
+ return section
+
+ def BeginFile(self, idl_file, parent_context, defn_list):
+ """Runs the pass 1 generation for an IDL file.
+
+ Args:
+ idl_file: the source IDL file.
+ parent_context: the code generation context.
+ defn_list: the list of top-level definitions in the IDL file.
+
+ Returns:
+ a 3-uple. The first element is the code generation context for that file.
+ The second element is the glue header writer. The third element is the
+ glue implementation writer.
+ """
+ header_writer, cpp_writer = self.CreateGlueWriters(idl_file)
+ header_writer.needed_defn = set()
+ cpp_writer.needed_glue = set()
+ header_section = self.CreateGlueSection(header_writer)
+ cpp_section = self.CreateGlueSection(cpp_writer)
+ header_section.needed_defn = header_writer.needed_defn
+ cpp_section.needed_glue = cpp_writer.needed_glue
+
+ context = self.CodeGenContext(parent_context.type_defn,
+ parent_context.scope, header_section,
+ cpp_section, parent_context)
+
+ self.GenerateList(context, defn_list)
+ return context, header_writer, cpp_writer
+
+ def FinishFile(self, idl_file, context, header_writer, cpp_writer):
+ """Runs the pass 2 generation for an IDL file.
+
+ Args:
+ idl_file: the source IDL file.
+ context: the code generation context for this file (returned by
+ BeginFile)
+ header_writer: the glue header writer (returned by BeginFile).
+ cpp_writer: the glue implementation writer (returned by BeginFile).
+
+ Returns:
+ a list of CppFileWriter instances that contain the generated files.
+ """
+ context = context # silence gpylint
+ source_files = (type_defn.GetFinalType().source.file for type_defn in
+ cpp_writer.needed_glue)
+ cpp_needed_glue_includes = set(GetGlueHeader(source_file) for source_file
+ in source_files)
+ cpp_needed_glue_includes.add(GetGlueHeader(idl_file))
+
+ for include_file in cpp_needed_glue_includes:
+ if include_file:
+ cpp_writer.AddInclude(include_file)
+
+ for include_file in set(type_defn.GetDefinitionInclude() for type_defn
+ in header_writer.needed_defn):
+ if include_file:
+ header_writer.AddInclude(include_file)
+
+ return [header_writer, cpp_writer]
+
+ def BeginGlobals(self, idl_file, namespace):
+ """Runs the pass 1 generation for the global namespace.
+
+ A separate files are written containing the global namespace glue.
+
+ Args:
+ idl_file: an idl_file.File for the global namespace file.
+ namespace: the global namespace.
+
+ Returns:
+ a 3-uple. The first element is the code generation context for that file.
+ The second element is the glue header writer. The third element is the
+ glue implementation writer.
+ """
+ scope = syntax_tree.Namespace(None, [], 'glue', [])
+ scope.parent = namespace
+
+ header_writer, cpp_writer = self.CreateGlueWriters(idl_file)
+ header_writer.needed_defn = set()
+ cpp_writer.needed_glue = set()
+ header_section = self.CreateGlueSection(header_writer)
+ cpp_section = self.CreateGlueSection(cpp_writer)
+ header_section.needed_defn = header_writer.needed_defn
+ cpp_section.needed_glue = cpp_writer.needed_glue
+
+ context = self.CodeGenContext(namespace, scope, header_section,
+ cpp_section, None)
+ return context, header_writer, cpp_writer
+
+ def FinishGlobals(self, context, header_writer, cpp_writer):
+ """Runs the pass 2 generation for the global namespace.
+
+ Args:
+ context: the code generation context for the global namespace (returned
+ by BeginGlobals).
+ header_writer: the glue header writer (returned by BeginGlobals).
+ cpp_writer: the glue implementation writer (returned by BeginGlobals).
+
+ Returns:
+ a list of CppFileWriter instances that contain the generated files.
+ """
+ for f in self._finalize_functions:
+ f()
+ namespace_id_dict = GenNamespaceCode(context)
+
+ substitution_dict = {}
+ substitution_dict.update(npapi_utils.MakeIdTableDict(
+ context.static_method_ids, 'static_method'))
+ substitution_dict.update(npapi_utils.MakeIdTableDict(
+ context.static_prop_ids, 'static_property'))
+ substitution_dict.update(namespace_id_dict)
+
+ context.header_section.EmitCode(_namespace_glue_header)
+
+ enum_dict = self.GetDictForEnumerations(context, False)
+ temp_string = _namespace_glue_cpp_template.safe_substitute(enum_dict)
+ temp_template = string.Template(temp_string)
+
+ context.cpp_section.EmitTemplate(
+ temp_template.safe_substitute(substitution_dict))
+
+ context.header_section.EmitCode(_globals_glue_header_tail)
+ context.cpp_section.EmitCode(_globals_glue_cpp_tail)
+
+ includes = set(GetGlueHeader(ns_obj.source.file) for ns_obj in
+ context.namespace_list)
+
+ for include_file in includes:
+ if include_file is not None:
+ cpp_writer.AddInclude(include_file)
+
+ return [header_writer, cpp_writer]
+
+
+def ProcessFiles(output_dir, pairs, namespace):
+ """Generates the NPAPI glue 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 glue header or
+ implementation file.
+ """
+ globals_file = idl_parser.File('<internal>')
+ globals_file.header = None
+ globals_file.basename = 'globals'
+ generator = NpapiGenerator(output_dir)
+
+ # pass 1
+ global_context, global_header_writer, global_cpp_writer = (
+ generator.BeginGlobals(globals_file, namespace))
+ file_map = {}
+ for (idl_file, defn) in pairs:
+ context, header_writer, cpp_writer = generator.BeginFile(
+ idl_file, global_context, defn)
+ file_map[idl_file] = (context, header_writer, cpp_writer)
+
+ # pass 2
+ writer_list = generator.FinishGlobals(global_context, global_header_writer,
+ global_cpp_writer)
+ for (idl_file, defn) in pairs:
+ context, header_writer, cpp_writer = file_map[idl_file]
+ writer_list += generator.FinishFile(idl_file, context, header_writer,
+ cpp_writer)
+ return writer_list
+
+
+def main():
+ pass
+
+if __name__ == '__main__':
+ main()
Property changes on: tools/nixysa/nixysa/npapi_generator.py
___________________________________________________________________
Added: svn:eol-style
+ LF
« no previous file with comments | « tools/nixysa/nixysa/naming_test.py ('k') | tools/nixysa/nixysa/npapi_utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698