[PATCH 1/4] widl: Support WinRT parameterized type parsing.

Rémi Bernon rbernon at codeweavers.com
Wed Feb 10 03:02:40 CST 2021


And add IVectorView<T> and IIterator<T> parameterized interfaces to
windows.foundation.idl for illustration and future use. They won't
generate any additional code until they are fully specialized.

This is a WIDL-specific feature, but MIDL has some magic knowledge of
these Windows.Foundation.Collections interface templates, and we need a
way to instruct WIDL about them too.

Having these interfaces declared in the IDL, guarded with __WIDL__ ifdef
is easier and more flexible than re-creating the types by hand in WIDL
source.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 include/windows.foundation.idl | 29 +++++++++++
 tools/widl/expr.c              |  2 +
 tools/widl/header.c            |  8 +--
 tools/widl/parser.y            | 93 +++++++++++++++++++++++++++++-----
 tools/widl/typegen.c           |  6 +++
 tools/widl/typelib.c           |  2 +
 tools/widl/typetree.c          | 39 ++++++++++++++
 tools/widl/typetree.h          |  4 ++
 tools/widl/widltypes.h         |  9 ++++
 9 files changed, 177 insertions(+), 15 deletions(-)

diff --git a/include/windows.foundation.idl b/include/windows.foundation.idl
index 5e17062f399..ab7c4753c3b 100644
--- a/include/windows.foundation.idl
+++ b/include/windows.foundation.idl
@@ -111,5 +111,34 @@ namespace Windows {
         {
             HRESULT ToString([out, retval] HSTRING *value);
         }
+
+#ifdef __WIDL__
+        namespace Collections
+        {
+            [
+                contract(Windows.Foundation.FoundationContract, 1.0),
+                uuid(6a79e863-4300-459a-9966-cbb660963ee1)
+            ]
+            interface IIterator<T> : IInspectable
+            {
+                [propget] HRESULT Current([out, retval] T *value);
+                [propget] HRESULT HasCurrent([out, retval] BOOL *value);
+                HRESULT MoveNext([out, retval] BOOL *value);
+                HRESULT GetMany([in] UINT32 count, [out] T *items, [out, retval] UINT32 *value);
+            }
+
+            [
+                contract(Windows.Foundation.FoundationContract, 1.0),
+                uuid(bbe1fa4c-b0e3-4583-baef-1f1b2e483e56)
+            ]
+            interface IVectorView<T> : IInspectable
+            {
+                HRESULT GetAt([in] ULONG index, [out, retval] T *value);
+                [propget] HRESULT Size([out, retval] ULONG *value);
+                HRESULT IndexOf([in, optional] T element, [out] ULONG *index, [out, retval] BOOLEAN *value);
+                HRESULT GetMany([in] ULONG start_index, [out] T *items, [out, retval] ULONG *value);
+            }
+        }
+#endif
     }
 }
diff --git a/tools/widl/expr.c b/tools/widl/expr.c
index 13bd5a889aa..c83e9aa5ec0 100644
--- a/tools/widl/expr.c
+++ b/tools/widl/expr.c
@@ -464,6 +464,8 @@ static type_t *find_identifier(const char *identifier, const type_t *cont_type,
         case TYPE_BITFIELD:
         case TYPE_APICONTRACT:
         case TYPE_RUNTIMECLASS:
+        case TYPE_PARAMETERIZED_TYPE:
+        case TYPE_PARAMETER:
             /* nothing to do */
             break;
         case TYPE_ALIAS:
diff --git a/tools/widl/header.c b/tools/widl/header.c
index e6394991317..8423756e060 100644
--- a/tools/widl/header.c
+++ b/tools/widl/header.c
@@ -488,6 +488,8 @@ void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, i
         break;
       }
       case TYPE_APICONTRACT:
+      case TYPE_PARAMETERIZED_TYPE:
+      case TYPE_PARAMETER:
         /* shouldn't be here */
         assert(0);
         break;
@@ -555,6 +557,8 @@ void write_type_right(FILE *h, type_t *t, int is_field)
   case TYPE_RUNTIMECLASS:
     break;
   case TYPE_APICONTRACT:
+  case TYPE_PARAMETERIZED_TYPE:
+  case TYPE_PARAMETER:
     /* not supposed to be here */
     assert(0);
     break;
