widl: Support WinRT parameterized type parsing.

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@codeweavers.com>
Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Rémi Bernon 2021-02-11 17:37:27 +01:00 committed by Alexandre Julliard
parent b79b158d6b
commit ed21c29481
9 changed files with 166 additions and 15 deletions

View File

@ -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
}
}

View File

@ -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:

View File

@ -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

View File

@ -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,7 @@ 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 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 +77,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 +116,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 +128,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 +291,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 +967,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 +989,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 +1829,16 @@ 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;
}
var_list_t *append_var(var_list_t *list, var_t *var)
{
if (!var) return list;
@ -1942,6 +1973,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 +2108,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 +2131,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 +2624,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;

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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;
}

View File

@ -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;