diff options
author | David Zeuthen <davidz@redhat.com> | 2009-05-07 19:26:55 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2009-05-07 19:26:55 -0400 |
commit | e4e6527f7ad3c486b23186c1ce53045664b28bb8 (patch) | |
tree | f4e2c60e65903892a335eeda252a86ea7adf2a23 | |
parent | bc2486b369506c07ec2d62bc16a5c80d35479947 (diff) |
First stab at language and parser
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | src/Makefile.am | 58 | ||||
-rw-r--r-- | src/dbus-idl-1.pc.in | 11 | ||||
-rw-r--r-- | src/dbusidl.c | 1867 | ||||
-rw-r--r-- | src/dbusidl.h | 234 | ||||
-rw-r--r-- | src/dbusidlprivate.h | 319 | ||||
-rw-r--r-- | src/idl.h (renamed from src/main.c) | 25 | ||||
-rw-r--r-- | src/idllexer.l | 156 | ||||
-rw-r--r-- | src/idlparser.y | 788 | ||||
-rw-r--r-- | src/org.freedesktop.DBus.Idl.Tests1.didl | 116 | ||||
-rw-r--r-- | src/test.c | 74 |
11 files changed, 3635 insertions, 16 deletions
diff --git a/configure.ac b/configure.ac index 25155a0..a49c081 100644 --- a/configure.ac +++ b/configure.ac @@ -8,6 +8,8 @@ AC_PROG_CC AC_ISC_POSIX AC_HEADER_STDC AC_PROG_LIBTOOL +AC_PROG_LEX +AC_PROG_YACC #### gcc warning flags AC_ARG_ENABLE(ansi, [ --enable-ansi enable -ansi -pedantic gcc flags],enable_ansi=$enableval,enable_ansi=no) @@ -90,6 +92,7 @@ AC_SUBST(GLIB2_LIBS) AC_OUTPUT([ Makefile src/Makefile +src/dbus-idl-1.pc ]) echo " diff --git a/src/Makefile.am b/src/Makefile.am index 70b8886..5291751 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,19 +1,65 @@ NULL = -noinst_PROGRAMS = dbus-idl +INCLUDES = -DDBUS_IDL_I_UNDERSTAND_THAT_API_IS_UNSTABLE -dbus_idl_SOURCES = \ - main.c \ +noinst_PROGRAMS = dbus-idl-test + +pkgconfigdir=$(libdir)/pkgconfig +pkgconfig_DATA = dbus-idl-1.pc + +dbus_idl_test_SOURCES = \ + test.c \ $(NULL) -dbus_idl_CFLAGS = \ +dbus_idl_test_CFLAGS = \ $(GLIB2_CFLAGS) \ $(NULL) -dbus_idl_LDADD = \ +dbus_idl_test_LDADD = \ $(GLIB2_LIBS) \ + libdbus-idl-1.la \ + $(NULL) + +lib_LTLIBRARIES=libdbus-idl-1.la + +libdbus_idl_1_la_includedir = \ + $(includedir)/dbus-idl-1/dbusidl + $(NULL) + +libdbus_idl_1_la_include_HEADERS = \ + dbusidl.h \ + $(NULL) + +libdbus_idl_1_la_SOURCES = \ + idl.h \ + idllexer.l idlparser.y \ + dbusidlprivate.h \ + dbusidl.h dbusidl.c \ + $(NULL) + +libdbus_idl_1_la_CFLAGS = \ + $(GLIB2_CFLAGS) \ $(NULL) +libdbus_idl_1_la_LIBADD = \ + $(GLIB2_LIBS) \ + $(NULL) + +idllexer.c : idllexer.l libdbus_idl_1_la-idlparser.h + +idlparser.c : idlparser.y + +libdbus_idl_1_la_YFLAGS = -v -d + +# ---------------------------------------------------------------------------------------------------- + +TESTS = dbus-idl-test + +EXTRA_DIST = org.freedesktop.DBus.Idl.Tests1.didl + +# ---------------------------------------------------------------------------------------------------- + clean-local: - rm -f *~ + rm -f *~ libdbus_idl_1_la-* + diff --git a/src/dbus-idl-1.pc.in b/src/dbus-idl-1.pc.in new file mode 100644 index 0000000..906da07 --- /dev/null +++ b/src/dbus-idl-1.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: dbus-idl-1 +Description: D-Bus Introspection Parser +Version: @VERSION@ +Libs: -L${libdir} -ldbus-idl-1 +Cflags: -I${includedir}/dbus-idl-1 +Requires: glib-2.0 >= 2.18 diff --git a/src/dbusidl.c b/src/dbusidl.c new file mode 100644 index 0000000..947d486 --- /dev/null +++ b/src/dbusidl.c @@ -0,0 +1,1867 @@ +/* Copyright (C) 2009 David Zeuthen <zeuthen@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen <zeuthen@gmail.com> + */ + +#include "config.h" + +#include <string.h> + +#include "idl.h" +#include "dbusidl.h" + +/* ---------------------------------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------------------------------- */ + +DIBaseType +di_base_get_type (DIBase *base) +{ + return base->type; +} + +const gchar * +di_base_get_decl_path (DIBase *base) +{ + return base->decl_filename; +} + +guint +di_base_get_decl_lineno (DIBase *base) +{ + return base->decl_lineno; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/* getters */ + +const gchar * +di_type_get_name (DIType *type) +{ + return type->fully_qualified_name != NULL ? type->fully_qualified_name : type->name; +} + +const gchar * +di_type_get_signature (DIType *type) +{ + return type->signature; +} + +static gint +get_typecode_for_primitive_type (const gchar *name) +{ + guint n; + const gchar *primitive_types[] = { + "byte", "y", + "boolean", "b", + "int16", "n", + "uint16", "q", + "int32", "i", + "uint32", "u", + "int64", "x", + "uint64", "t", + "double", "d", + "string", "s", + "objpath", "o", + "signature", "g", + "variant", "v", + NULL + }; + + for (n = 0; primitive_types[n] != NULL; n += 2) + { + if (g_strcmp0 (name, primitive_types[n]) == 0) + return (primitive_types[n+1])[0]; + } + + return -1; +} + +gint +di_type_get_typecode (DIType *type) +{ + return get_typecode_for_primitive_type (type->name); +} + +GList * +di_type_get_inner_types (DIType *type) +{ + return type->inner_types; +} + + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar * +di_arg_get_name (DIArg *arg) +{ + return arg->name; +} + +DIType * +di_arg_get_type (DIArg *arg) +{ + return arg->type; +} + +DIArgDirection +di_arg_get_direction (DIArg *arg) +{ + return arg->direction; +} + +GList * +di_arg_get_annotations (DIArg *arg) +{ + return arg->annotations; +} + + +const gchar * +di_method_get_name (DIMethod *method) +{ + return method->name; +} + +GList * +di_method_get_args (DIMethod *method) +{ + return method->args; +} + +GList * +di_method_get_annotations (DIMethod *method) +{ + return method->annotations; +} + +const gchar * +di_method_get_in_signature (DIMethod *method) +{ + return method->in_signature; +} + +const gchar * +di_method_get_out_signature (DIMethod *method) +{ + return method->out_signature; +} + + +const gchar * +di_signal_get_name (DISignal *signal) +{ + return signal->name; +} + +GList * +di_signal_get_args (DISignal *signal) +{ + return signal->args; +} + +GList * +di_signal_get_annotations (DISignal *signal) +{ + return signal->annotations; +} + +const gchar * +di_signal_get_signature (DISignal *signal) +{ + return signal->signature; +} + + +const gchar * +di_property_get_name (DIProperty *property) +{ + return property->name; +} + +DIType * +di_property_get_type (DIProperty *property) +{ + return property->type; +} + +GList * +di_property_get_annotations (DIProperty *property) +{ + return property->annotations; +} + +const gchar * +di_property_get_signature (DIProperty *property) +{ + return property->signature; +} + + +const gchar * +di_interface_get_name (DIInterface *interface) +{ + return interface->name; +} + +GList * +di_interface_get_methods (DIInterface *interface) +{ + return interface->methods; +} + +GList * +di_interface_get_signals (DIInterface *interface) +{ + return interface->signals; +} + +GList * +di_interface_get_properties (DIInterface *interface) +{ + return interface->properties; +} + +GList * +di_interface_get_annotations (DIInterface *interface) +{ + return interface->annotations; +} + + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar * +di_struct_member_get_name (DIStructMember *struct_member) +{ + return struct_member->name; +} + +DIType * +di_struct_member_get_type (DIStructMember *struct_member) +{ + return struct_member->type; +} + +GList * +di_struct_member_get_annotations (DIStructMember *struct_member) +{ + return struct_member->annotations; +} + + +const gchar * +di_struct_get_name (DIStruct *struct_) +{ + return struct_->name; +} + +GList * +di_struct_get_members (DIStruct *struct_) +{ + return struct_->members; +} + +GList * +di_struct_get_annotations (DIStruct *struct_) +{ + return struct_->annotations; +} + +const gchar * +di_struct_get_signature (DIStruct *struct_) +{ + return struct_->signature; +} + + +const gchar * +di_dynamic_struct_get_name (DIDynamicStruct *dynamic_struct) +{ + return dynamic_struct->name; +} + +GList * +di_dynamic_struct_get_members (DIDynamicStruct *dynamic_struct) +{ + return dynamic_struct->members; +} + +GList * +di_dynamic_struct_get_annotations (DIDynamicStruct *dynamic_struct) +{ + return dynamic_struct->annotations; +} + +const gchar * +di_dynamic_struct_get_signature (DIDynamicStruct *dynamic_struct) +{ + return "(sa{sv})"; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar * +di_enum_member_get_name (DIEnumMember *enum_member) +{ + return enum_member->name; +} + +guint +di_enum_member_get_value (DIEnumMember *enum_member) +{ + return enum_member->value; +} + +gboolean +di_enum_member_get_unset (DIEnumMember *enum_member) +{ + return enum_member->unset; +} + +GList * +di_enum_member_get_annotations (DIEnumMember *enum_member) +{ + return enum_member->annotations; +} + + +const gchar * +di_enum_get_name (DIEnum *enum_) +{ + return enum_->name; +} + +GList * +di_enum_get_members (DIEnum *enum_) +{ + return enum_->members; +} + +GList * +di_enum_get_annotations (DIEnum *enum_) +{ + return enum_->annotations; +} + + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar * +di_error_member_get_name (DIErrorMember *error_member) +{ + return error_member->name; +} + +GList * +di_error_member_get_annotations (DIErrorMember *error_member) +{ + return error_member->annotations; +} + + +const gchar * +di_error_domain_get_name (DIErrorDomain *error_domain) +{ + return error_domain->name; +} + +GList * +di_error_domain_get_members (DIErrorDomain *error_domain) +{ + return error_domain->members; +} + +GList * +di_error_domain_get_annotations (DIErrorDomain *error_domain) +{ + return error_domain->annotations; +} + + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar * +di_namespace_get_name (DINamespace *namespace) +{ + return namespace->name; +} + +GList * +di_namespace_get_interfaces (DINamespace *namespace) +{ + return namespace->interfaces; +} + +GList * +di_namespace_get_structs (DINamespace *namespace) +{ + return namespace->structs; +} + +GList * +di_namespace_get_dynamic_structs (DINamespace *namespace) +{ + return namespace->dynamic_structs; +} + +GList * +di_namespace_get_enums (DINamespace *namespace) +{ + return namespace->enums; +} + +GList * +di_namespace_get_error_domains (DINamespace *namespace) +{ + return namespace->error_domains; +} + +GList * +di_namespace_get_annotations (DINamespace *namespace) +{ + return namespace->annotations; +} + + +/* ---------------------------------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------------------------------- */ + +void +di_annotation_free (DIAnnotation *annotation) +{ +} + +void +di_type_free (DIType *type) +{ +} + +void +di_arg_free (DIArg *arg) +{ +} + +void +di_signal_free (DISignal *signal) +{ +} + +void +di_method_free (DIMethod *method) +{ +} + +void +di_property_free (DIProperty *property) +{ +} + +void +di_interface_free (DIInterface *interface) +{ +} + +void +di_struct_member_free (DIStructMember *struct_member) +{ +} + +void +di_struct_free (DIStruct *struct_) +{ +} + +void +di_dynamic_struct_free (DIDynamicStruct *dynamic_struct) +{ +} + +void +di_enum_member_free (DIEnumMember *enum_member) +{ +} + +void +di_enum_free (DIEnum *enum_) +{ +} + +void +di_error_member_free (DIErrorMember *error_member) +{ +} + +void +di_error_domain_free (DIErrorDomain *error_domain) +{ +} + +void +di_namespace_free (DINamespace *namespace) +{ +} + +/* ---------------------------------------------------------------------------------------------------- */ + +DIAnnotation *di_annotation_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + gchar *value) +{ + DIAnnotation *ret; + ret = g_new0 (DIAnnotation, 1); + ret->base.type = DI_BASE_TYPE_ANNOTATION; + ret->base.decl_filename = decl_filename; + ret->base.decl_lineno = decl_lineno; + ret->name = name; + ret->value = value; + return ret; +} + +DIType * +di_type_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *inner_types) +{ + DIType *ret; + ret = g_new0 (DIType, 1); + ret->base.type = DI_BASE_TYPE_TYPE; + ret->base.decl_filename = decl_filename; + ret->base.decl_lineno = decl_lineno; + ret->name = name; + ret->inner_types = inner_types; + return ret; +} + +DIArg * +di_arg_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + DIType *type, + DIArgDirection direction, + GList *annotations) +{ + DIArg *ret; + ret = g_new0 (DIArg, 1); + ret->base.type = DI_BASE_TYPE_ARG; + ret->base.decl_filename = decl_filename; + ret->base.decl_lineno = decl_lineno; + ret->name = name; + ret->type = type; + ret->direction = direction; + ret->annotations = annotations; + return ret; +} + +DIMethod * +di_method_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *args, + GList *annotations) +{ + DIMethod *ret; + ret = g_new0 (DIMethod, 1); + ret->base.type = DI_BASE_TYPE_METHOD; + ret->base.decl_filename = decl_filename; + ret->base.decl_lineno = decl_lineno; + ret->name = name; + ret->args = args; + ret->annotations = annotations; + return ret; +} + +DISignal * +di_signal_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *args, + GList *annotations) +{ + DISignal *ret; + ret = g_new0 (DISignal, 1); + ret->base.type = DI_BASE_TYPE_SIGNAL; + ret->base.decl_filename = decl_filename; + ret->base.decl_lineno = decl_lineno; + ret->name = name; + ret->args = args; + ret->annotations = annotations; + return ret; +} + +DIProperty * +di_property_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + DIType *type, + DIPropertyFlags flags, + GList *annotations) +{ + DIProperty *ret; + ret = g_new0 (DIProperty, 1); + ret->base.type = DI_BASE_TYPE_PROPERTY; + ret->base.decl_filename = decl_filename; + ret->base.decl_lineno = decl_lineno; + ret->name = name; + ret->type = type; + ret->flags = flags; + ret->annotations = annotations; + return ret; +} + +DIInterface * +di_interface_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *methods, + GList *signals, + GList *properties, + GList *annotations) +{ + DIInterface *ret; + ret = g_new0 (DIInterface, 1); + ret->base.type = DI_BASE_TYPE_INTERFACE; + ret->base.decl_filename = decl_filename; + ret->base.decl_lineno = decl_lineno; + ret->name = name; + ret->methods = methods; + ret->signals = signals; + ret->properties = properties; + ret->annotations = annotations; + return ret; +} + +DIStructMember * +di_struct_member_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + DIType *type, + GList *annotations) +{ + DIStructMember *ret; + ret = g_new0 (DIStructMember, 1); + ret->base.type = DI_BASE_TYPE_STRUCT_MEMBER; + ret->base.decl_filename = decl_filename; + ret->base.decl_lineno = decl_lineno; + ret->name = name; + ret->type = type; + ret->annotations = annotations; + return ret; +} + +DIStruct * +di_struct_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *members, + GList *annotations) +{ + DIStruct *ret; + ret = g_new0 (DIStruct, 1); + ret->base.type = DI_BASE_TYPE_STRUCT; + ret->base.decl_filename = decl_filename; + ret->base.decl_lineno = decl_lineno; + ret->name = name; + ret->members = members; + ret->annotations = annotations; + return ret; +} + +DIDynamicStruct * +di_dynamic_struct_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *members, + GList *annotations) +{ + DIDynamicStruct *ret; + ret = g_new0 (DIDynamicStruct, 1); + ret->base.type = DI_BASE_TYPE_DYNAMIC_STRUCT; + ret->base.decl_filename = decl_filename; + ret->base.decl_lineno = decl_lineno; + ret->name = name; + ret->members = members; + ret->annotations = annotations; + return ret; +} + +DIEnumMember * +di_enum_member_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + guint32 value, + gboolean unset, + GList *annotations) +{ + DIEnumMember *ret; + ret = g_new0 (DIEnumMember, 1); + ret->base.type = DI_BASE_TYPE_ENUM_MEMBER; + ret->base.decl_filename = decl_filename; + ret->base.decl_lineno = decl_lineno; + ret->name = name; + ret->value = value; + ret->unset = unset; + ret->annotations = annotations; + return ret; +} + +DIEnum * +di_enum_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *members, + GList *annotations) +{ + DIEnum *ret; + ret = g_new0 (DIEnum, 1); + ret->base.type = DI_BASE_TYPE_ENUM; + ret->base.decl_filename = decl_filename; + ret->base.decl_lineno = decl_lineno; + ret->name = name; + ret->members = members; + ret->annotations = annotations; + return ret; +} + +DIErrorMember * +di_error_member_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *annotations) +{ + DIErrorMember *ret; + ret = g_new0 (DIErrorMember, 1); + ret->base.type = DI_BASE_TYPE_ERROR_MEMBER; + ret->base.decl_filename = decl_filename; + ret->base.decl_lineno = decl_lineno; + ret->name = name; + ret->annotations = annotations; + return ret; +} + +DIErrorDomain * +di_error_domain_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *members, + GList *annotations) +{ + DIErrorDomain *ret; + ret = g_new0 (DIErrorDomain, 1); + ret->base.type = DI_BASE_TYPE_ERROR_DOMAIN; + ret->base.decl_filename = decl_filename; + ret->base.decl_lineno = decl_lineno; + ret->name = name; + ret->members = members; + ret->annotations = annotations; + return ret; +} + +DINamespace * +di_namespace_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *interfaces, + GList *structs, + GList *dynamic_structs, + GList *enums, + GList *error_domains, + GList *annotations) +{ + DINamespace *ret; + ret = g_new0 (DINamespace, 1); + ret->base.type = DI_BASE_TYPE_NAMESPACE; + ret->base.decl_filename = decl_filename; + ret->base.decl_lineno = decl_lineno; + ret->name = name; + ret->interfaces = interfaces; + ret->structs = structs; + ret->dynamic_structs = dynamic_structs; + ret->enums = enums; + ret->error_domains = error_domains; + ret->annotations = annotations; + return ret; +} + + +/* ---------------------------------------------------------------------------------------------------- */ + +void +di_annotation_print (DIAnnotation *annotation, guint indent) +{ + g_print ("%*s@%s", indent, "", annotation->name); + if (annotation->value != NULL) + { + g_print (" (\"%s\")", annotation->value); + } + g_print ("\n"); +} + +void +di_type_print (DIType *type, guint indent) +{ + g_print ("%*s%s", indent, "", + type->fully_qualified_name != NULL ? type->fully_qualified_name : type->name); + if (type->inner_types != NULL) + { + GList *l; + g_print ("<"); + for (l = type->inner_types; l != NULL; l = l->next) + { + if (l != type->inner_types) + g_print (","); + di_type_print (l->data, 0); + } + g_print (">"); + } +} + +void +di_arg_print (DIArg *arg, guint indent) +{ + const gchar *direction; + GList *l; + + switch (arg->direction) + { + case DI_ARG_DIRECTION_NONE: + direction = ""; + break; + case DI_ARG_DIRECTION_IN: + direction = "IN "; + break; + case DI_ARG_DIRECTION_OUT: + direction = "OUT "; + break; + } + for (l = arg->annotations; l != NULL; l = l->next) + di_annotation_print ((DIAnnotation *) l->data, indent); + g_print ("%*s%s", indent, "", direction); + di_type_print (arg->type, 0); + g_print (" %s", arg->name); +} + +void +di_signal_print (DISignal *signal, guint indent) +{ + GList *l; + guint arg_indent; + + arg_indent = indent + 7 + strlen (signal->name) + 2; + + for (l = signal->annotations; l != NULL; l = l->next) + di_annotation_print ((DIAnnotation *) l->data, indent); + g_print ("%*s# signature=%s\n", indent, "", signal->signature); + g_print ("%*ssignal %s (", indent, "", signal->name); + for (l = signal->args; l != NULL; l = l->next) + { + if (((DIArg *) l->data)->annotations != NULL) + di_arg_print (l->data, arg_indent); + else + di_arg_print (l->data, (l == signal->args ? 0 : arg_indent)); + if (l->next != NULL) + g_print (",\n"); + } + g_print (");\n"); +} + +void +di_method_print (DIMethod *method, guint indent) +{ + GList *l; + guint arg_indent; + + arg_indent = indent + 7 + strlen (method->name) + 2; + + for (l = method->annotations; l != NULL; l = l->next) + di_annotation_print ((DIAnnotation *) l->data, indent); + g_print ("%*s# in_signature=%s out_signature=%s\n", + indent, "", + method->in_signature, + method->out_signature); + g_print ("%*smethod %s (", indent, "", + method->name); + for (l = method->args; l != NULL; l = l->next) + { + if (((DIArg *) l->data)->annotations != NULL) + di_arg_print (l->data, arg_indent); + else + di_arg_print (l->data, (l == method->args ? 0 : arg_indent)); + if (l->next != NULL) + g_print (",\n"); + } + g_print (");\n"); +} + +void +di_property_print (DIProperty *property, guint indent) +{ + const gchar *flags_str; + GList *l; + + switch (property->flags) + { + case DI_PROPERTY_FLAGS_READABLE: + flags_str = "readonly"; + break; + case DI_PROPERTY_FLAGS_WRITABLE: + flags_str = "writeonly"; + break; + case DI_PROPERTY_FLAGS_READABLE | DI_PROPERTY_FLAGS_WRITABLE: + flags_str = "readwrite"; + break; + default: + g_assert_not_reached (); + break; + } + for (l = property->annotations; l != NULL; l = l->next) + di_annotation_print ((DIAnnotation *) l->data, indent); + g_print ("%*s# signature=%s\n", indent, "", property->signature); + g_print ("%*s%s property ", + indent, "", + flags_str); + di_type_print (property->type, 0); + g_print (" %s;\n", property->name); +} + +void +di_interface_print (DIInterface *interface, guint indent) +{ + GList *l; + for (l = interface->annotations; l != NULL; l = l->next) + di_annotation_print ((DIAnnotation *) l->data, indent); + g_print ("%*sinterface %s {\n", indent, "", interface->name); + for (l = interface->methods; l != NULL; l = l->next) + di_method_print (l->data, indent + 2); + for (l = interface->signals; l != NULL; l = l->next) + di_signal_print (l->data, indent + 2); + for (l = interface->properties; l != NULL; l = l->next) + di_property_print (l->data, indent + 2); + g_print ("%*s};\n", indent, ""); +} + +void +di_struct_member_print (DIStructMember *struct_member, guint indent) +{ + GList *l; + + for (l = struct_member->annotations; l != NULL; l = l->next) + di_annotation_print ((DIAnnotation *) l->data, indent); + g_print ("%*s", indent, ""); + di_type_print (struct_member->type, 0); + g_print (" %s;\n", struct_member->name); +} + +void +di_struct_print (DIStruct *struct_, guint indent) +{ + GList *l; + + for (l = struct_->annotations; l != NULL; l = l->next) + di_annotation_print ((DIAnnotation *) l->data, indent); + g_print ("%*s# signature=%s\n", indent, "", struct_->signature); + g_print ("%*sstruct %s {\n", indent, "", struct_->name); + for (l = struct_->members; l != NULL; l = l->next) + di_struct_member_print (l->data, indent + 2); + g_print ("%*s};\n", indent, ""); +} + +void +di_dynamic_struct_print (DIDynamicStruct *dynamic_struct, guint indent) +{ + GList *l; + + for (l = dynamic_struct->annotations; l != NULL; l = l->next) + di_annotation_print ((DIAnnotation *) l->data, indent); + g_print ("%*sdynamic_struct %s {\n", indent, "", dynamic_struct->name); + for (l = dynamic_struct->members; l != NULL; l = l->next) + di_struct_member_print (l->data, indent + 2); + g_print ("%*s};\n", indent, ""); +} + +void +di_enum_member_print (DIEnumMember *enum_member, guint indent) +{ + GList *l; + + for (l = enum_member->annotations; l != NULL; l = l->next) + di_annotation_print ((DIAnnotation *) l->data, indent); + if (enum_member->unset) + { + g_print ("%*s%s = 0x%08x (unset),\n", indent, "", + enum_member->name, + enum_member->value); + } + else + { + g_print ("%*s%s = 0x%08x,\n", indent, "", + enum_member->name, + enum_member->value); + } +} + +void +di_enum_print (DIEnum *enum_, guint indent) +{ + GList *l; + + for (l = enum_->annotations; l != NULL; l = l->next) + di_annotation_print ((DIAnnotation *) l->data, indent); + g_print ("%*senum %s {\n", indent, "", enum_->name); + for (l = enum_->members; l != NULL; l = l->next) + di_enum_member_print (l->data, indent + 2); + g_print ("%*s};\n", indent, ""); +} + +void +di_error_member_print (DIErrorMember *error_member, guint indent) +{ + GList *l; + + for (l = error_member->annotations; l != NULL; l = l->next) + di_annotation_print ((DIAnnotation *) l->data, indent); + g_print ("%*s%s,\n", indent, "", + error_member->name); +} + +void +di_error_domain_print (DIErrorDomain *error_domain, guint indent) +{ + GList *l; + + for (l = error_domain->annotations; l != NULL; l = l->next) + di_annotation_print ((DIAnnotation *) l->data, indent); + g_print ("%*serror_domain %s {\n", indent, "", error_domain->name); + for (l = error_domain->members; l != NULL; l = l->next) + di_error_member_print (l->data, indent + 2); + g_print ("%*s};\n", indent, ""); +} + +void +di_namespace_print (DINamespace *namespace, guint indent) +{ + GList *l; + + for (l = namespace->annotations; l != NULL; l = l->next) + di_annotation_print ((DIAnnotation *) l->data, indent); + g_print ("%*snamespace %s {\n", indent, "", namespace->name); + for (l = namespace->structs; l != NULL; l = l->next) + di_struct_print (l->data, indent + 2); + for (l = namespace->dynamic_structs; l != NULL; l = l->next) + di_dynamic_struct_print (l->data, indent + 2); + for (l = namespace->enums; l != NULL; l = l->next) + di_enum_print (l->data, indent + 2); + for (l = namespace->error_domains; l != NULL; l = l->next) + di_error_domain_print (l->data, indent + 2); + for (l = namespace->interfaces; l != NULL; l = l->next) + di_interface_print (l->data, indent + 2); + g_print ("%*s};\n", indent, ""); +} + + +/* ---------------------------------------------------------------------------------------------------- */ +static void +ensure_method (DIParser *parser, + DIMethod *method) +{ + GList *l, *ll; + for (l = method->args; l != NULL; l = l->next) + { + DIArg *i = l->data; + for (ll = method->args; ll != l; ll = ll->next) + { + DIArg *other = ll->data; + if (g_strcmp0 (other->name, i->name) == 0) + { + parser->errors = g_list_append (parser->errors, + g_strdup_printf ("%s:%d: Method %s already has an argument named %s", + method->base.decl_filename, + method->base.decl_lineno, + method->name, + i->name)); + } + } + } +} + +static void +ensure_signal (DIParser *parser, + DISignal *signal) +{ + GList *l, *ll; + for (l = signal->args; l != NULL; l = l->next) + { + DIArg *i = l->data; + for (ll = signal->args; ll != l; ll = ll->next) + { + DIArg *other = ll->data; + if (g_strcmp0 (other->name, i->name) == 0) + { + parser->errors = g_list_append (parser->errors, + g_strdup_printf ("%s:%d: Signal %s already has an argument named %s", + signal->base.decl_filename, + signal->base.decl_lineno, + signal->name, + i->name)); + } + } + } +} + +static const gchar * +di_base_type_to_string (DIBaseType type) +{ + const gchar *ret; + ret = NULL; + switch (type) + { + case DI_BASE_TYPE_METHOD: ret = "method"; break; + case DI_BASE_TYPE_SIGNAL: ret = "signal"; break; + case DI_BASE_TYPE_PROPERTY: ret = "property"; break; + case DI_BASE_TYPE_INTERFACE: ret = "interface"; break; + case DI_BASE_TYPE_STRUCT_MEMBER: ret = "struct_member"; break; + case DI_BASE_TYPE_STRUCT: ret = "struct"; break; + case DI_BASE_TYPE_DYNAMIC_STRUCT: ret = "dynstruct"; break; + case DI_BASE_TYPE_ENUM_MEMBER: ret = "enum_member"; break; + case DI_BASE_TYPE_ENUM: ret = "enum"; break; + case DI_BASE_TYPE_ERROR_MEMBER: ret = "error_member"; break; + case DI_BASE_TYPE_ERROR_DOMAIN: ret = "error_domain"; break; + case DI_BASE_TYPE_NAMESPACE: ret = "namespace"; break; + default: + g_assert_not_reached (); + break; + } + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static gboolean +insert_and_check (DIParser *parser, + DIBase *symbol, + const gchar *fully_qualified_name) +{ + DIBase *base; + gboolean ret; + + ret = FALSE; + + base = (DIBase *) g_hash_table_lookup (parser->symbol_table, fully_qualified_name); + if (base != NULL) + { + parser->errors = g_list_append (parser->errors, + g_strdup_printf ("%s:%d: error: name %s for %s is already in use", + symbol->decl_filename, + symbol->decl_lineno, + fully_qualified_name, + di_base_type_to_string (symbol->type))); + parser->errors = g_list_append (parser->errors, + g_strdup_printf ("%s:%d: error: name %s previously declared as a %s", + base->decl_filename, + base->decl_lineno, + fully_qualified_name, + di_base_type_to_string (base->type))); + goto out; + } + + g_hash_table_insert (parser->symbol_table, + (gpointer) fully_qualified_name, + symbol); + + ret = TRUE; + + out: + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +type_compute_fully_qualified_name (DIParser *parser, + DIType *type, + DINamespace *namespace) +{ + type->fully_qualified_name = NULL; + if (get_typecode_for_primitive_type (type->name) != -1) + { + /* do nothing for primitive types */ + g_assert (type->inner_types == NULL); + } + else if (g_strcmp0 (type->name, "array") == 0) + { + /* recurse into arrays */ + g_assert (g_list_length (type->inner_types) == 1); + type_compute_fully_qualified_name (parser, + (DIType *) type->inner_types->data, + namespace); + } + else if (g_strcmp0 (type->name, "dict") == 0) + { + /* recurse into dicts */ + g_assert (g_list_length (type->inner_types) == 2); + type_compute_fully_qualified_name (parser, + (DIType *) type->inner_types->data, + namespace); + type_compute_fully_qualified_name (parser, + (DIType *) type->inner_types->next->data, + namespace); + } + else if (strstr (type->name, ".") != NULL) + { + /* if name is already qualified, use that */ + g_assert (type->inner_types == NULL); + type->fully_qualified_name = g_strdup (type->name); + } + else + { + /* otherwise prepend the given namespace */ + g_assert (type->inner_types == NULL); + type->fully_qualified_name = g_strdup_printf ("%s.%s", + namespace->name, + type->name); + } +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +build_symbol_table (DIParser *parser) +{ + GList *l, *ll, *lll, *llll; + + parser->symbol_table = g_hash_table_new (g_str_hash, g_str_equal); + /* for all namespaces */ + for (l = parser->namespaces; l != NULL; l = l->next) + { + DINamespace *namespace = l->data; + + if (!insert_and_check (parser, (DIBase *) namespace, namespace->name)) + continue; + + /* for all interfaces */ + for (ll = namespace->interfaces; ll != NULL; ll = ll->next) + { + DIInterface *interface = ll->data; + interface->fully_qualified_name = g_strdup_printf ("%s.%s", + namespace->name, + interface->name); + if (!insert_and_check (parser, (DIBase *) interface, interface->fully_qualified_name)) + continue; + + /* for all methods */ + for (lll = interface->methods; lll != NULL; lll = lll->next) + { + DIMethod *method = lll->data; + method->fully_qualified_name = g_strdup_printf ("%s.%s", + interface->fully_qualified_name, + method->name); + insert_and_check (parser, (DIBase *) method, method->fully_qualified_name); + + /* check for collision for arg names */ + ensure_method (parser, method); + + /* make type names for all args fully qualified */ + for (llll = method->args; llll != NULL; llll = llll->next) + { + DIArg *arg = llll->data; + type_compute_fully_qualified_name (parser, + arg->type, + namespace); + } + } + + /* for all signals */ + for (lll = interface->signals; lll != NULL; lll = lll->next) + { + DISignal *signal = lll->data; + signal->fully_qualified_name = g_strdup_printf ("%s.%s", + interface->fully_qualified_name, + signal->name); + insert_and_check (parser, (DIBase *) signal, signal->fully_qualified_name); + /* check for collision for arg names */ + ensure_signal (parser, signal); + + /* make type names for all args fully qualified */ + for (llll = signal->args; llll != NULL; llll = llll->next) + { + DIArg *arg = llll->data; + type_compute_fully_qualified_name (parser, + arg->type, + namespace); + } + } + + /* for all properties */ + for (lll = interface->properties; lll != NULL; lll = lll->next) + { + DIProperty *property = lll->data; + property->fully_qualified_name = g_strdup_printf ("%s.%s", + interface->fully_qualified_name, + property->name); + insert_and_check (parser, (DIBase *) property, property->fully_qualified_name); + + /* make type name fully qualified */ + type_compute_fully_qualified_name (parser, + property->type, + namespace); + } + } + + /* for all structs */ + for (ll = namespace->structs; ll != NULL; ll = ll->next) + { + DIStruct *struct_ = ll->data; + struct_->fully_qualified_name = g_strdup_printf ("%s.%s", + namespace->name, + struct_->name); + insert_and_check (parser, (DIBase *) struct_, struct_->fully_qualified_name); + for (lll = struct_->members; lll != NULL; lll = lll->next) + { + DIStructMember *struct_member = lll->data; + + /* make type name fully qualified */ + type_compute_fully_qualified_name (parser, + struct_member->type, + namespace); + } + } + + /* for all dynamic structs */ + for (ll = namespace->dynamic_structs; ll != NULL; ll = ll->next) + { + DIDynamicStruct *dynamic_struct = ll->data; + dynamic_struct->fully_qualified_name = g_strdup_printf ("%s.%s", + namespace->name, + dynamic_struct->name); + insert_and_check (parser, (DIBase *) dynamic_struct, dynamic_struct->fully_qualified_name); + for (lll = dynamic_struct->members; lll != NULL; lll = lll->next) + { + DIStructMember *struct_member = lll->data; + + /* make type name fully qualified */ + type_compute_fully_qualified_name (parser, + struct_member->type, + namespace); + } + } + + /* for all enums */ + for (ll = namespace->enums; ll != NULL; ll = ll->next) + { + DIEnum *enum_ = ll->data; + enum_->fully_qualified_name = g_strdup_printf ("%s.%s", + namespace->name, + enum_->name); + insert_and_check (parser, (DIBase *) enum_, enum_->fully_qualified_name); + for (lll = enum_->members; lll != NULL; lll = lll->next) + { + DIEnumMember *enum_member = lll->data; + enum_member->fully_qualified_name = g_strdup_printf ("%s.%s", + enum_->fully_qualified_name, + enum_member->name); + insert_and_check (parser, (DIBase *) enum_member, enum_member->fully_qualified_name); + } + } + + /* for all errors */ + for (ll = namespace->error_domains; ll != NULL; ll = ll->next) + { + DIErrorDomain *error_domain = ll->data; + error_domain->fully_qualified_name = g_strdup_printf ("%s.%s", + namespace->name, + error_domain->name); + insert_and_check (parser, (DIBase *) error_domain, error_domain->fully_qualified_name); + for (lll = error_domain->members; lll != NULL; lll = lll->next) + { + DIErrorMember *error_member = lll->data; + error_member->fully_qualified_name = g_strdup_printf ("%s.%s", + error_domain->fully_qualified_name, + error_member->name); + insert_and_check (parser, (DIBase *) error_member, error_member->fully_qualified_name); + } + } + } /* for all namespaces */ +} + +/* ---------------------------------------------------------------------------------------------------- */ + +DIBase * +di_parser_lookup_symbol (DIParser *parser, + const gchar *fully_qualified_name) +{ + DIBase *base; + base = (DIBase *) g_hash_table_lookup (parser->symbol_table, fully_qualified_name); + return base; +} + +static void +visit_type (DIParser *parser, + DIType *type, + DIBase *referenced_in, + guint recursion_level) +{ + GString *s; + gint typecode; + + if (recursion_level >= 128) + { + parser->errors = g_list_append (parser->errors, + g_strdup_printf ("%s:%d: error: type recursion level reached", + referenced_in->decl_filename, + referenced_in->decl_lineno)); + return; + } + + if (type->signature != NULL) + return; + + s = g_string_new (NULL); + + typecode = get_typecode_for_primitive_type (type->name); + if (typecode != -1) + { + /* primitive type */ + g_string_append_c (s, typecode); + } + else if (g_strcmp0 (type->name, "array") == 0) + { + /* array */ + g_assert (g_list_length (type->inner_types) == 1); + visit_type (parser, + (DIType *) type->inner_types->data, + referenced_in, + recursion_level + 1); + g_string_append_c (s, 'a'); + g_string_append (s, ((DIType *) type->inner_types->data)->signature); + } + else if (g_strcmp0 (type->name, "dict") == 0) + { + /* dict */ + g_assert (g_list_length (type->inner_types) == 2); + visit_type (parser, + (DIType *) type->inner_types->data, + referenced_in, + recursion_level + 1); + visit_type (parser, + (DIType *) type->inner_types->next->data, + referenced_in, + recursion_level + 1); + g_string_append (s, "a{"); + g_string_append (s, ((DIType *) type->inner_types->data)->signature); + g_string_append (s, ((DIType *) type->inner_types->next->data)->signature); + g_string_append_c (s, '}'); + } + else + { + DIBase *base; + + /* can either reference a struct or an enum */ + base = di_parser_lookup_symbol (parser, type->fully_qualified_name); + if (base == NULL) + { + parser->errors = g_list_append (parser->errors, + g_strdup_printf ("%s:%d: error: cannot resolve type %s", + referenced_in->decl_filename, + referenced_in->decl_lineno, + type->fully_qualified_name)); + } + else if (base->type == DI_BASE_TYPE_STRUCT) + { + GList *l; + DIStruct *struct_; + DIStructMember *struct_member; + + g_string_append_c (s, '('); + struct_ = (DIStruct *) base; + for (l = struct_->members; l != NULL; l = l->next) + { + struct_member = (DIStructMember *) l->data; + visit_type (parser, + struct_member->type, + base, + recursion_level + 1); + g_string_append (s, struct_member->type->signature); + } + g_string_append_c (s, ')'); + } + else if (base->type == DI_BASE_TYPE_DYNAMIC_STRUCT) + { + GList *l; + DIDynamicStruct *dynamic_struct; + DIStructMember *struct_member; + + dynamic_struct = (DIDynamicStruct *) base; + for (l = dynamic_struct->members; l != NULL; l = l->next) + { + struct_member = (DIStructMember *) l->data; + visit_type (parser, + struct_member->type, + base, + recursion_level + 1); + } + /* dynamic structs are always marshalled as a (string, dict:string->variant) structure */ + g_string_append (s, "(sa{sv})"); + } + else if (base->type == DI_BASE_TYPE_ENUM) + { + /* we use uint32 for enums */ + g_string_append_c (s, 'u'); + } + else + { + parser->errors = g_list_append (parser->errors, + g_strdup_printf ("%s:%d: error: expected a struct or enum for %s " + "but got a %s", + referenced_in->decl_filename, + referenced_in->decl_lineno, + type->fully_qualified_name, + di_base_type_to_string (base->type))); + } + } + + type->signature = g_string_free (s, FALSE); +#if 0 + g_debug ("signature %s for %s %s %s", + type->signature, + type->name, + di_base_type_to_string (referenced_in->type), + referenced_in->fully_qualified_name); +#endif +} + +static void +check_types (DIParser *parser) +{ + GHashTableIter iter; + const gchar *fqn; + DIBase *base; + GList *l; + GString *s1; + GString *s2; + DIArg *arg; + DIMethod *method; + DISignal *signal; + DIProperty *property; + DIStruct *struct_; + DIDynamicStruct *dynamic_struct; + DIStructMember *struct_member; + + /* here we ensure that all the user supplied types referenced actually exists. We also + * compute the signature field for each of them. + */ + + g_hash_table_iter_init (&iter, parser->symbol_table); + while (g_hash_table_iter_next (&iter, (gpointer) &fqn, (gpointer) &base)) + { + switch (base->type) + { + case DI_BASE_TYPE_METHOD: + s1 = g_string_new (NULL); + s2 = g_string_new (NULL); + method = (DIMethod *) base; + for (l = method->args; l != NULL; l = l->next) + { + arg = l->data; + visit_type (parser, arg->type, base, 0); + if (arg->direction == DI_ARG_DIRECTION_IN) + g_string_append (s1, arg->type->signature); + else + g_string_append (s2, arg->type->signature); + } + method->in_signature = g_string_free (s1, FALSE); + method->out_signature = g_string_free (s2, FALSE); + break; + + case DI_BASE_TYPE_SIGNAL: + s1 = g_string_new (NULL); + signal = (DISignal *) base; + for (l = signal->args; l != NULL; l = l->next) + { + arg = l->data; + visit_type (parser, arg->type, base, 0); + g_string_append (s1, arg->type->signature); + } + signal->signature = g_string_free (s1, FALSE); + break; + + case DI_BASE_TYPE_PROPERTY: + property = (DIProperty *) base; + visit_type (parser, property->type, base, 0); + property->signature = g_strdup (property->type->signature); + break; + + case DI_BASE_TYPE_STRUCT: + s1 = g_string_new ("("); + struct_ = (DIStruct *) base; + for (l = struct_->members; l != NULL; l = l->next) + { + struct_member = (DIStructMember *) l->data; + visit_type (parser, struct_member->type, base, 0); + g_string_append (s1, struct_member->type->signature); + } + g_string_append_c (s1, ')'); + struct_->signature = g_string_free (s1, FALSE); + break; + + case DI_BASE_TYPE_DYNAMIC_STRUCT: + dynamic_struct = (DIDynamicStruct *) base; + for (l = dynamic_struct->members; l != NULL; l = l->next) + { + struct_member = (DIStructMember *) l->data; + visit_type (parser, struct_member->type, base, 0); + } + break; + + default: + /* ignore symbols that don't correspond to signatures */ + break; + } + } +} + +/* ---------------------------------------------------------------------------------------------------- */ + +DIParser * +di_parser_new (const gchar *path) +{ + DIParser *parser; + gchar *s; + + parser = g_new0 (DIParser, 1); + + yyin = fopen (path, "rt"); + if (yyin == NULL) + { + s = g_strdup_printf ("Error opening file %s: %m", path); + parser->errors = g_list_append (parser->errors, s); + goto out; + } + + parser->path_to_current_file = g_strdup (path); + + /* this covers lexical and syntactical analysis */ + yyparse (parser); + fclose (yyin); + + /* bail if we have errors at this point */ + if (parser->errors != NULL) + goto out; + + /* Now for semantical analysis... */ + + /* First build the symbol table - this is basically a mapping from the fully + * qualified name into a DIBase pointer. It contain the following objects + * + * o namespaces + * o interfaces + * - methods + * - signals + * - properties + * o structs + * - struct members + * o dynamic structs + * - struct members + * o enumerations + * - enum members + * o error domains + * - error members + * + * with user API being di_parser_lookup_symbol(). The user can then safely + * cast to the appropriate type by inspecting the type of the returned object. + * + * While doing this, also compute fully-qualified names and output errors + * if there are collisions. + */ + build_symbol_table (parser); + + /* bail if we have errors at this point */ + if (parser->errors != NULL) + goto out; + + /* With the symbol table in place, we can resolve and check types and + * also compute the D-Bus signature of all types, structs, methods, + * signals and properties. + */ + check_types (parser); + + out: + return parser; +} + +GList * +di_parser_get_namespaces (DIParser *parser) +{ + return parser->namespaces; +} + +GList * +di_parser_get_warnings (DIParser *parser) +{ + return parser->warnings; +} + +GList * +di_parser_get_errors (DIParser *parser) +{ + return parser->errors; +} + +void +di_parser_free (DIParser *parser) +{ + /* TODO */ +} + +/* ---------------------------------------------------------------------------------------------------- */ + +DINamespace * +di_parser_lookup_namespace (DIParser *parser, + const gchar *name) +{ + GList *l; + for (l = parser->namespaces; l != NULL; l = l->next) + { + DINamespace *i = l->data; + if (g_strcmp0 (i->name, name) == 0) + return i; + } + return NULL; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +DIInterface * +di_namespace_lookup_interface (DINamespace *namespace, + const gchar *name) +{ + GList *l; + for (l = namespace->interfaces; l != NULL; l = l->next) + { + DIInterface *interface = l->data; + if (g_strcmp0 (interface->name, name) == 0) + return interface; + } + return NULL; +} + +DIStruct * +di_namespace_lookup_struct (DINamespace *namespace, + const gchar *name) +{ + GList *l; + for (l = namespace->structs; l != NULL; l = l->next) + { + DIStruct *struct_ = l->data; + if (g_strcmp0 (struct_->name, name) == 0) + return struct_; + } + return NULL; +} + +DIDynamicStruct * +di_namespace_lookup_dynamic_struct (DINamespace *namespace, + const gchar *name) +{ + GList *l; + for (l = namespace->dynamic_structs; l != NULL; l = l->next) + { + DIDynamicStruct *dynamic_struct = l->data; + if (g_strcmp0 (dynamic_struct->name, name) == 0) + return dynamic_struct; + } + return NULL; +} + +DIEnum * +di_namespace_lookup_enum (DINamespace *namespace, + const gchar *name) +{ + GList *l; + for (l = namespace->enums; l != NULL; l = l->next) + { + DIEnum *enum_ = l->data; + if (g_strcmp0 (enum_->name, name) == 0) + return enum_; + } + return NULL; +} + +DIErrorDomain * +di_namespace_lookup_error_domain (DINamespace *namespace, + const gchar *name) +{ + GList *l; + for (l = namespace->error_domains; l != NULL; l = l->next) + { + DIErrorDomain *error_domain = l->data; + if (g_strcmp0 (error_domain->name, name) == 0) + return error_domain; + } + return NULL; +} + + +/* ---------------------------------------------------------------------------------------------------- */ + +DIMethod * +di_interface_lookup_method (DIInterface *interface, + const gchar *name) +{ + GList *l; + for (l = interface->methods; l != NULL; l = l->next) + { + DIMethod *method = l->data; + if (g_strcmp0 (method->name, name) == 0) + return method; + } + return NULL; +} + +DISignal * +di_interface_lookup_signal (DIInterface *interface, + const gchar *name) +{ + GList *l; + for (l = interface->signals; l != NULL; l = l->next) + { + DISignal *signal = l->data; + if (g_strcmp0 (signal->name, name) == 0) + return signal; + } + return NULL; +} + +DIProperty * +di_interface_lookup_property (DIInterface *interface, + const gchar *name) +{ + GList *l; + for (l = interface->properties; l != NULL; l = l->next) + { + DIProperty *property = l->data; + if (g_strcmp0 (property->name, name) == 0) + return property; + } + return NULL; +} + +/* ---------------------------------------------------------------------------------------------------- */ diff --git a/src/dbusidl.h b/src/dbusidl.h new file mode 100644 index 0000000..d1e45b2 --- /dev/null +++ b/src/dbusidl.h @@ -0,0 +1,234 @@ +/* Copyright (C) 2009 David Zeuthen <zeuthen@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen <zeuthen@gmail.com> + */ + +#include <glib.h> + +#ifndef __DBUS_IDL_H +#define __DBUS_IDL_H + +#ifndef DBUS_IDL_I_UNDERSTAND_THAT_API_IS_UNSTABLE +#error "The dbus-idl API is unstable You need to define DBUS_IDL_I_UNDERSTAND_THAT_API_IS_UNSTABLE to use this API." +#endif + +G_BEGIN_DECLS + +typedef enum +{ + DI_BASE_TYPE_ANNOTATION, + DI_BASE_TYPE_TYPE, + DI_BASE_TYPE_ARG, + DI_BASE_TYPE_METHOD, + DI_BASE_TYPE_SIGNAL, + DI_BASE_TYPE_PROPERTY, + DI_BASE_TYPE_INTERFACE, + DI_BASE_TYPE_STRUCT_MEMBER, + DI_BASE_TYPE_STRUCT, + DI_BASE_TYPE_DYNAMIC_STRUCT, + DI_BASE_TYPE_ENUM_MEMBER, + DI_BASE_TYPE_ENUM, + DI_BASE_TYPE_ERROR_MEMBER, + DI_BASE_TYPE_ERROR_DOMAIN, + DI_BASE_TYPE_NAMESPACE, +} DIBaseType; + +typedef enum +{ + DI_PROPERTY_FLAGS_NONE = 0, + DI_PROPERTY_FLAGS_READABLE = (1<<0), + DI_PROPERTY_FLAGS_WRITABLE = (1<<1), +} DIPropertyFlags; + +typedef enum +{ + DI_ARG_DIRECTION_NONE, + DI_ARG_DIRECTION_IN, + DI_ARG_DIRECTION_OUT, +} DIArgDirection; + +/* Parser object */ +typedef struct _DIParser DIParser; + +/* The base class for all objects */ +typedef struct _DIBase DIBase; + +/* These objects are all based on DIBase */ +typedef struct _DIAnnotation DIAnnotation; +typedef struct _DIType DIType; +typedef struct _DIArg DIArg; +typedef struct _DIMethod DIMethod; +typedef struct _DISignal DISignal; +typedef struct _DIProperty DIProperty; +typedef struct _DIInterface DIInterface; +typedef struct _DIStructMember DIStructMember; +typedef struct _DIStruct DIStruct; +typedef struct _DIDynamicStruct DIDynamicStruct; +typedef struct _DIEnumMember DIEnumMember; +typedef struct _DIEnum DIEnum; +typedef struct _DIErrorMember DIErrorMember; +typedef struct _DIErrorDomain DIErrorDomain; +typedef struct _DINamespace DINamespace; + +/* ---------------------------------------------------------------------------------------------------- */ + +DIBaseType di_base_get_type (DIBase *base); +const gchar *di_base_get_decl_path (DIBase *base); +guint di_base_get_decl_lineno (DIBase *base); + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar *di_type_get_name (DIType *type); +const gchar *di_type_get_signature (DIType *type); +gint di_type_get_typecode (DIType *type); +GList *di_type_get_inner_types (DIType *type); + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar *di_arg_get_name (DIArg *arg); +DIType *di_arg_get_type (DIArg *arg); +DIArgDirection di_arg_get_direction (DIArg *arg); +GList *di_arg_get_annotations (DIArg *arg); + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar *di_method_get_name (DIMethod *method); +const gchar *di_method_get_fully_qualified_name (DIMethod *method); +GList *di_method_get_args (DIMethod *method); +GList *di_method_get_annotations (DIMethod *method); +const gchar *di_method_get_in_signature (DIMethod *method); +const gchar *di_method_get_out_signature (DIMethod *method); + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar *di_signal_get_name (DISignal *signal); +const gchar *di_signal_get_fully_qualified_name (DISignal *signal); +GList *di_signal_get_args (DISignal *signal); +GList *di_signal_get_annotations (DISignal *signal); +const gchar *di_signal_get_signature (DISignal *signal); + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar *di_property_get_name (DIProperty *property); +const gchar *di_property_get_fully_qualified_name (DIProperty *property); +DIType *di_property_get_type (DIProperty *property); +GList *di_property_get_annotations (DIProperty *property); +const gchar *di_property_get_signature (DIProperty *property); + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar *di_interface_get_name (DIInterface *interface); +const gchar *di_interface_get_fully_qualified_name (DIInterface *interface); +GList *di_interface_get_methods (DIInterface *interface); +GList *di_interface_get_signals (DIInterface *interface); +GList *di_interface_get_properties (DIInterface *interface); +GList *di_interface_get_annotations (DIInterface *interface); +DIMethod *di_interface_lookup_method (DIInterface *interface, + const gchar *name); +DISignal *di_interface_lookup_signal (DIInterface *interface, + const gchar *name); +DIProperty *di_interface_lookup_property (DIInterface *interface, + const gchar *name); + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar *di_struct_member_get_name (DIStructMember *struct_member); +DIType *di_struct_member_get_type (DIStructMember *struct_member); +GList *di_struct_member_get_annotations (DIStructMember *struct_member); + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar *di_struct_get_name (DIStruct *struct_); +const gchar *di_struct_get_fully_qualified_name (DIStruct *struct_); +GList *di_struct_get_members (DIStruct *struct_); +GList *di_struct_get_annotations (DIStruct *struct_); +const gchar *di_struct_get_signature (DIStruct *struct_); + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar *di_dynamic_struct_get_name (DIDynamicStruct *dynamic_struct); +const gchar *di_dynamic_get_fully_qualified_name (DIDynamicStruct *dynamic_struct); +GList *di_dynamic_struct_get_members (DIDynamicStruct *dynamic_struct); +GList *di_dynamic_struct_get_annotations (DIDynamicStruct *dynamic_struct); +const gchar *di_dynamic_struct_get_signature (DIDynamicStruct *dynamic_struct); + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar *di_enum_member_get_name (DIEnumMember *enum_member); +const gchar *di_enum_member_get_fully_qualified_name (DIEnumMember *enum_member); +guint di_enum_member_get_value (DIEnumMember *enum_member); +gboolean di_enum_member_get_unset (DIEnumMember *enum_member); +GList *di_enum_member_get_annotations (DIEnumMember *enum_member); + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar *di_enum_get_name (DIEnum *enum_); +const gchar *di_enum_get_fully_qualified_name (DIEnum *enum_); +GList *di_enum_get_members (DIEnum *enum_); +GList *di_enum_get_annotations (DIEnum *enum_); + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar *di_error_member_get_name (DIErrorMember *error_member); +const gchar *di_error_member_get_fully_qualified_name (DIErrorMember *error_member); +GList *di_error_member_get_annotations (DIErrorMember *error_member); + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar *di_error_domain_get_name (DIErrorDomain *error_domain); +const gchar *di_error_domain_get_fully_qualified_name (DIErrorDomain *error_domain); +GList *di_error_domain_get_members (DIErrorDomain *error_domain); +GList *di_error_domain_get_annotations (DIErrorDomain *error_domain); + +/* ---------------------------------------------------------------------------------------------------- */ + +const gchar *di_namespace_get_name (DINamespace *namespace); +GList *di_namespace_get_interfaces (DINamespace *namespace); +GList *di_namespace_get_structs (DINamespace *namespace); +GList *di_namespace_get_dynamic_structs (DINamespace *namespace); +GList *di_namespace_get_enums (DINamespace *namespace); +GList *di_namespace_get_error_domains (DINamespace *namespace); +GList *di_namespace_get_annotations (DINamespace *namespace); +DIInterface *di_namespace_lookup_interface (DINamespace *namespace, + const gchar *name); +DIStruct *di_namespace_lookup_struct (DINamespace *namespace, + const gchar *name); +DIDynamicStruct *di_namespace_lookup_dynamic_struct (DINamespace *namespace, + const gchar *name); +DIEnum *di_namespace_lookup_enum (DINamespace *namespace, + const gchar *name); +DIErrorDomain *di_namespace_lookup_error_domain (DINamespace *namespace, + const gchar *name); + +/* ---------------------------------------------------------------------------------------------------- */ + +DIParser *di_parser_new (const gchar *path); +GList *di_parser_get_namespaces (DIParser *parser); +DINamespace *di_parser_lookup_namespace (DIParser *parser, + const gchar *name); +DIBase *di_parser_lookup_symbol (DIParser *parser, + const gchar *fully_qualified_name); +GList *di_parser_get_warnings (DIParser *parser); +GList *di_parser_get_errors (DIParser *parser); +void di_parser_free (DIParser *parser); + +/* ---------------------------------------------------------------------------------------------------- */ + +G_END_DECLS + +#endif /* __DBUS_IDL_H */ diff --git a/src/dbusidlprivate.h b/src/dbusidlprivate.h new file mode 100644 index 0000000..4f0b9ec --- /dev/null +++ b/src/dbusidlprivate.h @@ -0,0 +1,319 @@ +/* Copyright (C) 2009 David Zeuthen <zeuthen@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen <zeuthen@gmail.com> + */ + +#include "dbusidl.h" + +#ifndef __DBUS_IDL_PRIVATE_H +#define __DBUS_IDL_PRIVATE_H + +/* ---------------------------------------------------------------------------------------------------- */ + +struct _DIBase +{ + DIBaseType type; + gchar *decl_filename; + guint decl_lineno; +}; + +struct _DIAnnotation +{ + DIBase base; + gchar *name; + gchar *value; +}; + +struct _DIType +{ + DIBase base; + gchar *name; + GList *inner_types; + + gchar *signature; + + /* only set if type is a user supplied type */ + gchar *fully_qualified_name; +}; + +struct _DIArg +{ + DIBase base; + gchar *name; + DIType *type; + DIArgDirection direction; + GList *annotations; +}; + +struct _DIMethod +{ + DIBase base; + gchar *name; + gchar *fully_qualified_name; + GList *args; + GList *annotations; + + gchar *in_signature; + gchar *out_signature; +}; + +struct _DISignal +{ + DIBase base; + gchar *name; + gchar *fully_qualified_name; + GList *args; + GList *annotations; + + gchar *signature; +}; + +struct _DIProperty +{ + DIBase base; + gchar *name; + gchar *fully_qualified_name; + DIType *type; + DIPropertyFlags flags; + GList *annotations; + + gchar *signature; +}; + +struct _DIInterface +{ + DIBase base; + gchar *name; + gchar *fully_qualified_name; + GList *methods; + GList *signals; + GList *properties; + GList *annotations; +}; + +struct _DIStructMember +{ + DIBase base; + gchar *name; + DIType *type; + GList *annotations; +}; + +struct _DIStruct +{ + DIBase base; + gchar *name; + gchar *fully_qualified_name; + GList *members; + GList *annotations; + + gchar *signature; +}; + +struct _DIDynamicStruct +{ + DIBase base; + gchar *name; + gchar *fully_qualified_name; + GList *members; + GList *annotations; +}; + +struct _DIEnumMember +{ + DIBase base; + gchar *name; + gchar *fully_qualified_name; + guint32 value; + gboolean unset; + GList *annotations; +}; + +struct _DIEnum +{ + DIBase base; + gchar *name; + gchar *fully_qualified_name; + GList *members; + GList *annotations; +}; + +struct _DIErrorMember +{ + DIBase base; + gchar *name; + gchar *fully_qualified_name; + GList *annotations; +}; + +struct _DIErrorDomain +{ + DIBase base; + gchar *name; + gchar *fully_qualified_name; + GList *members; + GList *annotations; +}; + +struct _DINamespace +{ + DIBase base; + gchar *name; + GList *interfaces; + GList *structs; + GList *dynamic_structs; + GList *enums; + GList *error_domains; + + GList *annotations; +}; + +struct _DIParser +{ + gchar *path_to_current_file; + GList *namespaces; + GList *warnings; + GList *errors; + + /* hash from fully-qualified name to DIBase* */ + GHashTable *symbol_table; +}; + +/* ---------------------------------------------------------------------------------------------------- */ + +DIAnnotation *di_annotation_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + gchar *value); +DIType *di_type_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *inner_types); +DIArg *di_arg_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + DIType *type, + DIArgDirection direction, + GList *annotations); +DIMethod *di_method_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *args, + GList *annotations); +DISignal *di_signal_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *args, + GList *annotations); +DIProperty *di_property_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + DIType *type, + DIPropertyFlags flags, + GList *annotations); +DIInterface *di_interface_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *methods, + GList *signals, + GList *properties, + GList *annotations); +DIStructMember *di_struct_member_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + DIType *type, + GList *annotations); +DIStruct *di_struct_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *members, + GList *annotations); +DIDynamicStruct *di_dynamic_struct_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *members, + GList *annotations); +DIEnumMember *di_enum_member_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + guint32 value, + gboolean unset, + GList *annotations); +DIEnum *di_enum_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *members, + GList *annotations); +DIErrorMember *di_error_member_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *annotations); +DIErrorDomain *di_error_domain_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *members, + GList *annotations); +DINamespace *di_namespace_new (gchar *decl_filename, + guint decl_lineno, + gchar *name, + GList *interfaces, + GList *structs, + GList *dynamic_structs, + GList *enums, + GList *error_domains, + GList *annotations); + +/* ---------------------------------------------------------------------------------------------------- */ + +void di_annotation_free (DIAnnotation *annotation); +void di_type_free (DIType *type); +void di_arg_free (DIArg *arg); +void di_signal_free (DISignal *signal); +void di_method_free (DIMethod *method); +void di_property_free (DIProperty *property); +void di_interface_free (DIInterface *interface); +void di_struct_member_free (DIStructMember *struct_member); +void di_struct_free (DIStruct *struct_); +void di_dynamic_struct_free (DIDynamicStruct *dynamic_struct); +void di_enum_member_free (DIEnumMember *enum_member); +void di_enum_free (DIEnum *enum_); +void di_error_member_free (DIErrorMember *error_member); +void di_error_domain_free (DIErrorDomain *error_domain); +void di_namespace_free (DINamespace *namespace); + +/* ---------------------------------------------------------------------------------------------------- */ + +void di_annotation_print (DIAnnotation *annotation, guint indent); +void di_type_print (DIType *type, guint indent); +void di_arg_print (DIArg *arg, guint indent); +void di_signal_print (DISignal *signal, guint indent); +void di_method_print (DIMethod *method, guint indent); +void di_property_print (DIProperty *property, guint indent); +void di_interface_print (DIInterface *interface, guint indent); +void di_struct_member_print (DIStructMember *struct_member, guint indent); +void di_struct_print (DIStruct *struct_, guint indent); +void di_dynamic_struct_print (DIDynamicStruct *struct_, guint indent); +void di_enum_member_print (DIEnumMember *enum_member, guint indent); +void di_enum_print (DIEnum *enum_, guint indent); +void di_error_member_print (DIErrorMember *error_member, guint indent); +void di_error_domain_print (DIErrorDomain *error_domain, guint indent); +void di_namespace_print (DINamespace *namespace, guint indent); + +/* ---------------------------------------------------------------------------------------------------- */ + +#endif /* __DBUS_IDL_PRIVATE_H */ @@ -1,5 +1,3 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - /* Copyright (C) 2009 David Zeuthen <zeuthen@gmail.com> * * This library is free software; you can redistribute it and/or @@ -17,16 +15,23 @@ * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. * - * Author: David Zeuthen <davidz@redhat.com> + * Author: David Zeuthen <zeuthen@gmail.com> */ -#include "config.h" +#ifndef __IDL_H +#define __IDL_H +#include <stdio.h> #include <glib.h> -int -main (int argc, char *argv[]) -{ - printf ("Hello World!\n"); - return 0; -} +#include "dbusidl.h" +#include "dbusidlprivate.h" + +extern FILE *yyin; +extern int yyparse (DIParser *parser); +extern int yydebug; +extern int yy_flex_debug; + +extern DINamespace *yynamespace; + +#endif /* __IDL_H */ diff --git a/src/idllexer.l b/src/idllexer.l new file mode 100644 index 0000000..e54c7a7 --- /dev/null +++ b/src/idllexer.l @@ -0,0 +1,156 @@ +/* Copyright (C) 2009 David Zeuthen <zeuthen@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen <zeuthen@gmail.com> + */ + +%{ +#define YYDEBUG 1 + +#include <stdio.h> +#include <glib.h> +#include "libdbus_idl_1_la-idlparser.h" + +static void parse_comment (void); +static void parse_eol_comment (void); +static gchar *unescape_string (const gchar *str); +%} + +%option nounput + +stringtext ([^\\\"])|(\\.) + +%% + +"//" { parse_eol_comment (); yylineno++; } +"/*" { parse_comment (); } +"namespace" {return NAMESPACE;} +"interface" {return INTERFACE;} +"signal" {return SIGNAL;} +"property" {return PROPERTY;} +"struct" {return STRUCT;} +"dynamic_struct" {return DYNAMIC_STRUCT;} +"enum" {return ENUM;} +"error_domain" {return ERROR_DOMAIN;} +"in" {return IN;} +"out" {return OUT;} +"readonly" {return READONLY;} +"writeonly" {return WRITEONLY;} +"byte" {return TYPE_BYTE;} +"int16" {return TYPE_INT16;} +"uint16" {return TYPE_UINT16;} +"int32" {return TYPE_INT32;} +"uint32" {return TYPE_UINT32;} +"int64" {return TYPE_INT64;} +"uint64" {return TYPE_UINT64;} +"double" {return TYPE_DOUBLE;} +"boolean" {return TYPE_BOOLEAN;} +"string" {return TYPE_STRING;} +"objpath" {return TYPE_OBJECT_PATH;} +"signature" {return TYPE_SIGNATURE;} +"array" {return TYPE_ARRAY;} +"dict" {return TYPE_DICT;} +"variant" {return TYPE_VARIANT;} +"." {return DOT;} +"," {return COMMA;} +";" {return SEMICOLON;} +[a-zA-Z_][a-zA-Z0-9_]* {yylval.str = g_strdup (yytext); return IDENTIFIER;} +[0-9][0-9]* {yylval.number = atoi (yytext); return NUMBER;} +"=" {return EQUAL;} +"+" {return PLUS;} +"-" {return MINUS;} +"*" {return STAR;} +"/" {return SLASH;} +"&" {return AMPERSAND;} +"|" {return PIPE;} +"%" {return PERCENT;} +"{" {return OBRACE;} +"}" {return EBRACE;} +"(" {return OPAREN;} +")" {return EPAREN;} +"<" {return OBRACKET;} +">" {return EBRACKET;} +"@" {return ATSIGN;} +"\""{stringtext}*"\"" {yylval.str = unescape_string (yytext) ; return STRING; } +[\r\n] { yylineno++; /* ignore end of line */ } +[ \t]+ { /* ignore whitespace */ } +. {return UNKNOWN;} +%% + + +static void +parse_comment (void) +{ + GString *comment; + int c1, c2; + + c1 = input(); + c2 = input(); + + comment = g_string_new (""); + + while (c2 != EOF && (c1 != '*' || c2 != '/')) + { + g_string_append_c (comment, c1); + + if (c1 == '\n') + yylineno++; + + c1 = c2; + c2 = input(); + } + /* TODO: use comment */ + g_string_free (comment, TRUE); +} + + +static void +parse_eol_comment (void) +{ + GString *comment; + int c; + + c = input(); + comment = g_string_new (""); + + while (c != EOF && c != '\r' && c != '\n') + { + g_string_append_c (comment, c); + c = input (); + } + /* TODO: use comment */ + g_string_free (comment, TRUE); +} + +static gchar * +unescape_string (const gchar *str) +{ + gchar *ret; + gchar *s; + + ret = g_strdup (str + 1); + if (strlen (ret) == 0) + goto out; + ret[strlen (ret) - 1] = '\0'; + + s = ret; + ret = g_strcompress (ret); + g_free (s); + +out: + return ret; +} diff --git a/src/idlparser.y b/src/idlparser.y new file mode 100644 index 0000000..e141575 --- /dev/null +++ b/src/idlparser.y @@ -0,0 +1,788 @@ +/* Copyright (C) 2009 David Zeuthen <zeuthen@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen <zeuthen@gmail.com> + */ + +%{ +#define YYDEBUG 1 + +#include <stdio.h> +#include <string.h> +#include "idl.h" +#include "dbusidl.h" + +int yylex (DIParser *parser); +int yywrap (void); +void yyerror (DIParser *parser, char const *str); + +extern int yylineno; + +void +yyerror (DIParser *parser, const char *str) +{ + parser->errors = g_list_append (parser->errors, + g_strdup_printf ("%s:%d: %s", + parser->path_to_current_file, + yylineno, + str)); +} + +int yywrap (void) +{ + return 1; +} + +%} + +%parse-param { DIParser* parser } +%lex-param { DIParser* parser } + +%error-verbose +%union { + gchar *str; + guint32 number; + gint direction; + struct _DIType *type; + struct _DIArg *arg; + struct _DIMethod *method; + struct _DISignal *signal; + struct _DIInterface *interface; + struct _DIProperty *property; + gint property_flags; + struct _GList *arg_list; + struct _DIStruct *struct_; + struct _DIDynamicStruct *dynamic_struct; + struct _DIStructMember *struct_member; + struct _GList *struct_body; + struct _DIEnum *enum_; + struct _DIEnumMember *enum_member; + struct _GList *enum_body; + struct _DIErrorDomain *error_domain; + struct _DIErrorMember *error_member; + struct _GList *error_body; + struct + { + struct _GList *methods; + struct _GList *signals; + struct _GList *properties; + } iface_body; + struct + { + struct _GList *interfaces; + struct _GList *structs; + struct _GList *dynamic_structs; + struct _GList *enums; + struct _GList *error_domains; + } ns_body; + struct _GList *annotation_list; + struct _DIAnnotation *annotation; +} + +%type <number> numberexpr + +%type <annotation_list> annotation_list +%type <annotation> annotation + +%type <str> dbus_name +%type <direction> direction + +%type <type> type +%type <type> basic_type + +%type <arg> method_arg +%type <arg> signal_arg + +%type <method> method +%type <signal> signal +%type <interface> iface_decl +%type <arg_list> method_arg_list +%type <arg_list> signal_arg_list +%type <property> property +%type <property_flags> property_flags + +%type <dynamic_struct> dynamic_struct_decl + +%type <struct_> struct_decl +%type <struct_member> struct_member +%type <struct_body> struct_body + +%type <error_domain> error_domain_decl +%type <error_member> error_member +%type <error_body> error_body + +%type <enum_> enum_decl +%type <enum_member> enum_member +%type <enum_body> enum_body + +%type <iface_body> iface_body + +%type <ns_body> ns_decls + +%left PIPE +%left AMPERSAND +%left PLUS MINUS +%left STAR SLASH PERCENT +%left UMINUS /*supplies precedence for unary minus */ + +%% + +/* ---------------------------------------------------------------------------------------------------- */ + +file: + | ns_decl + ; + +ns_decl + : annotation_list NAMESPACE dbus_name OBRACE ns_decls EBRACE SEMICOLON + { + parser->namespaces = g_list_append (parser->namespaces, + di_namespace_new (g_strdup (parser->path_to_current_file), + yylineno, + $3, + $5.interfaces, + $5.structs, + $5.dynamic_structs, + $5.enums, + $5.error_domains, + $1)); + $5.interfaces = NULL; + $5.dynamic_structs = NULL; + $5.structs = NULL; + $5.enums = NULL; + $5.error_domains = NULL; + } + ; + +ns_decls + : iface_decl + { + $$.interfaces = g_list_append (NULL, $1); + $$.dynamic_structs = NULL; + $$.structs = NULL; + $$.enums = NULL; + $$.error_domains = NULL; + } + | ns_decls iface_decl + { + $$.interfaces = g_list_append ($1.interfaces, $2); + } + | struct_decl + { + $$.interfaces = NULL; + $$.structs = g_list_append (NULL, $1); + $$.dynamic_structs = NULL; + $$.enums = NULL; + $$.error_domains = NULL; + } + | ns_decls struct_decl + { + $$.structs = g_list_append ($1.structs, $2); + } + | dynamic_struct_decl + { + $$.interfaces = NULL; + $$.structs = NULL; + $$.dynamic_structs = g_list_append (NULL, $1); + $$.enums = NULL; + $$.error_domains = NULL; + } + | ns_decls dynamic_struct_decl + { + $$.dynamic_structs = g_list_append ($1.dynamic_structs, $2); + } + | enum_decl + { + $$.interfaces = NULL; + $$.structs = NULL; + $$.dynamic_structs = NULL; + $$.enums = g_list_append (NULL, $1); + $$.error_domains = NULL; + } + | ns_decls enum_decl + { + $$.enums = g_list_append ($1.enums, $2); + } + | error_domain_decl + { + $$.interfaces = NULL; + $$.structs = NULL; + $$.dynamic_structs = NULL; + $$.enums = NULL; + $$.error_domains = g_list_append (NULL, $1); + } + | ns_decls error_domain_decl + { + $$.error_domains = g_list_append ($1.error_domains, $2); + } + ; + +/* ---------------------------------------------------------------------------------------------------- */ + +dbus_name + : IDENTIFIER + { + $$ = $1; + } + | IDENTIFIER DOT dbus_name + { + $$ = g_strdup_printf ("%s.%s", $1, $3); + g_free ($1); + g_free ($3); + } + ; + +/* ---------------------------------------------------------------------------------------------------- */ + +error_domain_decl + : annotation_list ERROR_DOMAIN IDENTIFIER OBRACE error_body EBRACE SEMICOLON + { + $$ = di_error_domain_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ($3), + $5, + $1); + } + ; + +error_body + : error_member + { + $$ = g_list_append (NULL, $1); + } + | error_body COMMA error_member + { + $$ = g_list_append ($1, $3); + } + ; + +error_member + : annotation_list IDENTIFIER + { + $$ = di_error_member_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ($2), + $1); + } + ; + +/* ---------------------------------------------------------------------------------------------------- */ + +enum_decl + : annotation_list ENUM IDENTIFIER OBRACE enum_body EBRACE SEMICOLON + { + $$ = di_enum_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ($3), + $5, + $1); + } + ; + +enum_body + : enum_member + { + $$ = g_list_append (NULL, $1); + } + | enum_body COMMA enum_member + { + $$ = g_list_append ($1, $3); + } + ; + +enum_member + : annotation_list IDENTIFIER + { + $$ = di_enum_member_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ($2), + 0, + TRUE, + $1); + } + | annotation_list IDENTIFIER EQUAL numberexpr + { + $$ = di_enum_member_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ($2), + $4, + FALSE, + $1); + } + ; + +/* ---------------------------------------------------------------------------------------------------- */ + +numberexpr + : OPAREN numberexpr EPAREN + { + $$ = $2; + } + | numberexpr STAR numberexpr + { + $$ = $1 * $3; + } + | numberexpr SLASH numberexpr + { + $$ = $1 / $3; + } + | numberexpr PERCENT numberexpr + { + $$ = $1 % $3; + } + | numberexpr PLUS numberexpr + { + $$ = $1 + $3; + } + | numberexpr MINUS numberexpr + { + $$ = $1 - $3; + } + | numberexpr AMPERSAND numberexpr + { + $$ = $1 & $3; + } + | numberexpr PIPE numberexpr + { + $$ = $1 | $3; + } + | numberexpr OBRACKET OBRACKET numberexpr + { + $$ = $1 << $4; + } + | numberexpr EBRACKET EBRACKET numberexpr + { + $$ = $1 >> $4; + } + | MINUS numberexpr %prec UMINUS + { + $$ = -$2; + } + | NUMBER + { + $$ = $1; + } + ; + +/* ---------------------------------------------------------------------------------------------------- */ + +dynamic_struct_decl + : annotation_list DYNAMIC_STRUCT IDENTIFIER OBRACE struct_body EBRACE SEMICOLON + { + $$ = di_dynamic_struct_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ($3), + $5, + $1); + } + ; + +/* ---------------------------------------------------------------------------------------------------- */ + +struct_decl + : annotation_list STRUCT IDENTIFIER OBRACE struct_body EBRACE SEMICOLON + { + $$ = di_struct_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ($3), + $5, + $1); + } + ; + +struct_body + : struct_member + { + $$ = g_list_append (NULL, $1); + } + | struct_body struct_member + { + $$ = g_list_append ($1, $2); + } + ; + +struct_member + : annotation_list type IDENTIFIER SEMICOLON + { + $$ = di_struct_member_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ($3), + $2, + $1); + } + ; + +/* ---------------------------------------------------------------------------------------------------- */ + +iface_decl + : annotation_list INTERFACE IDENTIFIER OBRACE iface_body EBRACE SEMICOLON + { + $$ = di_interface_new (g_strdup (parser->path_to_current_file), + yylineno, + $3, + $5.methods, + $5.signals, + $5.properties, + $1); + $5.methods = NULL; + $5.signals = NULL; + $5.properties = NULL; + } + ; + +iface_body + : method + { + $$.methods = g_list_append (NULL, $1); + } + | iface_body method + { + $$.methods = g_list_append ($1.methods, $2); + } + | signal + { + $$.signals = g_list_append (NULL, $1); + } + | iface_body signal + { + $$.signals = g_list_append ($1.signals, $2); + } + | property + { + $$.properties = g_list_append (NULL, $1); + } + | iface_body property + { + $$.properties = g_list_append ($1.properties, $2); + } + ; + +/* ---------------------------------------------------------------------------------------------------- */ + +signal + : annotation_list SIGNAL IDENTIFIER OPAREN signal_arg_list EPAREN SEMICOLON + { + $$ = di_signal_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ($3), + $5, + $1); + } + ; + +signal_arg_list + : + { + $$ = NULL; + } + | signal_arg + { + $$ = g_list_append (NULL, $1); + } + | signal_arg_list COMMA signal_arg + { + $$ = g_list_append ($1, $3); + } + ; + +signal_arg + : annotation_list type IDENTIFIER + { + $$ = di_arg_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ($3), + $2, + DI_ARG_DIRECTION_NONE, + $1); + } + ; + +/* ---------------------------------------------------------------------------------------------------- */ + +method + : annotation_list IDENTIFIER OPAREN method_arg_list EPAREN SEMICOLON + { + $$ = di_method_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ($2), + $4, + $1); + } + ; + +method_arg_list + : + { + $$ = NULL; + } + | method_arg + { + $$ = g_list_append (NULL, $1); + } + | method_arg_list COMMA method_arg + { + $$ = g_list_append ($1, $3); + } + ; + +method_arg + : annotation_list direction type IDENTIFIER + { + $$ = di_arg_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ($4), + $3, + $2, + $1); + } + ; + +direction + : IN + { + $$=DI_ARG_DIRECTION_IN; + } + | OUT + { + $$=DI_ARG_DIRECTION_OUT; + } + ; + +/* ---------------------------------------------------------------------------------------------------- */ + +property + : annotation_list property_flags PROPERTY type IDENTIFIER SEMICOLON + { + $$ = di_property_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ($5), + $4, + $2, + $1); + } + ; + +property_flags + : + { + $$ = DI_PROPERTY_FLAGS_WRITABLE | DI_PROPERTY_FLAGS_READABLE; + } + | READONLY + { + $$ = DI_PROPERTY_FLAGS_READABLE; + } + | WRITEONLY + { + $$ = DI_PROPERTY_FLAGS_WRITABLE; + } + ; + +/* ---------------------------------------------------------------------------------------------------- */ + +annotation_list + : + { + $$ = NULL; + } + | annotation + { + $$ = g_list_append (NULL, $1); + } + | annotation_list annotation + { + $$ = g_list_append ($1, $2); + } + ; + +annotation + : ATSIGN dbus_name + { + $$ = di_annotation_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ($2), + NULL); + } + | ATSIGN dbus_name OPAREN STRING EPAREN + { + $$ = di_annotation_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ($2), + g_strdup ($4)); + } + ; + +/* ---------------------------------------------------------------------------------------------------- */ + +type + : basic_type + { + $$ = $1; + } + | TYPE_ARRAY OBRACKET type EBRACKET + { + $$ = di_type_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ("array"), + g_list_append (NULL, $3)); + } + | TYPE_DICT OBRACKET type COMMA type EBRACKET + { + GList *inner_types; + inner_types = g_list_append (NULL, $3); + inner_types = g_list_append (inner_types, $5); + $$ = di_type_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ("dict"), + inner_types); + } + ; + +basic_type + : TYPE_BYTE + { + $$ = di_type_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ("byte"), + NULL); + } + | TYPE_INT16 + { + $$ = di_type_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ("int16"), + NULL); + } + | TYPE_UINT16 + { + $$ = di_type_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ("uint16"), + NULL); + } + | TYPE_INT32 + { + $$ = di_type_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ("int32"), + NULL); + } + | TYPE_UINT32 + { + $$ = di_type_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ("uint32"), + NULL); + } + | TYPE_INT64 + { + $$ = di_type_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ("int64"), + NULL); + } + | TYPE_UINT64 + { + $$ = di_type_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ("uint64"), + NULL); + } + | TYPE_DOUBLE + { + $$ = di_type_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ("double"), + NULL); + } + | TYPE_BOOLEAN + { + $$ = di_type_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ("boolean"), + NULL); + } + | TYPE_STRING + { + $$ = di_type_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ("string"), + NULL); + } + | TYPE_OBJECT_PATH + { + $$ = di_type_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ("objpath"), + NULL); + } + | TYPE_SIGNATURE + { + $$ = di_type_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ("signature"), + NULL); + } + | TYPE_VARIANT + { + $$ = di_type_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ("variant"), + NULL); + } + | dbus_name + { + $$ = di_type_new (g_strdup (parser->path_to_current_file), + yylineno, + g_strdup ($1), + NULL); + } + ; + +// keywords +%token INTERFACE SIGNAL PROPERTY STRUCT DYNAMIC_STRUCT ENUM FLAGS ERROR_DOMAIN NAMESPACE; + +%token IN OUT READONLY WRITEONLY; + +%token TYPE_BYTE; +%token TYPE_INT16; +%token TYPE_UINT16; +%token TYPE_INT32; +%token TYPE_UINT32; +%token TYPE_INT64; +%token TYPE_UINT64; +%token TYPE_DOUBLE; +%token TYPE_BOOLEAN; +%token TYPE_STRING; +%token TYPE_OBJECT_PATH; +%token TYPE_SIGNATURE; +%token TYPE_VARIANT; + +%token TYPE_ARRAY; +%token TYPE_DICT; + +%token <str> IDENTIFIER; +%token <number> NUMBER; +%token <str> STRING; + +// braces / parens etc +%token OBRACE EBRACE OPAREN EPAREN OBRACKET EBRACKET SEMICOLON COMMA DOT EQUAL ATSIGN; + +// operators +%token PLUS MINUS STAR AMPERSAND PIPE PERCENT; + +// unknown +%token UNKNOWN; diff --git a/src/org.freedesktop.DBus.Idl.Tests1.didl b/src/org.freedesktop.DBus.Idl.Tests1.didl new file mode 100644 index 0000000..e506fd7 --- /dev/null +++ b/src/org.freedesktop.DBus.Idl.Tests1.didl @@ -0,0 +1,116 @@ +// -*- idl -*- + +@Version("1.5") +namespace org.freedesktop.DBus.Idl.Tests1 +{ + struct Struct1 + { + int32 bar; + uint64 baz; + variant something; + array<variant> lots_of_something; + dict<string,variant> property_bag; + }; + + dynamic_struct Struct2 + { + uint64 a; + uint64 b; + uint64 c; + string d; + array<string> stuff; + }; + + enum Enum1 + { + Foo, + Bar, + Baz, + BigFoo = 1000, + BigBar, + BigBaz, + A = 2000 + 0, + B = 2100 - 10, + C = -32, + D = 1408 / 11, + E = 2 * 5, + F = 1<<5, + G = (1<<5) + 10, + H = 1<<5 + 10 + }; + + @Flags + enum Enum2 + { + None = 0, + AllowReplacement = 1<<0, + Replace = 1<<1, + Activate = 1<<2 + }; + + struct Point + { + int32 x; + int32 y; + }; + + struct Pair + { + int32 first; + int32 second; + }; + + interface Frobnicable + { + VoidMethod (); + + PrimitiveMethod (in byte a1, + in boolean a2, + in int16 a3, + in uint16 a4, + in int32 a5, + in uint32 a6, + in int64 a7, + in uint64 a8, + in double a9, + in string a10, + in objpath a11, + in signature a12); + + @NoReply + ContainerMethod (in array<int32> a1, + in array<string> a2, + in array<array<int32>> a3, + in dict<int32,int32> a4, + in dict<string,dict<array<string>,string>> a5); + + @Deprecated + StructsMethod (in Struct1 a1, + in array<Struct1> a2, + in array<array<Struct1>> a3, + in dict<string,Struct1> a4, + out Struct2 a5, + out array<Struct2> a6, + out dict<string,Struct2> a7); + + @Since("1.3") + EnumMethod (in Enum1 a1, out Enum2 a2); + + @Deprecated("1.2") + signal VoidSignal(); + + signal ArgSignal (array<Point> points, array<Pair> pairs); + + property int32 RWProperty; + readonly property int32 ROProperty; + writeonly property int32 WOProperty; + + property dict<string,array<Point>> ComplexProperty; + }; + + interface SecondaryProtocol + { + SecretMethod (in int32 foo); + }; + +}; diff --git a/src/test.c b/src/test.c new file mode 100644 index 0000000..5408cf8 --- /dev/null +++ b/src/test.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2009 David Zeuthen <zeuthen@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen <zeuthen@gmail.com> + */ + +#include "config.h" + +#include <glib.h> + +#include "dbusidl.h" + +static gboolean +pof (const gchar *path) +{ + DIParser *parser; + gboolean ret; + GList *l; + + ret = FALSE; + + parser = di_parser_new (path); + + for (l = di_parser_get_errors (parser); l != NULL; l = l->next) + { + const gchar *message = l->data; + g_printerr ("%s\n", message); + } + + for (l = di_parser_get_warnings (parser); l != NULL; l = l->next) + { + const gchar *message = l->data; + g_printerr ("%s\n", message); + } + + ret = (di_parser_get_errors (parser) == NULL); + if (!ret) + goto out; + + + for (l = di_parser_get_namespaces (parser); l != NULL; l = l->next) + { + DINamespace *namespace = l->data; + di_namespace_print (namespace, 0); + } + + out: + di_parser_free (parser); + return ret; +} + +int +main (int argc, char *argv[]) +{ + /* TODO: actually compare di_namespace_print() output and di_parser_get_errors/warnings() with + * something + */ + pof ("org.freedesktop.DBus.Idl.Tests1.didl"); + return 0; +} |