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 --- include/windows.foundation.idl | 29 ++++++++++++ tools/widl/expr.c | 2 + tools/widl/header.c | 8 ++-- tools/widl/parser.y | 82 +++++++++++++++++++++++++++++----- 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, 166 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..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 <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(¤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#parameteri... + * 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;
And use it for format_namespace to grow buffer as needed.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- tools/widl/typetree.c | 46 ++++++++++++++----------------------------- tools/widl/utils.c | 37 ++++++++++++++++++++++++++++++++++ tools/widl/utils.h | 1 + 3 files changed, 53 insertions(+), 31 deletions(-)
diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c index f696d30a5f5..203fffcdee6 100644 --- a/tools/widl/typetree.c +++ b/tools/widl/typetree.c @@ -89,41 +89,25 @@ const char *type_get_name(const type_t *type, enum name_type name_type) return NULL; }
-static char *append_namespace(char *ptr, struct namespace *namespace, const char *separator, const char *abi_prefix) +static size_t append_namespace(char **buf, size_t *len, size_t pos, struct namespace *namespace, const char *separator, const char *abi_prefix) { - if(is_global_namespace(namespace)) { - if(!abi_prefix) return ptr; - strcpy(ptr, abi_prefix); - strcat(ptr, separator); - return ptr + strlen(ptr); - } - - ptr = append_namespace(ptr, namespace->parent, separator, abi_prefix); - strcpy(ptr, namespace->name); - strcat(ptr, separator); - return ptr + strlen(ptr); + int nested = namespace && !is_global_namespace(namespace); + const char *name = nested ? namespace->name : abi_prefix; + size_t n = 0; + if (!name) return 0; + if (nested) n += append_namespace(buf, len, pos + n, namespace->parent, separator, abi_prefix); + n += strappend(buf, len, pos + n, "%s%s", name, separator); + return n; }
-char *format_namespace(struct namespace *namespace, const char *prefix, const char *separator, const char *suffix, - const char *abi_prefix) +char *format_namespace(struct namespace *namespace, const char *prefix, const char *separator, const char *suffix, const char *abi_prefix) { - unsigned len = strlen(prefix) + strlen(suffix); - unsigned sep_len = strlen(separator); - struct namespace *iter; - char *ret, *ptr; - - if(abi_prefix) - len += strlen(abi_prefix) + sep_len; - - for(iter = namespace; !is_global_namespace(iter); iter = iter->parent) - len += strlen(iter->name) + sep_len; - - ret = xmalloc(len+1); - strcpy(ret, prefix); - ptr = append_namespace(ret + strlen(ret), namespace, separator, abi_prefix); - strcpy(ptr, suffix); - - return ret; + size_t len = 0, pos = 0; + char *buf = NULL; + pos += strappend(&buf, &len, pos, "%s", prefix); + pos += append_namespace(&buf, &len, pos, namespace, separator, abi_prefix); + pos += strappend(&buf, &len, pos, "%s", suffix); + return buf; }
type_t *type_new_function(var_list_t *args) diff --git a/tools/widl/utils.c b/tools/widl/utils.c index ea92372c8c7..634bd12a0ba 100644 --- a/tools/widl/utils.c +++ b/tools/widl/utils.c @@ -245,6 +245,43 @@ char *strmake( const char* fmt, ... ) } }
+size_t strappend(char **buf, size_t *len, size_t pos, const char* fmt, ...) +{ + size_t size; + va_list ap; + char *ptr; + int n; + + assert( buf && len ); + assert( (*len == 0 && *buf == NULL) || (*len != 0 && *buf != NULL) ); + + if (*buf) + { + size = *len; + ptr = *buf; + } + else + { + size = 100; + ptr = xmalloc( size ); + } + + for (;;) + { + va_start( ap, fmt ); + n = vsnprintf( ptr + pos, size - pos, fmt, ap ); + va_end( ap ); + if (n == -1) size *= 2; + else if (pos + (size_t)n >= size) size = pos + n + 1; + else break; + ptr = xrealloc( ptr, size ); + } + + *len = size; + *buf = ptr; + return n; +} + char *xstrdup(const char *str) { char *s; diff --git a/tools/widl/utils.h b/tools/widl/utils.h index 37406656504..82e0a6ae489 100644 --- a/tools/widl/utils.h +++ b/tools/widl/utils.h @@ -45,6 +45,7 @@ void warning(const char *s, ...) __attribute__((format (printf, 1, 2))); void warning_loc_info(const loc_info_t *, const char *s, ...) __attribute__((format (printf, 2, 3))); void chat(const char *s, ...) __attribute__((format (printf, 1, 2))); char *strmake(const char* fmt, ...) __attribute__((__format__ (__printf__, 1, 2 ))); +size_t strappend(char **buf, size_t *len, size_t pos, const char* fmt, ...) __attribute__((__format__ (__printf__, 4, 5 )));
char *dup_basename(const char *name, const char *ext); size_t widl_getline(char **linep, size_t *lenp, FILE *fp);
Signed-off-by: Jacek Caban jacek@codeweavers.com
This allows parameterized types to reference each other with a different set of parameters. This is required for instance for IIterable<T>, that needs to reference IIterator<T>.
The partial specialization is recorded by creating a new parameterized type, referencing the original one as its template. The parameterized type chain will be resolved all at once when the type is declared.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- include/windows.foundation.idl | 9 +++++++ tools/widl/parser.y | 47 ++++++++++++++++++++++++++++++++++ tools/widl/typetree.c | 41 ++++++++++++++++++++++++++--- tools/widl/typetree.h | 3 +++ tools/widl/widltypes.h | 1 + 5 files changed, 98 insertions(+), 3 deletions(-)
diff --git a/include/windows.foundation.idl b/include/windows.foundation.idl index ab7c4753c3b..5f7a49c38e4 100644 --- a/include/windows.foundation.idl +++ b/include/windows.foundation.idl @@ -127,6 +127,15 @@ namespace Windows { HRESULT GetMany([in] UINT32 count, [out] T *items, [out, retval] UINT32 *value); }
+ [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(faa585ea-6214-4217-afda-7f46de5869b3) + ] + interface IIterable<T> : IInspectable + { + HRESULT First([out, retval] Windows.Foundation.Collections.IIterator<T> **value); + } + [ contract(Windows.Foundation.FoundationContract, 1.0), uuid(bbe1fa4c-b0e3-4583-baef-1f1b2e483e56) diff --git a/tools/widl/parser.y b/tools/widl/parser.y index 6ab4f83a0ad..7ef16d90456 100644 --- a/tools/widl/parser.y +++ b/tools/widl/parser.y @@ -46,6 +46,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 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, @@ -293,6 +294,8 @@ static typelib_t *current_typelib; %type <type> type unqualified_type qualified_type %type <type> type_parameter %type <type_list> type_parameters +%type <type> parameterized_type +%type <type_list> parameterized_types %type <ifref> class_interface %type <ifref_list> class_interfaces %type <ifref_list> requires required_types @@ -909,6 +912,20 @@ qualified_type: | namespace_pfx typename { $$ = find_type_or_error($1, $2); } ;
+parameterized_type: qualified_type '<' parameterized_types '>' + { $$ = find_parameterized_type($1, $3); } + ; + +parameterized_types: + base_type { $$ = append_type(NULL, $1); } + | qualified_type { $$ = append_type(NULL, $1); } + | qualified_type '*' { $$ = append_type(NULL, type_new_pointer($1)); } + | parameterized_type { $$ = append_type(NULL, $1); } + | parameterized_type '*' { $$ = append_type(NULL, type_new_pointer($1)); } + | parameterized_types ',' parameterized_types + { $$ = append_types($1, $3); } + ; + coclass: tCOCLASS typename { $$ = type_coclass_declare($2); } ;
@@ -965,6 +982,7 @@ dispinterfacedef:
inherit: { $$ = NULL; } | ':' qualified_type { $$ = $2; } + | ':' parameterized_type { $$ = $2; } ;
type_parameter: typename { $$ = get_type(TYPE_PARAMETER, $1, parameters_namespace, 0); } @@ -983,7 +1001,9 @@ interface:
required_types: qualified_type { $$ = append_ifref(NULL, make_ifref($1)); } + | parameterized_type { $$ = append_ifref(NULL, make_ifref($1)); } | required_types ',' qualified_type { $$ = append_ifref($1, make_ifref($3)); } + | required_types ',' parameterized_type { $$ = append_ifref($1, make_ifref($3)); }
requires: { $$ = NULL; } | tREQUIRES required_types { $$ = $2; } @@ -1207,6 +1227,7 @@ unqualified_type: type: unqualified_type | namespace_pfx typename { $$ = find_type_or_error($1, $2); } + | parameterized_type { $$ = $1; } ;
typedef: m_attributes tTYPEDEF m_attributes decl_spec declarator_list @@ -1839,6 +1860,16 @@ static type_list_t *append_type(type_list_t *list, type_t *type) 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; @@ -3268,3 +3299,19 @@ void init_loc_info(loc_info_t *i) i->line_number = line_number; i->near_text = parser_text; } + +type_t *find_parameterized_type(type_t *type, type_list_t *params) +{ + char *name = format_parameterized_type_name(type, params); + + if (parameters_namespace) + { + assert(type->type_type == TYPE_PARAMETERIZED_TYPE); + type = type_parameterized_type_specialize_partial(type, params); + } + /* FIXME: If not in another parameterized type, we'll have to look for the declared specialization. */ + else error_loc("parameterized type '%s' not declared\n", name); + + free(name); + return type; +} diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c index 203fffcdee6..22c75d32161 100644 --- a/tools/widl/typetree.c +++ b/tools/widl/typetree.c @@ -100,13 +100,40 @@ static size_t append_namespace(char **buf, size_t *len, size_t pos, struct names return n; }
+static size_t append_namespaces(char **buf, size_t *len, size_t pos, struct namespace *namespace, const char *prefix, + const char *separator, const char *suffix, const char *abi_prefix) +{ + size_t n = 0; + n += strappend(buf, len, pos + n, "%s", prefix); + n += append_namespace(buf, len, pos + n, namespace, separator, abi_prefix); + n += strappend(buf, len, pos + n, "%s", suffix); + return n; +} + char *format_namespace(struct namespace *namespace, const char *prefix, const char *separator, const char *suffix, const char *abi_prefix) +{ + size_t len = 0; + char *buf = NULL; + append_namespaces(&buf, &len, 0, namespace, prefix, separator, suffix, abi_prefix); + return buf; +} + +char *format_parameterized_type_name(type_t *type, type_list_t *params) { size_t len = 0, pos = 0; char *buf = NULL; - pos += strappend(&buf, &len, pos, "%s", prefix); - pos += append_namespace(&buf, &len, pos, namespace, separator, abi_prefix); - pos += strappend(&buf, &len, pos, "%s", suffix); + type_list_t *entry; + + pos += strappend(&buf, &len, pos, "%s<", type->name); + for (entry = params; entry; entry = entry->next) + { + for (type = entry->type; type->type_type == TYPE_POINTER; type = type_pointer_get_ref_type(type)) {} + pos += append_namespaces(&buf, &len, pos, type->namespace, "", "::", type->name, use_abi_namespace ? "ABI" : NULL); + for (type = entry->type; type->type_type == TYPE_POINTER; type = type_pointer_get_ref_type(type)) pos += strappend(&buf, &len, pos, "*"); + if (entry->next) pos += strappend(&buf, &len, pos, ","); + } + pos += strappend(&buf, &len, pos, ">"); + return buf; }
@@ -642,6 +669,14 @@ type_t *type_parameterized_interface_define(type_t *type, attr_list_t *attrs, ty return type; }
+type_t *type_parameterized_type_specialize_partial(type_t *type, type_list_t *params) +{ + type_t *new_type = duptype(type, 0); + new_type->details.parameterized.type = type; + new_type->details.parameterized.params = params; + return new_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 96b681e0379..52ae2ec8677 100644 --- a/tools/widl/typetree.h +++ b/tools/widl/typetree.h @@ -36,6 +36,8 @@ attr_list_t *check_interface_attrs(const char *name, attr_list_t *attrs); attr_list_t *check_module_attrs(const char *name, attr_list_t *attrs); attr_list_t *check_runtimeclass_attrs(const char *name, attr_list_t *attrs);
+type_t *find_parameterized_type(type_t *type, type_list_t *params); + type_t *type_new_function(var_list_t *args); type_t *type_new_pointer(type_t *ref); type_t *type_new_alias(const decl_spec_t *t, const char *name); @@ -64,6 +66,7 @@ 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); +type_t *type_parameterized_type_specialize_partial(type_t *type, type_list_t *params); 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); diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h index 7596577493d..ce48567d583 100644 --- a/tools/widl/widltypes.h +++ b/tools/widl/widltypes.h @@ -650,6 +650,7 @@ void init_loc_info(loc_info_t *);
char *format_namespace(struct namespace *namespace, const char *prefix, const char *separator, const char *suffix, const char *abi_prefix); +char *format_parameterized_type_name(type_t *type, type_list_t *params);
static inline enum type_type type_get_type_detect_alias(const type_t *type) {
Hi Rémi,
On 11.02.2021 17:37, Rémi Bernon wrote:
+parameterized_type: qualified_type '<' parameterized_types '>'
{ $$ = find_parameterized_type($1, $3); }
- ;
+parameterized_types:
base_type { $$ = append_type(NULL, $1); }
- | qualified_type { $$ = append_type(NULL, $1); }
- | qualified_type '*' { $$ = append_type(NULL, type_new_pointer($1)); }
- | parameterized_type { $$ = append_type(NULL, $1); }
- | parameterized_type '*' { $$ = append_type(NULL, type_new_pointer($1)); }
- | parameterized_types ',' parameterized_types
{ $$ = append_types($1, $3); }
- ;
Naming here is a bit unfortunate, in my opinion. I'd expect parameterized_types to be a list of parameterized_type or something like that, but it's quite not how it's used. I already got it wrong while this reading the patch, so it would be great to make it cleaner.
Thanks,
Jacek
On 2/11/21 6:13 PM, Jacek Caban wrote:
Hi Rémi,
On 11.02.2021 17:37, Rémi Bernon wrote:
+parameterized_type: qualified_type '<' parameterized_types '>' + { $$ = find_parameterized_type($1, $3); } + ;
+parameterized_types: + base_type { $$ = append_type(NULL, $1); } + | qualified_type { $$ = append_type(NULL, $1); } + | qualified_type '*' { $$ = append_type(NULL, type_new_pointer($1)); } + | parameterized_type { $$ = append_type(NULL, $1); } + | parameterized_type '*' { $$ = append_type(NULL, type_new_pointer($1)); } + | parameterized_types ',' parameterized_types + { $$ = append_types($1, $3); } + ;
Naming here is a bit unfortunate, in my opinion. I'd expect parameterized_types to be a list of parameterized_type or something like that, but it's quite not how it's used. I already got it wrong while this reading the patch, so it would be great to make it cleaner.
Thanks,
Jacek
Right, I'll try to find something better.
This allows parameterized interfaces to be instanciated in declare blocks, in the same way MIDL does. It generates new interfaces in the header from the parameterized type template, replacing its parameters with the given types.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- include/windows.media.speechsynthesis.idl | 24 +++ tools/widl/header.c | 7 +- tools/widl/parser.l | 1 + tools/widl/parser.y | 63 +++++- tools/widl/typetree.c | 238 ++++++++++++++++++++++ tools/widl/typetree.h | 2 + 6 files changed, 330 insertions(+), 5 deletions(-)
diff --git a/include/windows.media.speechsynthesis.idl b/include/windows.media.speechsynthesis.idl index 87497678f30..af4466681dc 100644 --- a/include/windows.media.speechsynthesis.idl +++ b/include/windows.media.speechsynthesis.idl @@ -35,11 +35,24 @@ namespace Windows { interface ISpeechSynthesizer; interface ISpeechSynthesizer2; interface IVoiceInformation; + runtimeclass SpeechSynthesizer; runtimeclass VoiceInformation; } } }
+namespace Windows { + namespace Media { + namespace SpeechSynthesis { + declare { + interface Windows.Foundation.Collections.IIterator<Windows.Media.SpeechSynthesis.VoiceInformation*>; + interface Windows.Foundation.Collections.IIterable<Windows.Media.SpeechSynthesis.VoiceInformation*>; + interface Windows.Foundation.Collections.IVectorView<Windows.Media.SpeechSynthesis.VoiceInformation*>; + } + } + } +} + namespace Windows { namespace Media { namespace SpeechSynthesis { @@ -64,6 +77,17 @@ namespace Windows { [propget] HRESULT Gender([out] [retval] VoiceGender* value); }
+ [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Media.SpeechSynthesis.SpeechSynthesizer), + uuid(7d526ecc-7533-4c3f-85be-888c2baeebdc) + ] + interface IInstalledVoicesStatic : IInspectable + { + [propget] HRESULT AllVoices([out, retval] Windows.Foundation.Collections.IVectorView<VoiceInformation*>** value); + [propget] HRESULT DefaultVoice([out, retval] VoiceInformation** value); + } + [ contract(Windows.Foundation.UniversalApiContract, 1.0), marshaling_behavior(agile) diff --git a/tools/widl/header.c b/tools/widl/header.c index 8423756e060..a4f1db56a01 100644 --- a/tools/widl/header.c +++ b/tools/widl/header.c @@ -1479,7 +1479,8 @@ static void write_forward(FILE *header, type_t *iface) fprintf(header, "typedef interface %s %s;\n", iface->c_name, iface->c_name); fprintf(header, "#ifdef __cplusplus\n"); write_namespace_start(header, iface->namespace); - write_line(header, 0, "interface %s;", iface->name); + if (strchr(iface->name, '<')) write_line(header, 0, "template<> struct %s;", iface->name); + else write_line(header, 0, "interface %s;", iface->name); write_namespace_end(header, iface->namespace); fprintf(header, "#endif /* __cplusplus */\n"); fprintf(header, "#endif\n\n" ); @@ -1548,11 +1549,13 @@ static void write_com_interface_end(FILE *header, type_t *iface) write_namespace_start(header, iface->namespace); } if (uuid) { + if (strchr(iface->name, '<')) write_line(header, 0, "template<>"); write_line(header, 0, "MIDL_INTERFACE("%s")", uuid_string(uuid)); indent(header, 0); }else { indent(header, 0); - fprintf(header, "interface "); + if (strchr(iface->name, '<')) fprintf(header, "template<> struct "); + else fprintf(header, "interface "); } if (type_iface_get_inherit(iface)) { diff --git a/tools/widl/parser.l b/tools/widl/parser.l index 946dba84cd6..d319954edd3 100644 --- a/tools/widl/parser.l +++ b/tools/widl/parser.l @@ -276,6 +276,7 @@ static const struct keyword keywords[] = { {"coclass", tCOCLASS, 0}, {"const", tCONST, 0}, {"cpp_quote", tCPPQUOTE, 0}, + {"declare", tDECLARE, 1}, {"default", tDEFAULT, 0}, {"dispinterface", tDISPINTERFACE, 0}, {"double", tDOUBLE, 0}, diff --git a/tools/widl/parser.y b/tools/widl/parser.y index 7ef16d90456..345530b495a 100644 --- a/tools/widl/parser.y +++ b/tools/widl/parser.y @@ -81,6 +81,7 @@ static void pop_namespace(const char *name); static void push_parameters_namespace(const char *name); static void pop_parameters_namespace(const char *name);
+static statement_list_t *append_parameterized_type_stmts(statement_list_t *stmts); static void check_arg_attrs(const var_t *arg); static void check_statements(const statement_list_t *stmts, int is_inside_library); static void check_all_user_types(const statement_list_t *stmts); @@ -108,6 +109,7 @@ static statement_t *make_statement_importlib(const char *str); 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_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 *); @@ -118,6 +120,7 @@ static struct namespace global_namespace = {
static struct namespace *current_namespace = &global_namespace; static struct namespace *parameters_namespace = NULL; +static statement_list_t *parameterized_type_stmts = NULL;
static typelib_t *current_typelib;
@@ -180,6 +183,7 @@ static typelib_t *current_typelib; %token tCONTRACTVERSION %token tCONTROL tCPPQUOTE %token tCUSTOM +%token tDECLARE %token tDECODE tDEFAULT tDEFAULTBIND %token tDEFAULTCOLLELEM %token tDEFAULTVALUE @@ -320,6 +324,8 @@ static typelib_t *current_typelib; %type <typelib> library_start librarydef %type <statement> statement typedef pragma_warning %type <stmt_list> gbl_statements imp_statements int_statements +%type <stmt_list> decl_block decl_statements +%type <stmt_list> imp_decl_block imp_decl_statements %type <warning_list> warnings %type <num> allocate_option_list allocate_option %type <namespace> namespace_pfx @@ -343,7 +349,8 @@ static typelib_t *current_typelib;
%%
-input: gbl_statements m_acf { check_statements($1, FALSE); +input: gbl_statements m_acf { $1 = append_parameterized_type_stmts($1); + check_statements($1, FALSE); check_all_user_types($1); write_header($1); write_id_data($1); @@ -359,6 +366,22 @@ input: gbl_statements m_acf { check_statements($1, FALSE);
m_acf: /* empty */ | aACF acf_statements
+decl_statements: { $$ = NULL; } + | decl_statements tINTERFACE qualified_type '<' parameterized_types '>' ';' + { parameterized_type_stmts = append_statement(parameterized_type_stmts, make_statement_parameterized_type($3, $5)); + $$ = append_statement($1, make_statement_reference(type_parameterized_type_specialize_declare($3, $5))); + } + ; + +decl_block: tDECLARE '{' decl_statements '}' { $$ = $3; } + +imp_decl_statements: { $$ = NULL; } + | imp_decl_statements tINTERFACE qualified_type '<' parameterized_types '>' ';' + { $$ = append_statement($1, make_statement_reference(type_parameterized_type_specialize_declare($3, $5))); } + ; + +imp_decl_block: tDECLARE '{' imp_decl_statements '}' { $$ = $3; } + gbl_statements: { $$ = NULL; } | gbl_statements namespacedef '{' { push_namespace($2); } gbl_statements '}' { pop_namespace($2); $$ = append_statements($1, $5); } @@ -380,6 +403,7 @@ gbl_statements: { $$ = NULL; } | gbl_statements moduledef { $$ = append_statement($1, make_statement_module($2)); } | gbl_statements librarydef { $$ = append_statement($1, make_statement_library($2)); } | gbl_statements statement { $$ = append_statement($1, $2); } + | gbl_statements decl_block { $$ = append_statements($1, $2); } ;
imp_statements: { $$ = NULL; } @@ -402,6 +426,7 @@ imp_statements: { $$ = NULL; } | imp_statements statement { $$ = append_statement($1, $2); } | imp_statements importlib { $$ = append_statement($1, make_statement_importlib($2)); } | imp_statements librarydef { $$ = append_statement($1, make_statement_library($2)); } + | imp_statements imp_decl_block { $$ = append_statements($1, $2); } ;
int_statements: { $$ = NULL; } @@ -3084,6 +3109,27 @@ static void check_async_uuid(type_t *iface) iface->details.iface->async_iface = async_iface->details.iface->async_iface = async_iface; }
+static statement_list_t *append_parameterized_type_stmts(statement_list_t *stmts) +{ + statement_t *stmt, *next; + if (stmts && parameterized_type_stmts) LIST_FOR_EACH_ENTRY_SAFE(stmt, next, parameterized_type_stmts, statement_t, entry) + { + switch(stmt->type) { + case STMT_TYPE: + stmt->u.type = type_parameterized_type_specialize_define(stmt->u.type_list->type, stmt->u.type_list->next); + stmt->declonly = FALSE; + list_remove(&stmt->entry); + stmts = append_statement(stmts, stmt); + break; + default: + assert(0); /* should not be there */ + break; + } + } + + return stmts; +} + static void check_statements(const statement_list_t *stmts, int is_inside_library) { const statement_t *stmt; @@ -3265,6 +3311,15 @@ static statement_t *make_statement_typedef(declarator_list_t *decls, int declonl return stmt; }
+static statement_t *make_statement_parameterized_type(type_t *type, type_list_t *params) +{ + statement_t *stmt = make_statement(STMT_TYPE); + stmt->u.type_list = xmalloc(sizeof(type_list_t)); + stmt->u.type_list->type = type; + stmt->u.type_list->next = params; + return stmt; +} + static statement_list_t *append_statements(statement_list_t *l1, statement_list_t *l2) { if (!l2) return l1; @@ -3309,8 +3364,10 @@ type_t *find_parameterized_type(type_t *type, type_list_t *params) assert(type->type_type == TYPE_PARAMETERIZED_TYPE); type = type_parameterized_type_specialize_partial(type, params); } - /* FIXME: If not in another parameterized type, we'll have to look for the declared specialization. */ - else error_loc("parameterized type '%s' not declared\n", name); + else if ((type = find_type(name, type->namespace, 0))) + assert(type->type_type != TYPE_PARAMETERIZED_TYPE); + else + error_loc("parameterized type '%s' not declared\n", name);
free(name); return type; diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c index 22c75d32161..58b019cc090 100644 --- a/tools/widl/typetree.c +++ b/tools/widl/typetree.c @@ -137,6 +137,41 @@ char *format_parameterized_type_name(type_t *type, type_list_t *params) return buf; }
+static char const *parameterized_type_shorthands[][2] = { + {"Windows_CFoundation_CCollections_C", "__F"}, + {"Windows_CFoundation_C", "__F"}, +}; + +static char *format_parameterized_type_c_name(type_t *type, type_list_t *params) +{ + size_t len = 0, pos = 0; + char *buf = NULL, *tmp; + type_list_t *entry; + int i, count = 0; + + pos += append_namespaces(&buf, &len, pos, type->namespace, "__x_", "_C", type->name, use_abi_namespace ? "ABI" : NULL); + for (entry = params; entry; entry = entry->next) count++; + pos += strappend(&buf, &len, pos, "_%d", count); + for (entry = params; entry; entry = entry->next) + { + for (type = entry->type; type->type_type == TYPE_POINTER; type = type_pointer_get_ref_type(type)) {} + pos += append_namespaces(&buf, &len, pos, type->namespace, "_", "__C", type->name, NULL); + } + + for (i = 0; i < ARRAY_SIZE(parameterized_type_shorthands); ++i) + { + if ((tmp = strstr(buf, parameterized_type_shorthands[i][0])) && + (tmp - buf) == strlen(use_abi_namespace ? "__x_ABI_C" : "__x_C")) + { + tmp += strlen(parameterized_type_shorthands[i][0]); + strcpy(buf, parameterized_type_shorthands[i][1]); + memmove(buf + 3, tmp, len - (tmp - buf) + 1); + } + } + + return buf; +} + type_t *type_new_function(var_list_t *args) { var_t *arg; @@ -677,6 +712,209 @@ type_t *type_parameterized_type_specialize_partial(type_t *type, type_list_t *pa return new_type; }
+static type_t *replace_type_parameters_in_type(type_t *type, type_list_t *orig, type_list_t *repl); + +static type_list_t *replace_type_parameters_in_type_list(type_list_t *type_list, type_list_t *orig, type_list_t *repl) +{ + type_list_t *entry, *new_entry, **next, *first = NULL; + + if (!type_list) return type_list; + + next = &first; + for (entry = type_list; entry; entry = entry->next) + { + new_entry = xmalloc(sizeof(*new_entry)); + new_entry->type = replace_type_parameters_in_type(entry->type, orig, repl); + new_entry->next = NULL; + *next = new_entry; + next = &new_entry->next; + } + + return first; +} + +static var_t *replace_type_parameters_in_var(var_t *var, type_list_t *orig, type_list_t *repl) +{ + var_t *new_var = xmalloc(sizeof(*new_var)); + *new_var = *var; + list_init(&new_var->entry); + new_var->declspec.type = replace_type_parameters_in_type(var->declspec.type, orig, repl); + return new_var; +} + +static var_list_t *replace_type_parameters_in_var_list(var_list_t *var_list, type_list_t *orig, type_list_t *repl) +{ + var_list_t *new_var_list; + var_t *var, *new_var; + + if (!var_list) return var_list; + + new_var_list = xmalloc(sizeof(*new_var_list)); + list_init(new_var_list); + + LIST_FOR_EACH_ENTRY(var, var_list, var_t, entry) + { + new_var = replace_type_parameters_in_var(var, orig, repl); + list_add_tail(new_var_list, &new_var->entry); + } + + return new_var_list; +} + +static statement_t *replace_type_parameters_in_statement(statement_t *stmt, type_list_t *orig, type_list_t *repl) +{ + statement_t *new_stmt = xmalloc(sizeof(*new_stmt)); + *new_stmt = *stmt; + list_init(&new_stmt->entry); + + switch (stmt->type) + { + case STMT_DECLARATION: + new_stmt->u.var = replace_type_parameters_in_var(stmt->u.var, orig, repl); + break; + case STMT_LIBRARY: + case STMT_TYPE: + case STMT_TYPEREF: + case STMT_MODULE: + case STMT_TYPEDEF: + new_stmt->u.type_list = replace_type_parameters_in_type_list(stmt->u.type_list, orig, repl); + break; + case STMT_IMPORT: + case STMT_IMPORTLIB: + case STMT_PRAGMA: + case STMT_CPPQUOTE: + fprintf(stderr, "%d\n", stmt->type); + assert(0); + break; + } + + return new_stmt; +} + +static statement_list_t *replace_type_parameters_in_statement_list(statement_list_t *stmt_list, type_list_t *orig, type_list_t *repl) +{ + statement_list_t *new_stmt_list; + statement_t *stmt, *new_stmt; + + if (!stmt_list) return stmt_list; + + new_stmt_list = xmalloc(sizeof(*new_stmt_list)); + list_init(new_stmt_list); + + LIST_FOR_EACH_ENTRY(stmt, stmt_list, statement_t, entry) + { + new_stmt = replace_type_parameters_in_statement(stmt, orig, repl); + list_add_tail(new_stmt_list, &new_stmt->entry); + } + + return new_stmt_list; +} + +static type_t *replace_type_parameters_in_type(type_t *type, type_list_t *orig, type_list_t *repl) +{ + type_list_t *o, *r; + type_t *t; + + if (!type) return type; + switch (type->type_type) + { + case TYPE_VOID: + case TYPE_BASIC: + case TYPE_ENUM: + case TYPE_BITFIELD: + case TYPE_INTERFACE: + case TYPE_RUNTIMECLASS: + return type; + case TYPE_PARAMETER: + for (o = orig, r = repl; o && r; o = o->next, r = r->next) + if (type == o->type) return r->type; + return type; + case TYPE_POINTER: + t = replace_type_parameters_in_type(type->details.pointer.ref.type, orig, repl); + if (t == type->details.pointer.ref.type) return type; + type = duptype(type, 0); + type->details.pointer.ref.type = t; + return type; + case TYPE_ALIAS: + t = replace_type_parameters_in_type(type->details.alias.aliasee.type, orig, repl); + if (t == type->details.alias.aliasee.type) return type; + type = duptype(type, 0); + type->details.alias.aliasee.type = t; + return type; + case TYPE_ARRAY: + t = replace_type_parameters_in_type(type->details.array.elem.type, orig, repl); + if (t == t->details.array.elem.type) return type; + type = duptype(type, 0); + t->details.array.elem.type = t; + return type; + case TYPE_FUNCTION: + t = duptype(type, 0); + t->details.function = xmalloc(sizeof(*t->details.function)); + t->details.function->args = replace_type_parameters_in_var_list(type->details.function->args, orig, repl); + t->details.function->retval = replace_type_parameters_in_var(type->details.function->retval, orig, repl); + return t; + case TYPE_PARAMETERIZED_TYPE: + t = type->details.parameterized.type; + if (t->type_type != TYPE_PARAMETERIZED_TYPE) return find_parameterized_type(type, repl); + repl = replace_type_parameters_in_type_list(type->details.parameterized.params, orig, repl); + return replace_type_parameters_in_type(t, t->details.parameterized.params, repl); + case TYPE_STRUCT: + case TYPE_ENCAPSULATED_UNION: + case TYPE_UNION: + case TYPE_MODULE: + case TYPE_COCLASS: + case TYPE_APICONTRACT: + assert(0); /* FIXME: implement when needed */ + break; + } + + return type; +} + +static void type_parameterized_interface_specialize(type_t *tmpl, type_t *iface, type_list_t *orig, type_list_t *repl) +{ + iface->details.iface = xmalloc(sizeof(*iface->details.iface)); + iface->details.iface->disp_methods = NULL; + iface->details.iface->disp_props = NULL; + iface->details.iface->stmts = replace_type_parameters_in_statement_list(tmpl->details.iface->stmts, orig, repl); + iface->details.iface->inherit = replace_type_parameters_in_type(tmpl->details.iface->inherit, orig, repl); + iface->details.iface->disp_inherit = NULL; + iface->details.iface->async_iface = NULL; + iface->details.iface->requires = NULL; +} + +type_t *type_parameterized_type_specialize_declare(type_t *type, type_list_t *params) +{ + type_t *tmpl = type->details.parameterized.type; + type_t *new_type = duptype(tmpl, 0); + + new_type->namespace = type->namespace; + new_type->name = format_parameterized_type_name(type, params); + reg_type(new_type, new_type->name, new_type->namespace, 0); + new_type->c_name = format_parameterized_type_c_name(type, params); + + return new_type; +} + +type_t *type_parameterized_type_specialize_define(type_t *type, type_list_t *params) +{ + type_list_t *orig = type->details.parameterized.params; + type_t *tmpl = type->details.parameterized.type; + type_t *iface = find_parameterized_type(type, params); + + if (tmpl->type_type == TYPE_INTERFACE) + type_parameterized_interface_specialize(tmpl, iface, orig, params); + else + { + error_loc("Unsupported parameterized type template %d\n", tmpl->type_type); + return NULL; + } + + iface->defined = TRUE; + compute_method_indexes(iface); + return iface; +} + 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 52ae2ec8677..0dc75dff62e 100644 --- a/tools/widl/typetree.h +++ b/tools/widl/typetree.h @@ -67,6 +67,8 @@ 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); type_t *type_parameterized_type_specialize_partial(type_t *type, type_list_t *params); +type_t *type_parameterized_type_specialize_declare(type_t *type, type_list_t *params); +type_t *type_parameterized_type_specialize_define(type_t *type, type_list_t *params); 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);