[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(¤t_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