@@ -1864,10 +1868,8 @@ static void write_header_stmts(FILE *header, const statement_list_t *stmts, cons
           write_apicontract(header, stmt->u.type);
         else if (type_get_type(stmt->u.type) == TYPE_RUNTIMECLASS)
           write_runtimeclass(header, stmt->u.type);
-        else
-        {
+        else if (type_get_type(stmt->u.type) != TYPE_PARAMETERIZED_TYPE)
           write_type_definition(header, stmt->u.type, stmt->declonly);
-        }
         break;
       case STMT_TYPEREF:
         /* FIXME: shouldn't write out forward declarations for undefined
diff --git a/tools/widl/parser.y b/tools/widl/parser.y
index a6128074f2d..3250320648d 100644
--- a/tools/widl/parser.y
+++ b/tools/widl/parser.y
@@ -38,12 +38,6 @@
 #include "expr.h"
 #include "typetree.h"
 
-typedef struct list typelist_t;
-struct typenode {
-  type_t *type;
-  struct list entry;
-};
-
 struct _import_t
 {
   char *name;
@@ -51,6 +45,8 @@ struct _import_t
 };
 
 static str_list_t *append_str(str_list_t *list, char *str);
+static type_list_t *append_type(type_list_t *list, type_t *type);
+static type_list_t *append_types(type_list_t *list, type_list_t *types);
 static attr_list_t *append_attr(attr_list_t *list, attr_t *attr);
 static attr_list_t *append_attr_list(attr_list_t *new_list, attr_list_t *old_list);
 static decl_spec_t *make_decl_spec(type_t *type, decl_spec_t *left, decl_spec_t *right,
@@ -82,6 +78,8 @@ static var_t *reg_const(var_t *var);
 
 static void push_namespace(const char *name);
 static void pop_namespace(const char *name);
+static void push_parameters_namespace(const char *name);
+static void pop_parameters_namespace(const char *name);
 
 static void check_arg_attrs(const var_t *arg);
 static void check_statements(const statement_list_t *stmts, int is_inside_library);
@@ -119,6 +117,7 @@ static struct namespace global_namespace = {
 };
 
 static struct namespace *current_namespace = &global_namespace;
+static struct namespace *parameters_namespace = NULL;
 
 static typelib_t *current_typelib;
 
@@ -130,6 +129,7 @@ static typelib_t *current_typelib;
 	expr_t *expr;
 	expr_list_t *expr_list;
 	type_t *type;
+	type_list_t *type_list;
 	var_t *var;
 	var_list_t *var_list;
 	declarator_t *declarator;
@@ -292,6 +292,8 @@ static typelib_t *current_typelib;
 %type <type> base_type int_std
 %type <type> enumdef structdef uniondef typedecl
 %type <type> type unqualified_type qualified_type
+%type <type> type_parameter
+%type <type_list> type_parameters
 %type <ifref> class_interface
 %type <ifref_list> class_interfaces
 %type <ifref_list> requires required_types
@@ -966,7 +968,18 @@ inherit:					{ $$ = NULL; }
 	| ':' qualified_type                    { $$ = $2; }
 	;
 
-interface: tINTERFACE typename			{ $$ = type_interface_declare($2, current_namespace); }
+type_parameter: typename			{ $$ = get_type(TYPE_PARAMETER, $1, parameters_namespace, 0); }
+	;
+
+type_parameters:
+	  type_parameter			{ $$ = append_type(NULL, $1); }
+	| type_parameters ',' type_parameter	{ $$ = append_type($1, $3); }
+	;
+
+interface:
+	  tINTERFACE typename			{ $$ = type_interface_declare($2, current_namespace); }
+	| tINTERFACE typename '<' { push_parameters_namespace($2); } type_parameters { pop_parameters_namespace($2); } '>'
+						{ $$ = type_parameterized_interface_declare($2, current_namespace, $5); }
 	;
 
 required_types:
@@ -977,9 +990,18 @@ requires:					{ $$ = NULL; }
 	| tREQUIRES required_types		{ $$ = $2; }
 	;
 
-interfacedef: attributes interface inherit requires
-	  '{' int_statements '}' semicolon_opt	{ $$ = type_interface_define($2, $1, $3, $6, $4);
-						  check_async_uuid($$);
+interfacedef: attributes interface		{ if ($2->type_type == TYPE_PARAMETERIZED_TYPE) push_parameters_namespace($2->name); }
+	  inherit requires '{' int_statements '}' semicolon_opt
+						{ if ($2->type_type == TYPE_PARAMETERIZED_TYPE)
+						  {
+						      $$ = type_parameterized_interface_define($2, $1, $4, $7, $5);
+						      pop_parameters_namespace($2->name);
+						  }
+						  else
+						  {
+						      $$ = type_interface_define($2, $1, $4, $7, $5);
+						      check_async_uuid($$);
+						  }
 						}
 	| dispinterfacedef semicolon_opt	{ $$ = $1; }
 	;
@@ -1808,6 +1830,26 @@ static ifref_t *make_ifref(type_t *iface)
   return l;
 }
 
+static type_list_t *append_type(type_list_t *list, type_t *type)
+{
+    type_list_t *entry;
+    if (!type) return list;
+    entry = xmalloc( sizeof(*entry) );
+    entry->type = type;
+    entry->next = list;
+    return entry;
+}
+
+static type_list_t *append_types(type_list_t *list, type_list_t *types)
+{
+    type_list_t *entry;
+    if (!list) return types;
+    if (!types) return list;
+    for (entry = list; entry->next; entry = entry->next) {}
+    entry->next = types;
+    return list;
+}
+
 var_list_t *append_var(var_list_t *list, var_t *var)
 {
     if (!var) return list;
@@ -1942,6 +1984,29 @@ static void pop_namespace(const char *name)
   current_namespace = current_namespace->parent;
 }
 
+static void push_parameters_namespace(const char *name)
+{
+    struct namespace *namespace;
+
+    if (!(namespace = find_sub_namespace(current_namespace, name)))
+    {
+        namespace = xmalloc(sizeof(*namespace));
+        namespace->name = xstrdup(name);
+        namespace->parent = current_namespace;
+        list_add_tail(&current_namespace->children, &namespace->entry);
+        list_init(&namespace->children);
+        memset(namespace->type_hash, 0, sizeof(namespace->type_hash));
+    }
+
+    parameters_namespace = namespace;
+}
+
+static void pop_parameters_namespace(const char *name)
+{
+    assert(!strcmp(parameters_namespace->name, name) && parameters_namespace->parent);
+    parameters_namespace = NULL;
+}
+
 struct rtype {
   const char *name;
   type_t *type;
@@ -2054,7 +2119,8 @@ type_t *find_type(const char *name, struct namespace *namespace, int t)
 static type_t *find_type_or_error(struct namespace *namespace, const char *name)
 {
     type_t *type;
-    if (!(type = find_type(name, namespace, 0)))
+    if (!(type = find_type(name, namespace, 0)) &&
+        !(type = find_type(name, parameters_namespace, 0)))
     {
         error_loc("type '%s' not found in %s namespace\n", name, namespace && namespace->name ? namespace->name : "global");
         return NULL;
@@ -2076,7 +2142,8 @@ static struct namespace *find_namespace_or_error(struct namespace *parent, const
 
 int is_type(const char *name)
 {
-    return find_type(name, current_namespace, 0) != NULL;
+    return find_type(name, current_namespace, 0) != NULL ||
+           find_type(name, parameters_namespace, 0);
 }
 
 type_t *get_type(enum type_type type, char *name, struct namespace *namespace, int t)
@@ -2568,6 +2635,8 @@ static int is_allowed_conf_type(const type_t *type)
     case TYPE_RUNTIMECLASS:
         return FALSE;
     case TYPE_APICONTRACT:
+    case TYPE_PARAMETERIZED_TYPE:
+    case TYPE_PARAMETER:
         /* not supposed to be here */
         assert(0);
         break;
diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c
index 2e9be0748c1..1b5fe16b6ec 100644
--- a/tools/widl/typegen.c
+++ b/tools/widl/typegen.c
@@ -377,6 +377,8 @@ enum typegen_type typegen_detect_type(const type_t *type, const attr_list_t *att
     case TYPE_RUNTIMECLASS:
         break;
     case TYPE_APICONTRACT:
+    case TYPE_PARAMETERIZED_TYPE:
+    case TYPE_PARAMETER:
         /* not supposed to be here */
         assert(0);
         break;
@@ -1974,6 +1976,8 @@ unsigned int type_memsize_and_alignment(const type_t *t, unsigned int *align)
     case TYPE_BITFIELD:
     case TYPE_APICONTRACT:
     case TYPE_RUNTIMECLASS:
+    case TYPE_PARAMETERIZED_TYPE:
+    case TYPE_PARAMETER:
         /* 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
@@ -2077,6 +2081,8 @@ static unsigned int type_buffer_alignment(const type_t *t)
     case TYPE_BITFIELD:
     case TYPE_APICONTRACT:
     case TYPE_RUNTIMECLASS:
+    case TYPE_PARAMETERIZED_TYPE:
+    case TYPE_PARAMETER:
         /* 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 ace6424e3a0..6f6c5f3ccc8 100644
--- a/tools/widl/typelib.c
+++ b/tools/widl/typelib.c
@@ -226,6 +226,8 @@ unsigned short get_type_vt(type_t *t)
 
   case TYPE_ALIAS:
   case TYPE_APICONTRACT:
+  case TYPE_PARAMETERIZED_TYPE:
+  case TYPE_PARAMETER:
     /* not supposed to be here */
     assert(0);
     break;
diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c
index 3c2f183eb13..f696d30a5f5 100644
--- a/tools/widl/typetree.c
+++ b/tools/widl/typetree.c
@@ -619,6 +619,45 @@ type_t *type_apicontract_define(type_t *apicontract, attr_list_t *attrs)
     return apicontract;
 }
 
+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);
+    if (type_get_type_detect_alias(type) != TYPE_PARAMETERIZED_TYPE)
+        error_loc("pinterface %s previously not declared a pinterface at %s:%d\n",
+                  type->name, type->loc_info.input_name, type->loc_info.line_number);
+    type->details.parameterized.type = make_type(TYPE_INTERFACE);
+    type->details.parameterized.params = params;
+    return type;
+}
+
+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 *iface;
+    if (type->defined)
+        error_loc("pinterface %s already defined at %s:%d\n",
+                  type->name, type->loc_info.input_name, type->loc_info.line_number);
+
+    /* The parameterized type UUID is actually a PIID that is then used as a seed to generate
+     * a new type GUID with the rules described in:
+     *   https://docs.microsoft.com/en-us/uwp/winrt-cref/winrt-type-system#parameterized-types
+     * TODO: store type signatures for generated interfaces, and generate their GUIDs
+     */
+    type->attrs = check_interface_attrs(type->name, attrs);
+
+    iface = type->details.parameterized.type;
+    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 = inherit;
+    iface->details.iface->disp_inherit = NULL;
+    iface->details.iface->async_iface = NULL;
+    iface->details.iface->requires = requires;
+
+    type->defined = TRUE;
+    return type;
+}
+
 int type_is_equal(const type_t *type1, const type_t *type2)
 {
     if (type1 == type2)
diff --git a/tools/widl/typetree.h b/tools/widl/typetree.h
index 9866d2a1e98..96b681e0379 100644
--- a/tools/widl/typetree.h
+++ b/tools/widl/typetree.h
@@ -62,6 +62,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_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);
 int type_is_equal(const type_t *type1, const type_t *type2);
 const char *type_get_name(const type_t *type, enum name_type name_type);
 char *gen_name(void);
