зеркало из https://github.com/mozilla/pjs.git
1195 строки
39 KiB
C
1195 строки
39 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (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.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
/*
|
|
* Generate XPCOM headers from XPIDL.
|
|
*/
|
|
|
|
#include "xpidl.h"
|
|
#include <ctype.h>
|
|
|
|
#define AS_DECL 0
|
|
#define AS_CALL 1
|
|
#define AS_IMPL 2
|
|
|
|
static gboolean write_method_signature(IDL_tree method_tree, FILE *outfile,
|
|
int mode, const char *className);
|
|
static gboolean write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
|
|
gboolean getter,
|
|
int mode, const char *className);
|
|
|
|
static void
|
|
write_indent(FILE *outfile) {
|
|
fputs(" ", outfile);
|
|
}
|
|
|
|
static gboolean
|
|
header_prolog(TreeState *state)
|
|
{
|
|
const char *define = xpidl_basename(state->basename);
|
|
fprintf(state->file, "/*\n * DO NOT EDIT. THIS FILE IS GENERATED FROM"
|
|
" %s.idl\n */\n", state->basename);
|
|
fprintf(state->file,
|
|
"\n#ifndef __gen_%s_h__\n"
|
|
"#define __gen_%s_h__\n",
|
|
define, define);
|
|
if (state->base_includes != NULL) {
|
|
guint len = g_slist_length(state->base_includes);
|
|
guint i;
|
|
|
|
fputc('\n', state->file);
|
|
for (i = 0; i < len; i++) {
|
|
char *ident, *dot;
|
|
|
|
ident = (char *)g_slist_nth_data(state->base_includes, i);
|
|
|
|
/* suppress any trailing .extension */
|
|
|
|
/* XXX use g_basename instead ? ? */
|
|
|
|
dot = strrchr(ident, '.');
|
|
if (dot != NULL)
|
|
*dot = '\0';
|
|
|
|
|
|
/* begin include guard */
|
|
fprintf(state->file,
|
|
"\n#ifndef __gen_%s_h__\n",
|
|
ident);
|
|
|
|
fprintf(state->file, "#include \"%s.h\"\n",
|
|
(char *)g_slist_nth_data(state->base_includes, i));
|
|
|
|
fprintf(state->file, "#endif\n");
|
|
|
|
}
|
|
if (i > 0)
|
|
fputc('\n', state->file);
|
|
}
|
|
/*
|
|
* Support IDL files that don't include a root IDL file that defines
|
|
* NS_NO_VTABLE.
|
|
*/
|
|
fprintf(state->file,
|
|
"/* For IDL files that don't want to include root IDL files. */\n"
|
|
"#ifndef NS_NO_VTABLE\n"
|
|
"#define NS_NO_VTABLE\n"
|
|
"#endif\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
header_epilog(TreeState *state)
|
|
{
|
|
const char *define = xpidl_basename(state->basename);
|
|
fprintf(state->file, "\n#endif /* __gen_%s_h__ */\n", define);
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
write_classname_iid_define(FILE *file, const char *className)
|
|
{
|
|
const char *iidName;
|
|
if (className[0] == 'n' && className[1] == 's') {
|
|
/* backcompat naming styles */
|
|
fputs("NS_", file);
|
|
iidName = className + 2;
|
|
} else {
|
|
iidName = className;
|
|
}
|
|
while (*iidName)
|
|
fputc(toupper(*iidName++), file);
|
|
fputs("_IID", file);
|
|
}
|
|
|
|
static gboolean
|
|
interface(TreeState *state)
|
|
{
|
|
IDL_tree iface = state->tree, iter, orig;
|
|
char *className = IDL_IDENT(IDL_INTERFACE(iface).ident).str;
|
|
char *classNameUpper = NULL;
|
|
char *classNameImpl = NULL;
|
|
char *cp;
|
|
gboolean ok = TRUE;
|
|
gboolean keepvtable;
|
|
const char *iid;
|
|
const char *name_space;
|
|
struct nsID id;
|
|
char iid_parsed[UUID_LENGTH];
|
|
GSList *doc_comments = IDL_IDENT(IDL_INTERFACE(iface).ident).comments;
|
|
|
|
if (!verify_interface_declaration(iface))
|
|
return FALSE;
|
|
|
|
#define FAIL do {ok = FALSE; goto out;} while(0)
|
|
|
|
fprintf(state->file, "\n/* starting interface: %s */\n",
|
|
className);
|
|
|
|
name_space = IDL_tree_property_get(IDL_INTERFACE(iface).ident, "namespace");
|
|
if (name_space) {
|
|
fprintf(state->file, "/* namespace: %s */\n",
|
|
name_space);
|
|
fprintf(state->file, "/* fully qualified name: %s.%s */\n",
|
|
name_space,className);
|
|
}
|
|
|
|
iid = IDL_tree_property_get(IDL_INTERFACE(iface).ident, "uuid");
|
|
if (iid) {
|
|
/* Redundant, but a better error than 'cannot parse.' */
|
|
if (strlen(iid) != 36) {
|
|
IDL_tree_error(state->tree, "IID %s is the wrong length\n", iid);
|
|
FAIL;
|
|
}
|
|
|
|
/*
|
|
* Parse uuid and then output resulting nsID to string, to validate
|
|
* uuid and normalize resulting .h files.
|
|
*/
|
|
if (!xpidl_parse_iid(&id, iid)) {
|
|
IDL_tree_error(state->tree, "cannot parse IID %s\n", iid);
|
|
FAIL;
|
|
}
|
|
if (!xpidl_sprint_iid(&id, iid_parsed)) {
|
|
IDL_tree_error(state->tree, "error formatting IID %s\n", iid);
|
|
FAIL;
|
|
}
|
|
|
|
/* #define NS_ISUPPORTS_IID_STR "00000000-0000-0000-c000-000000000046" */
|
|
fputs("#define ", state->file);
|
|
write_classname_iid_define(state->file, className);
|
|
fprintf(state->file, "_STR \"%s\"\n", iid_parsed);
|
|
fputc('\n', state->file);
|
|
|
|
/* #define NS_ISUPPORTS_IID { {0x00000000 .... 0x46 }} */
|
|
fprintf(state->file, "#define ");
|
|
write_classname_iid_define(state->file, className);
|
|
fprintf(state->file, " \\\n"
|
|
" {0x%.8x, 0x%.4x, 0x%.4x, \\\n"
|
|
" { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, "
|
|
"0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }}\n",
|
|
id.m0, id.m1, id.m2,
|
|
id.m3[0], id.m3[1], id.m3[2], id.m3[3],
|
|
id.m3[4], id.m3[5], id.m3[6], id.m3[7]);
|
|
fputc('\n', state->file);
|
|
} else {
|
|
IDL_tree_error(state->tree, "interface %s lacks a uuid attribute\n",
|
|
className);
|
|
FAIL;
|
|
}
|
|
|
|
if (doc_comments != NULL)
|
|
printlist(state->file, doc_comments);
|
|
|
|
/*
|
|
* NS_NO_VTABLE is defined in nsISupportsUtils.h, and defined on windows
|
|
* to __declspec(novtable) on windows. This optimization is safe
|
|
* whenever the constructor calls no virtual methods. Writing in IDL
|
|
* almost guarantees this, except for the case when a %{C++ block occurs in
|
|
* the interface. We detect that case, and emit a macro call that disables
|
|
* the optimization.
|
|
*/
|
|
keepvtable = FALSE;
|
|
for (iter = IDL_INTERFACE(state->tree).body;
|
|
iter != NULL;
|
|
iter = IDL_LIST(iter).next)
|
|
{
|
|
IDL_tree data = IDL_LIST(iter).data;
|
|
if (IDL_NODE_TYPE(data) == IDLN_CODEFRAG)
|
|
keepvtable = TRUE;
|
|
}
|
|
|
|
/* The interface declaration itself. */
|
|
fprintf(state->file,
|
|
"class %s%s",
|
|
(keepvtable ? "" : "NS_NO_VTABLE "), className);
|
|
|
|
if ((iter = IDL_INTERFACE(iface).inheritance_spec)) {
|
|
fputs(" : ", state->file);
|
|
if (IDL_LIST(iter).next != NULL) {
|
|
IDL_tree_error(iter,
|
|
"multiple inheritance is not supported by xpidl");
|
|
FAIL;
|
|
}
|
|
fprintf(state->file, "public %s", IDL_IDENT(IDL_LIST(iter).data).str);
|
|
}
|
|
fputs(" {\n"
|
|
" public: \n\n", state->file);
|
|
if (iid) {
|
|
fputs(" NS_DEFINE_STATIC_IID_ACCESSOR(", state->file);
|
|
write_classname_iid_define(state->file, className);
|
|
fputs(")\n\n", state->file);
|
|
}
|
|
|
|
orig = state->tree; /* It would be nice to remove this state-twiddling. */
|
|
|
|
state->tree = IDL_INTERFACE(iface).body;
|
|
|
|
if (state->tree && !xpidl_process_node(state))
|
|
FAIL;
|
|
|
|
fputs("};\n", state->file);
|
|
fputc('\n', state->file);
|
|
|
|
/*
|
|
* #define NS_DECL_NSIFOO - create method prototypes that can be used in
|
|
* class definitions that support this interface.
|
|
*
|
|
* Walk the tree explicitly to prototype a reworking of xpidl to get rid of
|
|
* the callback mechanism.
|
|
*/
|
|
state->tree = orig;
|
|
fputs("/* Use this macro when declaring classes that implement this "
|
|
"interface. */\n", state->file);
|
|
fputs("#define NS_DECL_", state->file);
|
|
classNameUpper = xpidl_strdup(className);
|
|
for (cp = classNameUpper; *cp != '\0'; cp++)
|
|
*cp = toupper(*cp);
|
|
fprintf(state->file, "%s \\\n", classNameUpper);
|
|
if (IDL_INTERFACE(state->tree).body == NULL) {
|
|
write_indent(state->file);
|
|
fputs("/* no methods! */\n", state->file);
|
|
}
|
|
|
|
for (iter = IDL_INTERFACE(state->tree).body;
|
|
iter != NULL;
|
|
iter = IDL_LIST(iter).next)
|
|
{
|
|
IDL_tree data = IDL_LIST(iter).data;
|
|
|
|
switch(IDL_NODE_TYPE(data)) {
|
|
case IDLN_OP_DCL:
|
|
write_indent(state->file);
|
|
write_method_signature(data, state->file, AS_DECL, NULL);
|
|
break;
|
|
|
|
case IDLN_ATTR_DCL:
|
|
write_indent(state->file);
|
|
if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL))
|
|
FAIL;
|
|
if (!IDL_ATTR_DCL(data).f_readonly) {
|
|
fputs("; \\\n", state->file); /* Terminate the previous one. */
|
|
write_indent(state->file);
|
|
if (!write_attr_accessor(data, state->file,
|
|
FALSE, AS_DECL, NULL))
|
|
FAIL;
|
|
/* '; \n' at end will clean up. */
|
|
}
|
|
break;
|
|
|
|
case IDLN_CONST_DCL:
|
|
/* ignore it here; it doesn't contribute to the macro. */
|
|
continue;
|
|
|
|
case IDLN_CODEFRAG:
|
|
XPIDL_WARNING((iter, IDL_WARNING1,
|
|
"%%{ .. %%} code fragment within interface "
|
|
"ignored when generating NS_DECL_%s macro; "
|
|
"if the code fragment contains method "
|
|
"declarations, the macro probably isn't "
|
|
"complete.", classNameUpper));
|
|
continue;
|
|
|
|
default:
|
|
IDL_tree_error(iter,
|
|
"unexpected node type %d! "
|
|
"Please file a bug against the xpidl component.",
|
|
IDL_NODE_TYPE(data));
|
|
FAIL;
|
|
}
|
|
|
|
if (IDL_LIST(iter).next != NULL) {
|
|
fprintf(state->file, "; \\\n");
|
|
} else {
|
|
fprintf(state->file, "; \n");
|
|
}
|
|
}
|
|
fputc('\n', state->file);
|
|
|
|
/* XXX abstract above and below into one function? */
|
|
/*
|
|
* #define NS_FORWARD_NSIFOO - create forwarding methods that can delegate
|
|
* behavior from in implementation to another object. As generated by
|
|
* idlc.
|
|
*/
|
|
fprintf(state->file,
|
|
"/* Use this macro to declare functions that forward the "
|
|
"behavior of this interface to another object. */\n"
|
|
"#define NS_FORWARD_%s(_to) \\\n",
|
|
classNameUpper);
|
|
if (IDL_INTERFACE(state->tree).body == NULL) {
|
|
write_indent(state->file);
|
|
fputs("/* no methods! */\n", state->file);
|
|
}
|
|
|
|
for (iter = IDL_INTERFACE(state->tree).body;
|
|
iter != NULL;
|
|
iter = IDL_LIST(iter).next)
|
|
{
|
|
IDL_tree data = IDL_LIST(iter).data;
|
|
|
|
switch(IDL_NODE_TYPE(data)) {
|
|
case IDLN_OP_DCL:
|
|
write_indent(state->file);
|
|
write_method_signature(data, state->file, AS_DECL, NULL);
|
|
fputs(" { return _to ", state->file);
|
|
write_method_signature(data, state->file, AS_CALL, NULL);
|
|
break;
|
|
|
|
case IDLN_ATTR_DCL:
|
|
write_indent(state->file);
|
|
if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL))
|
|
FAIL;
|
|
fputs(" { return _to ", state->file);
|
|
if (!write_attr_accessor(data, state->file, TRUE, AS_CALL, NULL))
|
|
FAIL;
|
|
if (!IDL_ATTR_DCL(data).f_readonly) {
|
|
fputs("; } \\\n", state->file); /* Terminate the previous one. */
|
|
write_indent(state->file);
|
|
if (!write_attr_accessor(data, state->file,
|
|
FALSE, AS_DECL, NULL))
|
|
FAIL;
|
|
fputs(" { return _to ", state->file);
|
|
if (!write_attr_accessor(data, state->file,
|
|
FALSE, AS_CALL, NULL))
|
|
FAIL;
|
|
/* '; } \n' at end will clean up. */
|
|
}
|
|
break;
|
|
|
|
case IDLN_CONST_DCL:
|
|
case IDLN_CODEFRAG:
|
|
continue;
|
|
|
|
default:
|
|
FAIL;
|
|
}
|
|
|
|
if (IDL_LIST(iter).next != NULL) {
|
|
fprintf(state->file, "; } \\\n");
|
|
} else {
|
|
fprintf(state->file, "; } \n");
|
|
}
|
|
}
|
|
fputc('\n', state->file);
|
|
|
|
|
|
/* XXX abstract above and below into one function? */
|
|
/*
|
|
* #define NS_FORWARD_SAFE_NSIFOO - create forwarding methods that can delegate
|
|
* behavior from in implementation to another object. As generated by
|
|
* idlc.
|
|
*/
|
|
fprintf(state->file,
|
|
"/* Use this macro to declare functions that forward the "
|
|
"behavior of this interface to another object in a safe way. */\n"
|
|
"#define NS_FORWARD_SAFE_%s(_to) \\\n",
|
|
classNameUpper);
|
|
if (IDL_INTERFACE(state->tree).body == NULL) {
|
|
write_indent(state->file);
|
|
fputs("/* no methods! */\n", state->file);
|
|
}
|
|
|
|
for (iter = IDL_INTERFACE(state->tree).body;
|
|
iter != NULL;
|
|
iter = IDL_LIST(iter).next)
|
|
{
|
|
IDL_tree data = IDL_LIST(iter).data;
|
|
|
|
switch(IDL_NODE_TYPE(data)) {
|
|
case IDLN_OP_DCL:
|
|
write_indent(state->file);
|
|
write_method_signature(data, state->file, AS_DECL, NULL);
|
|
fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file);
|
|
write_method_signature(data, state->file, AS_CALL, NULL);
|
|
break;
|
|
|
|
case IDLN_ATTR_DCL:
|
|
write_indent(state->file);
|
|
if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL))
|
|
FAIL;
|
|
fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file);
|
|
if (!write_attr_accessor(data, state->file, TRUE, AS_CALL, NULL))
|
|
FAIL;
|
|
if (!IDL_ATTR_DCL(data).f_readonly) {
|
|
fputs("; } \\\n", state->file); /* Terminate the previous one. */
|
|
write_indent(state->file);
|
|
if (!write_attr_accessor(data, state->file,
|
|
FALSE, AS_DECL, NULL))
|
|
FAIL;
|
|
fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file);
|
|
if (!write_attr_accessor(data, state->file,
|
|
FALSE, AS_CALL, NULL))
|
|
FAIL;
|
|
/* '; } \n' at end will clean up. */
|
|
}
|
|
break;
|
|
|
|
case IDLN_CONST_DCL:
|
|
case IDLN_CODEFRAG:
|
|
continue;
|
|
|
|
default:
|
|
FAIL;
|
|
}
|
|
|
|
if (IDL_LIST(iter).next != NULL) {
|
|
fprintf(state->file, "; } \\\n");
|
|
} else {
|
|
fprintf(state->file, "; } \n");
|
|
}
|
|
}
|
|
fputc('\n', state->file);
|
|
|
|
/*
|
|
* Build a sample implementation template.
|
|
*/
|
|
if (strlen(className) >= 3 && className[2] == 'I') {
|
|
classNameImpl = xpidl_strdup(className);
|
|
if (!classNameImpl)
|
|
FAIL;
|
|
memmove(&classNameImpl[2], &classNameImpl[3], strlen(classNameImpl) - 2);
|
|
} else {
|
|
classNameImpl = xpidl_strdup("_MYCLASS_");
|
|
if (!classNameImpl)
|
|
FAIL;
|
|
}
|
|
|
|
fputs("#if 0\n"
|
|
"/* Use the code below as a template for the "
|
|
"implementation class for this interface. */\n"
|
|
"\n"
|
|
"/* Header file */"
|
|
"\n",
|
|
state->file);
|
|
fprintf(state->file, "class %s : public %s\n", classNameImpl, className);
|
|
fputs("{\n"
|
|
"public:\n", state->file);
|
|
write_indent(state->file);
|
|
fputs("NS_DECL_ISUPPORTS\n", state->file);
|
|
write_indent(state->file);
|
|
fprintf(state->file, "NS_DECL_%s\n", classNameUpper);
|
|
fputs("\n", state->file);
|
|
write_indent(state->file);
|
|
fprintf(state->file, "%s();\n", classNameImpl);
|
|
fputs("\n"
|
|
"private:\n", state->file);
|
|
write_indent(state->file);
|
|
fprintf(state->file, "~%s();\n", classNameImpl);
|
|
fputs("\n"
|
|
"protected:\n", state->file);
|
|
write_indent(state->file);
|
|
fputs("/* additional members */\n", state->file);
|
|
fputs("};\n\n", state->file);
|
|
|
|
fputs("/* Implementation file */\n", state->file);
|
|
|
|
fprintf(state->file,
|
|
"NS_IMPL_ISUPPORTS1(%s, %s)\n", classNameImpl, className);
|
|
fputs("\n", state->file);
|
|
|
|
fprintf(state->file, "%s::%s()\n", classNameImpl, classNameImpl);
|
|
fputs("{\n", state->file);
|
|
write_indent(state->file);
|
|
fputs("/* member initializers and constructor code */\n", state->file);
|
|
fputs("}\n\n", state->file);
|
|
|
|
fprintf(state->file, "%s::~%s()\n", classNameImpl, classNameImpl);
|
|
fputs("{\n", state->file);
|
|
write_indent(state->file);
|
|
fputs("/* destructor code */\n", state->file);
|
|
fputs("}\n\n", state->file);
|
|
|
|
for (iter = IDL_INTERFACE(state->tree).body;
|
|
iter != NULL;
|
|
iter = IDL_LIST(iter).next)
|
|
{
|
|
IDL_tree data = IDL_LIST(iter).data;
|
|
|
|
switch(IDL_NODE_TYPE(data)) {
|
|
case IDLN_OP_DCL:
|
|
/* It would be nice to remove this state-twiddling. */
|
|
orig = state->tree;
|
|
state->tree = data;
|
|
xpidl_write_comment(state, 0);
|
|
state->tree = orig;
|
|
|
|
write_method_signature(data, state->file, AS_IMPL, classNameImpl);
|
|
fputs("\n{\n", state->file);
|
|
write_indent(state->file);
|
|
write_indent(state->file);
|
|
fputs("return NS_ERROR_NOT_IMPLEMENTED;\n"
|
|
"}\n"
|
|
"\n", state->file);
|
|
break;
|
|
|
|
case IDLN_ATTR_DCL:
|
|
/* It would be nice to remove this state-twiddling. */
|
|
orig = state->tree;
|
|
state->tree = data;
|
|
xpidl_write_comment(state, 0);
|
|
state->tree = orig;
|
|
|
|
if (!write_attr_accessor(data, state->file, TRUE,
|
|
AS_IMPL, classNameImpl))
|
|
FAIL;
|
|
fputs("\n{\n", state->file);
|
|
write_indent(state->file);
|
|
write_indent(state->file);
|
|
fputs("return NS_ERROR_NOT_IMPLEMENTED;\n"
|
|
"}\n", state->file);
|
|
|
|
if (!IDL_ATTR_DCL(data).f_readonly) {
|
|
if (!write_attr_accessor(data, state->file, FALSE,
|
|
AS_IMPL, classNameImpl))
|
|
FAIL;
|
|
fputs("\n{\n", state->file);
|
|
write_indent(state->file);
|
|
write_indent(state->file);
|
|
fputs("return NS_ERROR_NOT_IMPLEMENTED;\n"
|
|
"}\n", state->file);
|
|
}
|
|
fputs("\n", state->file);
|
|
break;
|
|
|
|
case IDLN_CONST_DCL:
|
|
case IDLN_CODEFRAG:
|
|
continue;
|
|
|
|
default:
|
|
FAIL;
|
|
}
|
|
}
|
|
|
|
fputs("/* End of implementation class template. */\n"
|
|
"#endif\n"
|
|
"\n", state->file);
|
|
|
|
#undef FAIL
|
|
|
|
out:
|
|
if (classNameUpper)
|
|
free(classNameUpper);
|
|
if (classNameImpl)
|
|
free(classNameImpl);
|
|
return ok;
|
|
}
|
|
|
|
static gboolean
|
|
list(TreeState *state)
|
|
{
|
|
IDL_tree iter;
|
|
for (iter = state->tree; iter; iter = IDL_LIST(iter).next) {
|
|
state->tree = IDL_LIST(iter).data;
|
|
if (!xpidl_process_node(state))
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
write_type(IDL_tree type_tree, gboolean is_out, FILE *outfile)
|
|
{
|
|
if (!type_tree) {
|
|
fputs("void", outfile);
|
|
return TRUE;
|
|
}
|
|
|
|
switch (IDL_NODE_TYPE(type_tree)) {
|
|
case IDLN_TYPE_INTEGER: {
|
|
gboolean sign = IDL_TYPE_INTEGER(type_tree).f_signed;
|
|
switch (IDL_TYPE_INTEGER(type_tree).f_type) {
|
|
case IDL_INTEGER_TYPE_SHORT:
|
|
fputs(sign ? "PRInt16" : "PRUint16", outfile);
|
|
break;
|
|
case IDL_INTEGER_TYPE_LONG:
|
|
fputs(sign ? "PRInt32" : "PRUint32", outfile);
|
|
break;
|
|
case IDL_INTEGER_TYPE_LONGLONG:
|
|
fputs(sign ? "PRInt64" : "PRUint64", outfile);
|
|
break;
|
|
default:
|
|
g_error("Unknown integer type %d\n",
|
|
IDL_TYPE_INTEGER(type_tree).f_type);
|
|
return FALSE;
|
|
}
|
|
break;
|
|
}
|
|
case IDLN_TYPE_CHAR:
|
|
fputs("char", outfile);
|
|
break;
|
|
case IDLN_TYPE_WIDE_CHAR:
|
|
fputs("PRUnichar", outfile); /* wchar_t? */
|
|
break;
|
|
case IDLN_TYPE_WIDE_STRING:
|
|
fputs("PRUnichar *", outfile);
|
|
break;
|
|
case IDLN_TYPE_STRING:
|
|
fputs("char *", outfile);
|
|
break;
|
|
case IDLN_TYPE_BOOLEAN:
|
|
fputs("PRBool", outfile);
|
|
break;
|
|
case IDLN_TYPE_OCTET:
|
|
fputs("PRUint8", outfile);
|
|
break;
|
|
case IDLN_TYPE_FLOAT:
|
|
switch (IDL_TYPE_FLOAT(type_tree).f_type) {
|
|
case IDL_FLOAT_TYPE_FLOAT:
|
|
fputs("float", outfile);
|
|
break;
|
|
case IDL_FLOAT_TYPE_DOUBLE:
|
|
fputs("double", outfile);
|
|
break;
|
|
/* XXX 'long double' just ignored, or what? */
|
|
default:
|
|
fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree));
|
|
break;
|
|
}
|
|
break;
|
|
case IDLN_IDENT:
|
|
if (UP_IS_NATIVE(type_tree)) {
|
|
if (IDL_tree_property_get(type_tree, "domstring") ||
|
|
IDL_tree_property_get(type_tree, "astring")) {
|
|
fputs("nsAString", outfile);
|
|
} else if (IDL_tree_property_get(type_tree, "utf8string")) {
|
|
fputs("nsACString", outfile);
|
|
} else if (IDL_tree_property_get(type_tree, "cstring")) {
|
|
fputs("nsACString", outfile);
|
|
} else {
|
|
fputs(IDL_NATIVE(IDL_NODE_UP(type_tree)).user_type, outfile);
|
|
}
|
|
if (IDL_tree_property_get(type_tree, "ptr")) {
|
|
fputs(" *", outfile);
|
|
} else if (IDL_tree_property_get(type_tree, "ref")) {
|
|
fputs(" &", outfile);
|
|
}
|
|
} else {
|
|
fputs(IDL_IDENT(type_tree).str, outfile);
|
|
}
|
|
if (UP_IS_AGGREGATE(type_tree))
|
|
fputs(" *", outfile);
|
|
break;
|
|
default:
|
|
fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree));
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* An attribute declaration looks like:
|
|
*
|
|
* [ IDL_ATTR_DCL]
|
|
* - param_type_spec [IDL_TYPE_* or NULL for void]
|
|
* - simple_declarations [IDL_LIST]
|
|
* - data [IDL_IDENT]
|
|
* - next [IDL_LIST or NULL if no more idents]
|
|
* - data [IDL_IDENT]
|
|
*/
|
|
|
|
#define ATTR_IDENT(tree) (IDL_IDENT(IDL_LIST(IDL_ATTR_DCL(tree).simple_declarations).data))
|
|
#define ATTR_TYPE_DECL(tree) (IDL_ATTR_DCL(tree).param_type_spec)
|
|
#define ATTR_TYPE(tree) (IDL_NODE_TYPE(ATTR_TYPE_DECL(tree)))
|
|
|
|
/*
|
|
* AS_DECL writes 'NS_IMETHOD foo(string bar, long sil)'
|
|
* AS_IMPL writes 'NS_IMETHODIMP className::foo(string bar, long sil)'
|
|
* AS_CALL writes 'foo(bar, sil)'
|
|
*/
|
|
static gboolean
|
|
write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
|
|
gboolean getter, int mode, const char *className)
|
|
{
|
|
char *attrname = ATTR_IDENT(attr_tree).str;
|
|
|
|
if (mode == AS_DECL) {
|
|
fputs("NS_IMETHOD ", outfile);
|
|
} else if (mode == AS_IMPL) {
|
|
fprintf(outfile, "NS_IMETHODIMP %s::", className);
|
|
}
|
|
fprintf(outfile, "%cet%c%s(",
|
|
getter ? 'G' : 'S',
|
|
toupper(*attrname), attrname + 1);
|
|
if (mode == AS_DECL || mode == AS_IMPL) {
|
|
/* Setters for string, wstring, nsid, domstring, utf8string,
|
|
* cstring and astring get const.
|
|
*/
|
|
if (!getter &&
|
|
(IDL_NODE_TYPE(ATTR_TYPE_DECL(attr_tree)) == IDLN_TYPE_STRING ||
|
|
IDL_NODE_TYPE(ATTR_TYPE_DECL(attr_tree)) == IDLN_TYPE_WIDE_STRING ||
|
|
IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "nsid") ||
|
|
IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "domstring") ||
|
|
IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "utf8string") ||
|
|
IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "cstring") ||
|
|
IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "astring")))
|
|
{
|
|
fputs("const ", outfile);
|
|
}
|
|
|
|
if (!write_type(ATTR_TYPE_DECL(attr_tree), getter, outfile))
|
|
return FALSE;
|
|
fprintf(outfile, "%s%s",
|
|
(STARRED_TYPE(attr_tree) ? "" : " "),
|
|
(getter && !DIPPER_TYPE(ATTR_TYPE_DECL(attr_tree)))? "*" : "");
|
|
}
|
|
fprintf(outfile, "a%c%s)", toupper(attrname[0]), attrname + 1);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
attr_dcl(TreeState *state)
|
|
{
|
|
GSList *doc_comments;
|
|
|
|
if (!verify_attribute_declaration(state->tree))
|
|
return FALSE;
|
|
|
|
doc_comments =
|
|
IDL_IDENT(IDL_LIST(IDL_ATTR_DCL
|
|
(state->tree).simple_declarations).data).comments;
|
|
|
|
if (doc_comments != NULL) {
|
|
write_indent(state->file);
|
|
printlist(state->file, doc_comments);
|
|
}
|
|
|
|
/*
|
|
* XXX lists of attributes with the same type, e.g.
|
|
* attribute string foo, bar sil;
|
|
* are legal IDL... but we don't do anything with 'em.
|
|
*/
|
|
if (IDL_LIST(IDL_ATTR_DCL(state->tree).simple_declarations).next != NULL) {
|
|
XPIDL_WARNING((state->tree, IDL_WARNING1,
|
|
"multiple attributes in a single declaration aren't "
|
|
"currently supported by xpidl"));
|
|
}
|
|
|
|
xpidl_write_comment(state, 2);
|
|
|
|
write_indent(state->file);
|
|
if (!write_attr_accessor(state->tree, state->file, TRUE, AS_DECL, NULL))
|
|
return FALSE;
|
|
fputs(" = 0;\n", state->file);
|
|
|
|
if (!IDL_ATTR_DCL(state->tree).f_readonly) {
|
|
write_indent(state->file);
|
|
if (!write_attr_accessor(state->tree, state->file, FALSE, AS_DECL, NULL))
|
|
return FALSE;
|
|
fputs(" = 0;\n", state->file);
|
|
}
|
|
fputc('\n', state->file);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
do_enum(TreeState *state)
|
|
{
|
|
IDL_tree_error(state->tree, "enums not supported, "
|
|
"see http://bugzilla.mozilla.org/show_bug.cgi?id=8781");
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
do_const_dcl(TreeState *state)
|
|
{
|
|
struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(state->tree);
|
|
const char *name = IDL_IDENT(dcl->ident).str;
|
|
gboolean is_signed;
|
|
GSList *doc_comments = IDL_IDENT(dcl->ident).comments;
|
|
IDL_tree real_type;
|
|
const char *const_format;
|
|
|
|
if (!verify_const_declaration(state->tree))
|
|
return FALSE;
|
|
|
|
if (doc_comments != NULL) {
|
|
write_indent(state->file);
|
|
printlist(state->file, doc_comments);
|
|
}
|
|
|
|
/* Could be a typedef; try to map it to the real type. */
|
|
real_type = find_underlying_type(dcl->const_type);
|
|
real_type = real_type ? real_type : dcl->const_type;
|
|
is_signed = IDL_TYPE_INTEGER(real_type).f_signed;
|
|
|
|
const_format = is_signed ? "%" IDL_LL "d" : "%" IDL_LL "uU";
|
|
write_indent(state->file);
|
|
fprintf(state->file, "enum { %s = ", name);
|
|
fprintf(state->file, const_format, IDL_INTEGER(dcl->const_exp).value);
|
|
fprintf(state->file, " };\n\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
do_typedef(TreeState *state)
|
|
{
|
|
IDL_tree type = IDL_TYPE_DCL(state->tree).type_spec;
|
|
IDL_tree dcls = IDL_TYPE_DCL(state->tree).dcls;
|
|
IDL_tree complex;
|
|
GSList *doc_comments;
|
|
|
|
if (IDL_NODE_TYPE(type) == IDLN_TYPE_SEQUENCE) {
|
|
XPIDL_WARNING((state->tree, IDL_WARNING1,
|
|
"sequences not supported, ignored"));
|
|
} else {
|
|
if (IDL_NODE_TYPE(complex = IDL_LIST(dcls).data) == IDLN_TYPE_ARRAY) {
|
|
IDL_tree dim = IDL_TYPE_ARRAY(complex).size_list;
|
|
doc_comments = IDL_IDENT(IDL_TYPE_ARRAY(complex).ident).comments;
|
|
|
|
if (doc_comments != NULL)
|
|
printlist(state->file, doc_comments);
|
|
|
|
fputs("typedef ", state->file);
|
|
if (!write_type(type, FALSE, state->file))
|
|
return FALSE;
|
|
fputs(" ", state->file);
|
|
|
|
fprintf(state->file, "%s",
|
|
IDL_IDENT(IDL_TYPE_ARRAY(complex).ident).str);
|
|
do {
|
|
fputc('[', state->file);
|
|
if (IDL_LIST(dim).data) {
|
|
fprintf(state->file, "%ld",
|
|
(long)IDL_INTEGER(IDL_LIST(dim).data).value);
|
|
}
|
|
fputc(']', state->file);
|
|
} while ((dim = IDL_LIST(dim).next) != NULL);
|
|
} else {
|
|
doc_comments = IDL_IDENT(IDL_LIST(dcls).data).comments;
|
|
|
|
if (doc_comments != NULL)
|
|
printlist(state->file, doc_comments);
|
|
|
|
fputs("typedef ", state->file);
|
|
if (!write_type(type, FALSE, state->file))
|
|
return FALSE;
|
|
fputs(" ", state->file);
|
|
fputs(IDL_IDENT(IDL_LIST(dcls).data).str, state->file);
|
|
}
|
|
fputs(";\n\n", state->file);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* param generation:
|
|
* in string foo --> nsString *foo
|
|
* out string foo --> nsString **foo;
|
|
* inout string foo --> nsString **foo;
|
|
*/
|
|
|
|
/* If notype is true, just write the param name. */
|
|
static gboolean
|
|
write_param(IDL_tree param_tree, FILE *outfile)
|
|
{
|
|
IDL_tree param_type_spec = IDL_PARAM_DCL(param_tree).param_type_spec;
|
|
gboolean is_in = IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_IN;
|
|
/* in string, wstring, nsid, domstring, utf8string, cstring and
|
|
* astring any explicitly marked [const] are const
|
|
*/
|
|
|
|
if (is_in &&
|
|
(IDL_NODE_TYPE(param_type_spec) == IDLN_TYPE_STRING ||
|
|
IDL_NODE_TYPE(param_type_spec) == IDLN_TYPE_WIDE_STRING ||
|
|
IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator,
|
|
"const") ||
|
|
IDL_tree_property_get(param_type_spec, "nsid") ||
|
|
IDL_tree_property_get(param_type_spec, "domstring") ||
|
|
IDL_tree_property_get(param_type_spec, "utf8string") ||
|
|
IDL_tree_property_get(param_type_spec, "cstring") ||
|
|
IDL_tree_property_get(param_type_spec, "astring"))) {
|
|
fputs("const ", outfile);
|
|
}
|
|
else if (IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_OUT &&
|
|
IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator,
|
|
"shared")) {
|
|
fputs("const ", outfile);
|
|
}
|
|
|
|
if (!write_type(param_type_spec, !is_in, outfile))
|
|
return FALSE;
|
|
|
|
/* unless the type ended in a *, add a space */
|
|
if (!STARRED_TYPE(param_type_spec))
|
|
fputc(' ', outfile);
|
|
|
|
/* out and inout params get a bonus '*' (unless this is type that has a
|
|
* 'dipper' class that is passed in to receive 'out' data)
|
|
*/
|
|
if (IDL_PARAM_DCL(param_tree).attr != IDL_PARAM_IN &&
|
|
!DIPPER_TYPE(param_type_spec)) {
|
|
fputc('*', outfile);
|
|
}
|
|
/* arrays get a bonus * too */
|
|
/* XXX Should this be a leading '*' or a trailing "[]" ?*/
|
|
if (IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator,
|
|
"array"))
|
|
fputc('*', outfile);
|
|
|
|
fputs(IDL_IDENT(IDL_PARAM_DCL(param_tree).simple_declarator).str, outfile);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* A forward declaration, usually an interface.
|
|
*/
|
|
static gboolean
|
|
forward_dcl(TreeState *state)
|
|
{
|
|
IDL_tree iface = state->tree;
|
|
const char *className = IDL_IDENT(IDL_FORWARD_DCL(iface).ident).str;
|
|
|
|
if (!className)
|
|
return FALSE;
|
|
|
|
fprintf(state->file, "class %s; /* forward declaration */\n\n", className);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Shared between the interface class declaration and the NS_DECL_IFOO macro
|
|
* provided to aid declaration of implementation classes.
|
|
* mode...
|
|
* AS_DECL writes 'NS_IMETHOD foo(string bar, long sil)'
|
|
* AS_IMPL writes 'NS_IMETHODIMP className::foo(string bar, long sil)'
|
|
* AS_CALL writes 'foo(bar, sil)'
|
|
*/
|
|
static gboolean
|
|
write_method_signature(IDL_tree method_tree, FILE *outfile, int mode,
|
|
const char *className)
|
|
{
|
|
struct _IDL_OP_DCL *op = &IDL_OP_DCL(method_tree);
|
|
gboolean no_generated_args = TRUE;
|
|
gboolean op_notxpcom =
|
|
(IDL_tree_property_get(op->ident, "notxpcom") != NULL);
|
|
const char *name;
|
|
IDL_tree iter;
|
|
|
|
if (mode == AS_DECL) {
|
|
if (op_notxpcom) {
|
|
fputs("NS_IMETHOD_(", outfile);
|
|
if (!write_type(op->op_type_spec, FALSE, outfile))
|
|
return FALSE;
|
|
fputc(')', outfile);
|
|
} else {
|
|
fputs("NS_IMETHOD", outfile);
|
|
}
|
|
fputc(' ', outfile);
|
|
}
|
|
else if (mode == AS_IMPL) {
|
|
if (op_notxpcom) {
|
|
fputs("NS_IMETHODIMP_(", outfile);
|
|
if (!write_type(op->op_type_spec, FALSE, outfile))
|
|
return FALSE;
|
|
fputc(')', outfile);
|
|
} else {
|
|
fputs("NS_IMETHODIMP", outfile);
|
|
}
|
|
fputc(' ', outfile);
|
|
}
|
|
name = IDL_IDENT(op->ident).str;
|
|
if (mode == AS_IMPL) {
|
|
fprintf(outfile, "%s::%c%s(", className, toupper(*name), name + 1);
|
|
} else {
|
|
fprintf(outfile, "%c%s(", toupper(*name), name + 1);
|
|
}
|
|
for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next) {
|
|
if (mode == AS_DECL || mode == AS_IMPL) {
|
|
if (!write_param(IDL_LIST(iter).data, outfile))
|
|
return FALSE;
|
|
} else {
|
|
fputs(IDL_IDENT(IDL_PARAM_DCL(IDL_LIST(iter).data)
|
|
.simple_declarator).str,
|
|
outfile);
|
|
}
|
|
if ((IDL_LIST(iter).next ||
|
|
(!op_notxpcom && op->op_type_spec) || op->f_varargs))
|
|
fputs(", ", outfile);
|
|
no_generated_args = FALSE;
|
|
}
|
|
|
|
/* make IDL return value into trailing out argument */
|
|
if (op->op_type_spec && !op_notxpcom) {
|
|
IDL_tree fake_param = IDL_param_dcl_new(IDL_PARAM_OUT,
|
|
op->op_type_spec,
|
|
IDL_ident_new("_retval"));
|
|
if (!fake_param)
|
|
return FALSE;
|
|
if (mode == AS_DECL || mode == AS_IMPL) {
|
|
if (!write_param(fake_param, outfile))
|
|
return FALSE;
|
|
} else {
|
|
fputs("_retval", outfile);
|
|
}
|
|
if (op->f_varargs)
|
|
fputs(", ", outfile);
|
|
no_generated_args = FALSE;
|
|
}
|
|
|
|
/* varargs go last */
|
|
if (op->f_varargs) {
|
|
if (mode == AS_DECL || mode == AS_IMPL) {
|
|
fputs("nsVarArgs *", outfile);
|
|
}
|
|
fputs("_varargs", outfile);
|
|
no_generated_args = FALSE;
|
|
}
|
|
|
|
/*
|
|
* If generated method has no arguments, output 'void' to avoid C legacy
|
|
* behavior of disabling type checking.
|
|
*/
|
|
if (no_generated_args && mode == AS_DECL) {
|
|
fputs("void", outfile);
|
|
}
|
|
|
|
fputc(')', outfile);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* A method is an `operation', therefore a method decl is an `op dcl'.
|
|
* I blame Elliot.
|
|
*/
|
|
static gboolean
|
|
op_dcl(TreeState *state)
|
|
{
|
|
GSList *doc_comments = IDL_IDENT(IDL_OP_DCL(state->tree).ident).comments;
|
|
|
|
/*
|
|
* Verify that e.g. non-scriptable methods in [scriptable] interfaces
|
|
* are declared so. Do this in a separate verification pass?
|
|
*/
|
|
if (!verify_method_declaration(state->tree))
|
|
return FALSE;
|
|
|
|
if (doc_comments != NULL) {
|
|
write_indent(state->file);
|
|
printlist(state->file, doc_comments);
|
|
}
|
|
xpidl_write_comment(state, 2);
|
|
|
|
write_indent(state->file);
|
|
if (!write_method_signature(state->tree, state->file, AS_DECL, NULL))
|
|
return FALSE;
|
|
fputs(" = 0;\n\n", state->file);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
write_codefrag_line(gpointer data, gpointer user_data)
|
|
{
|
|
TreeState *state = (TreeState *)user_data;
|
|
const char *line = (const char *)data;
|
|
fputs(line, state->file);
|
|
fputc('\n', state->file);
|
|
}
|
|
|
|
static gboolean
|
|
codefrag(TreeState *state)
|
|
{
|
|
const char *desc = IDL_CODEFRAG(state->tree).desc;
|
|
GSList *lines = IDL_CODEFRAG(state->tree).lines;
|
|
guint fragment_length;
|
|
|
|
if (strcmp(desc, "C++") && /* libIDL bug? */ strcmp(desc, "C++\r")) {
|
|
XPIDL_WARNING((state->tree, IDL_WARNING1,
|
|
"ignoring '%%{%s' escape. "
|
|
"(Use '%%{C++' to escape verbatim C++ code.)", desc));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Emit #file directive to point debuggers back to the original .idl file
|
|
* for the duration of the code fragment. We look at internal IDL node
|
|
* properties _file, _line to do this; hopefully they won't change.
|
|
*
|
|
* _line seems to refer to the line immediately after the closing %}, so
|
|
* we backtrack to get the proper line for the beginning of the block.
|
|
*/
|
|
/*
|
|
* Looks like getting this right means maintaining an accurate line
|
|
* count of everything generated, so we can set the file back to the
|
|
* correct line in the generated file afterwards. Skipping for now...
|
|
*/
|
|
|
|
fragment_length = g_slist_length(lines);
|
|
/* fprintf(state->file, "#line %d \"%s\"\n", */
|
|
/* state->tree->_line - fragment_length - 1, */
|
|
/* state->tree->_file); */
|
|
|
|
g_slist_foreach(lines, write_codefrag_line, (gpointer)state);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
backend *
|
|
xpidl_header_dispatch(void)
|
|
{
|
|
static backend result;
|
|
static nodeHandler table[IDLN_LAST];
|
|
static gboolean initialized = FALSE;
|
|
|
|
result.emit_prolog = header_prolog;
|
|
result.emit_epilog = header_epilog;
|
|
|
|
if (!initialized) {
|
|
table[IDLN_LIST] = list;
|
|
table[IDLN_ATTR_DCL] = attr_dcl;
|
|
table[IDLN_OP_DCL] = op_dcl;
|
|
table[IDLN_FORWARD_DCL] = forward_dcl;
|
|
table[IDLN_TYPE_ENUM] = do_enum;
|
|
table[IDLN_INTERFACE] = interface;
|
|
table[IDLN_CODEFRAG] = codefrag;
|
|
table[IDLN_TYPE_DCL] = do_typedef;
|
|
table[IDLN_CONST_DCL] = do_const_dcl;
|
|
table[IDLN_NATIVE] = check_native;
|
|
initialized = TRUE;
|
|
}
|
|
|
|
result.dispatch_table = table;
|
|
return &result;
|
|
}
|