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 : 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 : 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..6ab4f83a0ad 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,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 base_type int_std %type enumdef structdef uniondef typedecl %type type unqualified_type qualified_type +%type type_parameter +%type type_parameters %type class_interface %type class_interfaces %type 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(¤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 +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; 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;