@@ -246,6 +248,8 @@ static inline int type_is_complete(const type_t *type)
     case TYPE_RUNTIMECLASS:
         return TRUE;
     case TYPE_APICONTRACT:
+    case TYPE_PARAMETERIZED_TYPE:
+    case TYPE_PARAMETER:
         assert(0);
         break;
     }
diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h
index e22d425e85b..7596577493d 100644
--- a/tools/widl/widltypes.h
+++ b/tools/widl/widltypes.h
@@ -436,6 +436,12 @@ struct runtimeclass_details
     ifref_list_t *ifaces;
 };
 
+struct parameterized_details
+{
+    type_t *type;
+    type_list_t *params;
+};
+
 #define HASHMAX 64
 
 struct namespace {
@@ -464,6 +470,8 @@ enum type_type
     TYPE_BITFIELD,
     TYPE_APICONTRACT,
     TYPE_RUNTIMECLASS,
+    TYPE_PARAMETERIZED_TYPE,
+    TYPE_PARAMETER,
 };
 
 struct _type_t {
@@ -485,6 +493,7 @@ struct _type_t {
     struct bitfield_details bitfield;
     struct alias_details alias;
     struct runtimeclass_details runtimeclass;
+    struct parameterized_details parameterized;
   } details;
   const char *c_name;
   unsigned int typestring_offset;
-- 
2.30.0




More information about the wine-devel mailing list