[PATCH v2 3/4] widl: Support WinRT delegate type.

Rémi Bernon rbernon at codeweavers.com
Tue Feb 16 14:15:59 CST 2021


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 tools/widl/expr.c      |  1 +
 tools/widl/header.c    | 16 +++++++++-----
 tools/widl/parser.l    |  1 +
 tools/widl/parser.y    | 20 +++++++++++++++++
 tools/widl/typegen.c   |  4 ++++
 tools/widl/typelib.c   |  1 +
 tools/widl/typetree.c  | 49 ++++++++++++++++++++++++++++++++++++++++++
 tools/widl/typetree.h  | 10 +++++++++
 tools/widl/widltypes.h |  7 ++++++
 9 files changed, 104 insertions(+), 5 deletions(-)

diff --git a/tools/widl/expr.c b/tools/widl/expr.c
index c83e9aa5ec0..88d59290d6b 100644
--- a/tools/widl/expr.c
+++ b/tools/widl/expr.c
@@ -466,6 +466,7 @@ static type_t *find_identifier(const char *identifier, const type_t *cont_type,
         case TYPE_RUNTIMECLASS:
         case TYPE_PARAMETERIZED_TYPE:
         case TYPE_PARAMETER:
+        case TYPE_DELEGATE:
             /* nothing to do */
             break;
         case TYPE_ALIAS:
diff --git a/tools/widl/header.c b/tools/widl/header.c
index a4f1db56a01..7ab79d3b6e1 100644
--- a/tools/widl/header.c
+++ b/tools/widl/header.c
@@ -470,6 +470,9 @@ void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, i
       case TYPE_RUNTIMECLASS:
         fprintf(h, "%s", type_get_name(type_runtimeclass_get_default_iface(t), name_type));
         break;
+      case TYPE_DELEGATE:
+        fprintf(h, "%s", type_get_name(type_delegate_get_iface(t), name_type));
+        break;
       case TYPE_VOID:
         fprintf(h, "void");
         break;
@@ -555,6 +558,7 @@ void write_type_right(FILE *h, type_t *t, int is_field)
   case TYPE_COCLASS:
   case TYPE_INTERFACE:
   case TYPE_RUNTIMECLASS:
+  case TYPE_DELEGATE:
     break;
   case TYPE_APICONTRACT:
   case TYPE_PARAMETERIZED_TYPE:
@@ -974,7 +978,7 @@ int has_out_arg_or_return(const var_t *func)
 int is_object(const type_t *iface)
 {
     const attr_t *attr;
-    if (type_is_defined(iface) && type_iface_get_inherit(iface))
+    if (type_is_defined(iface) && (type_get_type(iface) == TYPE_DELEGATE || type_iface_get_inherit(iface)))
         return 1;
     if (iface->attrs) LIST_FOR_EACH_ENTRY( attr, iface->attrs, const attr_t, entry )
         if (attr->type == ATTR_OBJECT || attr->type == ATTR_ODL) return 1;
@@ -1799,9 +1803,10 @@ static void write_forward_decls(FILE *header, const statement_list_t *stmts)
     switch (stmt->type)
     {
       case STMT_TYPE:
-        if (type_get_type(stmt->u.type) == TYPE_INTERFACE)
+        if (type_get_type(stmt->u.type) == TYPE_INTERFACE || type_get_type(stmt->u.type) == TYPE_DELEGATE)
         {
           type_t *iface = stmt->u.type;
+          if (type_get_type(iface) == TYPE_DELEGATE) iface = type_delegate_get_iface(iface);
           if (is_object(iface) || is_attr(iface->attrs, ATTR_DISPINTERFACE))
           {
             write_forward(header, iface);
@@ -1841,10 +1846,11 @@ static void write_header_stmts(FILE *header, const statement_list_t *stmts, cons
     switch (stmt->type)
     {
       case STMT_TYPE:
-        if (type_get_type(stmt->u.type) == TYPE_INTERFACE)
+        if (type_get_type(stmt->u.type) == TYPE_INTERFACE || type_get_type(stmt->u.type) == TYPE_DELEGATE)
         {
-          type_t *iface = stmt->u.type;
-          type_t *async_iface = type_iface_get_async_iface(iface);
+          type_t *iface = stmt->u.type, *async_iface;
+          if (type_get_type(stmt->u.type) == TYPE_DELEGATE) iface = type_delegate_get_iface(iface);
+          async_iface = type_iface_get_async_iface(iface);
           if (is_object(iface)) is_object_interface++;
           if (is_attr(stmt->u.type->attrs, ATTR_DISPINTERFACE) || is_object(stmt->u.type))
           {
diff --git a/tools/widl/parser.l b/tools/widl/parser.l
index d319954edd3..f5e91dc741a 100644
--- a/tools/widl/parser.l
+++ b/tools/widl/parser.l
@@ -278,6 +278,7 @@ static const struct keyword keywords[] = {
 	{"cpp_quote",       tCPPQUOTE,       0},
 	{"declare",         tDECLARE,        1},
 	{"default",         tDEFAULT,        0},
+	{"delegate",        tDELEGATE,       1},
 	{"dispinterface",   tDISPINTERFACE,  0},
 	{"double",          tDOUBLE,         0},
 	{"enum",            tENUM,           0},
diff --git a/tools/widl/parser.y b/tools/widl/parser.y
index 697265349f2..4068ed759e4 100644
--- a/tools/widl/parser.y
+++ b/tools/widl/parser.y
@@ -109,6 +109,7 @@ static statement_t *make_statement_module(type_t *type);
 static statement_t *make_statement_typedef(var_list_t *names, int declonly);
 static statement_t *make_statement_import(const char *str);
 static statement_t *make_statement_parameterized_type(type_t *type, type_list_t *params);
+static statement_t *make_statement_delegate(type_t *ret, var_list_t *args);
 static statement_list_t *append_statement(statement_list_t *list, statement_t *stmt);
 static statement_list_t *append_statements(statement_list_t *, statement_list_t *);
 static attr_list_t *append_attribs(attr_list_t *, attr_list_t *);
@@ -184,6 +185,7 @@ static typelib_t *current_typelib;
 %token tCUSTOM
 %token tDECLARE
 %token tDECODE tDEFAULT tDEFAULTBIND
+%token tDELEGATE
 %token tDEFAULTCOLLELEM
 %token tDEFAULTVALUE
 %token tDEFAULTVTABLE
@@ -282,6 +284,7 @@ static typelib_t *current_typelib;
 %type <expr_list> m_exprs /* exprs expr_list */ expr_list_int_const
 %type <expr> contract_req
 %type <expr> static_attr
+%type <type> delegatedef
 %type <stgclass> storage_cls_spec
 %type <type_qualifier> type_qualifier m_type_qual_list
 %type <function_specifier> function_specifier
@@ -388,6 +391,7 @@ gbl_statements:					{ $$ = NULL; }
 	| gbl_statements interface ';'		{ $$ = append_statement($1, make_statement_reference($2)); }
 	| gbl_statements dispinterface ';'	{ $$ = append_statement($1, make_statement_reference($2)); }
 	| gbl_statements interfacedef		{ $$ = append_statement($1, make_statement_type_decl($2)); }
+	| gbl_statements delegatedef		{ $$ = append_statement($1, make_statement_type_decl($2)); }
 	| gbl_statements coclass ';'		{ $$ = $1;
 						  reg_type($2, $2->name, current_namespace, 0);
 						}
@@ -412,6 +416,7 @@ imp_statements:					{ $$ = NULL; }
 	| imp_statements namespacedef '{' { push_namespace($2); } imp_statements '}'
 						{ pop_namespace($2); $$ = append_statements($1, $5); }
 	| imp_statements interfacedef		{ $$ = append_statement($1, make_statement_type_decl($2)); }
+	| imp_statements delegatedef		{ $$ = append_statement($1, make_statement_type_decl($2)); }
 	| imp_statements coclass ';'		{ $$ = $1; reg_type($2, $2->name, current_namespace, 0); }
 	| imp_statements coclassdef		{ $$ = append_statement($1, make_statement_type_decl($2));
 						  reg_type($2, $2->name, current_namespace, 0);
@@ -1028,6 +1033,12 @@ interface:
 						{ $$ = type_parameterized_interface_declare($2, current_namespace, $5); }
 	;
 
+delegatedef: m_attributes tDELEGATE type ident '(' m_args ')' semicolon_opt
+						{ $$ = type_delegate_declare($4->name, current_namespace);
+						  $$ = type_delegate_define($$, $1, append_statement(NULL, make_statement_delegate($3, $6)));
+						}
+	;
+
 required_types:
 	  qualified_type			{ $$ = append_ifref(NULL, make_ifref($1)); }
 	| parameterized_type			{ $$ = append_ifref(NULL, make_ifref($1)); }
@@ -2672,6 +2683,7 @@ static int is_allowed_conf_type(const type_t *type)
     case TYPE_INTERFACE:
     case TYPE_BITFIELD:
     case TYPE_RUNTIMECLASS:
+    case TYPE_DELEGATE:
         return FALSE;
     case TYPE_APICONTRACT:
     case TYPE_PARAMETERIZED_TYPE:
@@ -3314,6 +3326,14 @@ static statement_t *make_statement_parameterized_type(type_t *type, type_list_t
     return stmt;
 }
 
+static statement_t *make_statement_delegate(type_t *ret, var_list_t *args)
+{
+    declarator_t *decl = make_declarator(make_var(xstrdup("Invoke")));
+    decl_spec_t *spec = make_decl_spec(ret, NULL, NULL, STG_NONE, 0, 0);
+    append_chain_type(decl, type_new_function(args), 0);
+    return make_statement_declaration(declare_var(NULL, spec, decl, FALSE));
+}
+
 static statement_list_t *append_statements(statement_list_t *l1, statement_list_t *l2)
 {
     if (!l2) return l1;
diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c
index 1b5fe16b6ec..ec85f149da1 100644
--- a/tools/widl/typegen.c
+++ b/tools/widl/typegen.c
@@ -354,6 +354,7 @@ enum typegen_type typegen_detect_type(const type_t *type, const attr_list_t *att
     case TYPE_POINTER:
         if (type_get_type(type_pointer_get_ref_type(type)) == TYPE_INTERFACE ||
             type_get_type(type_pointer_get_ref_type(type)) == TYPE_RUNTIMECLASS ||
+            type_get_type(type_pointer_get_ref_type(type)) == TYPE_DELEGATE ||
             (type_get_type(type_pointer_get_ref_type(type)) == TYPE_VOID && is_attr(attrs, ATTR_IIDIS)))
             return TGT_IFACE_POINTER;
         else if (is_aliaschain_attr(type_pointer_get_ref_type(type), ATTR_CONTEXTHANDLE))
@@ -375,6 +376,7 @@ enum typegen_type typegen_detect_type(const type_t *type, const attr_list_t *att
     case TYPE_ALIAS:
     case TYPE_BITFIELD:
     case TYPE_RUNTIMECLASS:
+    case TYPE_DELEGATE:
         break;
     case TYPE_APICONTRACT:
     case TYPE_PARAMETERIZED_TYPE:
@@ -1978,6 +1980,7 @@ unsigned int type_memsize_and_alignment(const type_t *t, unsigned int *align)
     case TYPE_RUNTIMECLASS:
     case TYPE_PARAMETERIZED_TYPE:
     case TYPE_PARAMETER:
+    case TYPE_DELEGATE:
         /* these types should not be encountered here due to language
          * restrictions (interface, void, coclass, module), logical
          * restrictions (alias - due to type_get_type call above) or
@@ -2083,6 +2086,7 @@ static unsigned int type_buffer_alignment(const type_t *t)
     case TYPE_RUNTIMECLASS:
     case TYPE_PARAMETERIZED_TYPE:
     case TYPE_PARAMETER:
+    case TYPE_DELEGATE:
         /* these types should not be encountered here due to language
          * restrictions (interface, void, coclass, module), logical
          * restrictions (alias - due to type_get_type call above) or
diff --git a/tools/widl/typelib.c b/tools/widl/typelib.c
index 6f6c5f3ccc8..8b2a2401367 100644
--- a/tools/widl/typelib.c
+++ b/tools/widl/typelib.c
@@ -219,6 +219,7 @@ unsigned short get_type_vt(type_t *t)
   case TYPE_UNION:
   case TYPE_ENCAPSULATED_UNION:
   case TYPE_RUNTIMECLASS:
+  case TYPE_DELEGATE:
     return VT_USERDEFINED;
 
   case TYPE_VOID:
diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c
index 58b019cc090..1ab41a488ca 100644
--- a/tools/widl/typetree.c
+++ b/tools/widl/typetree.c
@@ -665,6 +665,54 @@ type_t *type_apicontract_define(type_t *apicontract, attr_list_t *attrs)
     return apicontract;
 }
 
+static void compute_delegate_iface_names(type_t *delegate)
+{
+    type_t *iface = delegate->details.delegate.iface;
+    iface->namespace = delegate->namespace;
+    iface->name = strmake("I%s", delegate->name);
+    iface->c_name = format_namespace(delegate->namespace, "__x_", "_C", iface->name, use_abi_namespace ? "ABI" : NULL);
+}
+
+type_t *type_delegate_declare(char *name, struct namespace *namespace)
+{
+    type_t *type = get_type(TYPE_DELEGATE, name, NULL, 0);
+    if (type_get_type_detect_alias(type) != TYPE_DELEGATE)
+        error_loc("delegate %s previously not declared a delegate at %s:%d\n",
+                  type->name, type->loc_info.input_name, type->loc_info.line_number);
+    return type;
+}
+
+type_t *type_delegate_define(type_t *delegate, attr_list_t *attrs, statement_list_t *stmts)
+{
+    type_t *iface;
+
+    if (delegate->defined)
+        error_loc("delegate %s already defined at %s:%d\n",
+                  delegate->name, delegate->loc_info.input_name, delegate->loc_info.line_number);
+
+    delegate->attrs = check_interface_attrs(delegate->name, attrs);
+
+    iface = make_type(TYPE_INTERFACE);
+    iface->attrs = delegate->attrs;
+    iface->details.iface = xmalloc(sizeof(*iface->details.iface));
+    iface->details.iface->disp_props = NULL;
+    iface->details.iface->disp_methods = NULL;
+    iface->details.iface->stmts = stmts;
+    iface->details.iface->inherit = find_type("IUnknown", NULL, 0);
+    if (!iface->details.iface->inherit) error_loc("IUnknown is undefined\n");
+    iface->details.iface->disp_inherit = NULL;
+    iface->details.iface->async_iface = NULL;
+    iface->details.iface->requires = NULL;
+    iface->defined = TRUE;
+    compute_method_indexes(iface);
+
+    delegate->details.delegate.iface = iface;
+    delegate->defined = TRUE;
+    compute_delegate_iface_names(delegate);
+
+    return delegate;
+}
+
 type_t *type_parameterized_interface_declare(char *name, struct namespace *namespace, type_list_t *params)
 {
     type_t *type = get_type(TYPE_PARAMETERIZED_TYPE, name, namespace, 0);
@@ -824,6 +872,7 @@ static type_t *replace_type_parameters_in_type(type_t *type, type_list_t *orig,
     case TYPE_BITFIELD:
     case TYPE_INTERFACE:
     case TYPE_RUNTIMECLASS:
+    case TYPE_DELEGATE:
         return type;
     case TYPE_PARAMETER:
         for (o = orig, r = repl; o && r; o = o->next, r = r->next)
diff --git a/tools/widl/typetree.h b/tools/widl/typetree.h
index 0dc75dff62e..13d6a4d51fb 100644
--- a/tools/widl/typetree.h
+++ b/tools/widl/typetree.h
@@ -64,6 +64,8 @@ type_t *type_coclass_define(type_t *coclass, attr_list_t *attrs, ifref_list_t *i
 type_t *type_runtimeclass_define(type_t *runtimeclass, attr_list_t *attrs, ifref_list_t *ifaces);
 type_t *type_apicontract_declare(char *name, struct namespace *namespace);
 type_t *type_apicontract_define(type_t *apicontract, attr_list_t *attrs);
+type_t *type_delegate_declare(char *name, struct namespace *namespace);
+type_t *type_delegate_define(type_t *delegate, attr_list_t *attrs, statement_list_t *stmts);
 type_t *type_parameterized_interface_declare(char *name, struct namespace *namespace, type_list_t *params);
 type_t *type_parameterized_interface_define(type_t *type, attr_list_t *attrs, type_t *inherit, statement_list_t *stmts, ifref_list_t *requires);
 type_t *type_parameterized_type_specialize_partial(type_t *type, type_list_t *params);
@@ -251,6 +253,7 @@ static inline int type_is_complete(const type_t *type)
     case TYPE_ARRAY:
     case TYPE_BITFIELD:
     case TYPE_RUNTIMECLASS:
+    case TYPE_DELEGATE:
         return TRUE;
     case TYPE_APICONTRACT:
     case TYPE_PARAMETERIZED_TYPE:
@@ -373,6 +376,13 @@ static inline type_t *type_runtimeclass_get_default_iface(const type_t *type)
     return NULL;
 }
 
+static inline type_t *type_delegate_get_iface(const type_t *type)
+{
+    type = type_get_real_type(type);
+    assert(type_get_type(type) == TYPE_DELEGATE);
+    return type->details.delegate.iface;
+}
+
 static inline const decl_spec_t *type_pointer_get_ref(const type_t *type)
 {
     type = type_get_real_type(type);
diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h
index ce48567d583..69f95b9cbbe 100644
--- a/tools/widl/widltypes.h
+++ b/tools/widl/widltypes.h
@@ -442,6 +442,11 @@ struct parameterized_details
     type_list_t *params;
 };
 
+struct delegate_details
+{
+    type_t *iface;
+};
+
 #define HASHMAX 64
 
 struct namespace {
@@ -472,6 +477,7 @@ enum type_type
     TYPE_RUNTIMECLASS,
     TYPE_PARAMETERIZED_TYPE,
     TYPE_PARAMETER,
+    TYPE_DELEGATE,
 };
 
 struct _type_t {
@@ -494,6 +500,7 @@ struct _type_t {
     struct alias_details alias;
     struct runtimeclass_details runtimeclass;
     struct parameterized_details parameterized;
+    struct delegate_details delegate;
   } details;
   const char *c_name;
   unsigned int typestring_offset;
-- 
2.30.0




More information about the wine-devel mailing list