#include "expr.h"
#include "typetree.h"
-static unsigned char pointer_default = RPC_FC_UP;
+static unsigned char pointer_default = FC_UP;
typedef struct list typelist_t;
struct typenode {
static attr_t *make_attrv(enum attr_type type, unsigned int val);
static attr_t *make_attrp(enum attr_type type, void *val);
static expr_list_t *append_expr(expr_list_t *list, expr_t *expr);
-static array_dims_t *append_array(array_dims_t *list, expr_t *expr);
+static type_t *append_array(type_t *chain, expr_t *expr);
static var_t *declare_var(attr_list_t *attrs, decl_spec_t *decl_spec, const declarator_t *decl, int top);
static var_list_t *set_var_types(attr_list_t *attrs, decl_spec_t *decl_spec, declarator_list_t *decls);
static ifref_list_t *append_ifref(ifref_list_t *list, ifref_t *iface);
static declarator_t *make_declarator(var_t *var);
static type_t *make_safearray(type_t *type);
static typelib_t *make_library(const char *name, const attr_list_t *attrs);
-static type_t *append_ptrchain_type(type_t *ptrchain, type_t *type);
+static type_t *append_chain_type(type_t *chain, type_t *type);
static warning_list_t *append_warning(warning_list_t *, int);
static type_t *reg_typedefs(decl_spec_t *decl_spec, var_list_t *names, attr_list_t *attrs);
static void add_explicit_handle_if_necessary(const type_t *iface, var_t *func);
static void check_def(const type_t *t);
+static void check_async_uuid(type_t *iface);
+
static statement_t *make_statement(enum statement_type type);
static statement_t *make_statement_type_decl(type_t *type);
static statement_t *make_statement_reference(type_t *type);
static struct namespace *current_namespace = &global_namespace;
+#ifndef __REACTOS__
+static typelib_t *current_typelib;
+#endif
+
%}
%union {
attr_t *attr;
str_list_t *str_list;
expr_t *expr;
expr_list_t *expr_list;
- array_dims_t *array_dims;
type_t *type;
var_t *var;
var_list_t *var_list;
%token <dbl> aDOUBLE
%token <str> aSTRING aWSTRING aSQSTRING
%token <uuid> aUUID
-%token aEOF
+%token aEOF aACF
%token SHL SHR
%token MEMBERPTR
%token EQUALITY INEQUALITY
%token tIMPORT tIMPORTLIB
%token tIN tIN_LINE tINLINE
%token tINPUTSYNC
-%token tINT tINT3264 tINT64
+%token tINT tINT32 tINT3264 tINT64
%token tINTERFACE
%token tLCID
%token tLENGTHIS tLIBRARY
%token tWCHAR tWIREMARSHAL
%token tAPARTMENT tNEUTRAL tSINGLE tFREE tBOTH
-%type <attr> attribute type_qualifier function_specifier
+%type <attr> attribute type_qualifier function_specifier acf_attribute
%type <attr_list> m_attributes attributes attrib_list m_type_qual_list
+%type <attr_list> acf_attributes acf_attribute_list
%type <str_list> str_list
%type <expr> m_expr expr expr_const expr_int_const array m_bitfield
%type <expr_list> m_exprs /* exprs expr_list */ expr_list_int_const
%%
-input: gbl_statements { fix_incomplete();
+input: gbl_statements m_acf { fix_incomplete();
check_statements($1, FALSE);
check_all_user_types($1);
write_header($1);
write_client($1);
write_server($1);
write_regscript($1);
+#ifndef __REACTOS__
+ write_typelib_regscript($1);
+#endif
write_dlldata($1);
write_local_stubs($1);
}
;
+m_acf: /* empty */ | aACF acf_statements
+
gbl_statements: { $$ = NULL; }
| gbl_statements namespacedef '{' { push_namespace($2); } gbl_statements '}'
{ pop_namespace($2); $$ = append_statements($1, $5); }
;
importlib: tIMPORTLIB '(' aSTRING ')'
+/* ifdef __REACTOS__ */
semicolon_opt { $$ = $3; if(!parse_only) add_importlib($3); }
+/* else
+ semicolon_opt { $$ = $3; if(!parse_only) add_importlib($3, current_typelib); }
+*/
;
libraryhdr: tLIBRARY aIDENTIFIER { $$ = $2; }
| tLIBRARY aKNOWNTYPE { $$ = $2; }
;
library_start: attributes libraryhdr '{' { $$ = make_library($2, check_library_attrs($2, $1));
+/* ifdef __REACTOS__ */
if (!parse_only) start_typelib($$);
+/* else
+ if (!parse_only && do_typelib) current_typelib = $$;
+*/
}
;
librarydef: library_start imp_statements '}'
+/* ifdef __REACTOS__ */
semicolon_opt { $$ = $1;
$$->stmts = $2;
if (!parse_only) end_typelib();
}
+/* else
+ semicolon_opt { $$ = $1; $$->stmts = $2; }
+*/
;
m_args: { $$ = NULL; }
;
array: '[' expr ']' { $$ = $2;
- if (!$$->is_const)
- error_loc("array dimension is not an integer constant\n");
+ if (!$$->is_const || $$->cval <= 0)
+ error_loc("array dimension is not a positive integer constant\n");
}
| '[' '*' ']' { $$ = make_expr(EXPR_VOID); }
| '[' ']' { $$ = make_expr(EXPR_VOID); }
int_std: tINT { $$ = type_new_int(TYPE_BASIC_INT, 0); }
| tSHORT m_int { $$ = type_new_int(TYPE_BASIC_INT16, 0); }
| tSMALL { $$ = type_new_int(TYPE_BASIC_INT8, 0); }
- | tLONG m_int { $$ = type_new_int(TYPE_BASIC_INT32, 0); }
+ | tLONG m_int { $$ = type_new_int(TYPE_BASIC_LONG, 0); }
| tHYPER m_int { $$ = type_new_int(TYPE_BASIC_HYPER, 0); }
| tINT64 { $$ = type_new_int(TYPE_BASIC_INT64, 0); }
| tCHAR { $$ = type_new_int(TYPE_BASIC_CHAR, 0); }
+ | tINT32 { $$ = type_new_int(TYPE_BASIC_INT32, 0); }
| tINT3264 { $$ = type_new_int(TYPE_BASIC_INT3264, 0); }
;
if($$ == $2)
error_loc("Interface can't inherit from itself\n");
type_interface_define($$, $2, $4);
+ check_async_uuid($$);
pointer_default = $1.old_pointer_default;
}
/* MIDL is able to import the definition of a base class from inside the
declarator:
'*' m_type_qual_list declarator %prec PPTR
- { $$ = $3; $$->type = append_ptrchain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
+ { $$ = $3; $$->type = append_chain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
| callconv declarator { $$ = $2; if ($$->func_type) $$->func_type->attrs = append_attr($$->func_type->attrs, make_attrp(ATTR_CALLCONV, $1));
else if ($$->type) $$->type->attrs = append_attr($$->type->attrs, make_attrp(ATTR_CALLCONV, $1)); }
| direct_declarator
direct_declarator:
ident { $$ = make_declarator($1); }
| '(' declarator ')' { $$ = $2; }
- | direct_declarator array { $$ = $1; $$->array = append_array($$->array, $2); }
+ | direct_declarator array { $$ = $1; $$->type = append_array($$->type, $2); }
| direct_declarator '(' m_args ')' { $$ = $1;
- $$->func_type = append_ptrchain_type($$->type, type_new_function($3));
+ $$->func_type = append_chain_type($$->type, type_new_function($3));
$$->type = NULL;
}
;
/* abstract declarator */
abstract_declarator:
'*' m_type_qual_list m_abstract_declarator %prec PPTR
- { $$ = $3; $$->type = append_ptrchain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
+ { $$ = $3; $$->type = append_chain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
| callconv m_abstract_declarator { $$ = $2; if ($$->func_type) $$->func_type->attrs = append_attr($$->func_type->attrs, make_attrp(ATTR_CALLCONV, $1));
else if ($$->type) $$->type->attrs = append_attr($$->type->attrs, make_attrp(ATTR_CALLCONV, $1)); }
| abstract_direct_declarator
/* abstract declarator without accepting direct declarator */
abstract_declarator_no_direct:
'*' m_type_qual_list m_any_declarator %prec PPTR
- { $$ = $3; $$->type = append_ptrchain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
+ { $$ = $3; $$->type = append_chain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
| callconv m_any_declarator { $$ = $2; if ($$->func_type) $$->func_type->attrs = append_attr($$->func_type->attrs, make_attrp(ATTR_CALLCONV, $1));
else if ($$->type) $$->type->attrs = append_attr($$->type->attrs, make_attrp(ATTR_CALLCONV, $1)); }
;
/* abstract direct declarator */
abstract_direct_declarator:
'(' abstract_declarator_no_direct ')' { $$ = $2; }
- | abstract_direct_declarator array { $$ = $1; $$->array = append_array($$->array, $2); }
- | array { $$ = make_declarator(NULL); $$->array = append_array($$->array, $1); }
+ | abstract_direct_declarator array { $$ = $1; $$->type = append_array($$->type, $2); }
+ | array { $$ = make_declarator(NULL); $$->type = append_array($$->type, $1); }
| '(' m_args ')'
{ $$ = make_declarator(NULL);
- $$->func_type = append_ptrchain_type($$->type, type_new_function($2));
+ $$->func_type = append_chain_type($$->type, type_new_function($2));
$$->type = NULL;
}
| abstract_direct_declarator '(' m_args ')'
{ $$ = $1;
- $$->func_type = append_ptrchain_type($$->type, type_new_function($3));
+ $$->func_type = append_chain_type($$->type, type_new_function($3));
$$->type = NULL;
}
;
/* abstract or non-abstract declarator */
any_declarator:
'*' m_type_qual_list m_any_declarator %prec PPTR
- { $$ = $3; $$->type = append_ptrchain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
+ { $$ = $3; $$->type = append_chain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
| callconv m_any_declarator { $$ = $2; $$->type->attrs = append_attr($$->type->attrs, make_attrp(ATTR_CALLCONV, $1)); }
| any_direct_declarator
;
/* abstract or non-abstract declarator without accepting direct declarator */
any_declarator_no_direct:
'*' m_type_qual_list m_any_declarator %prec PPTR
- { $$ = $3; $$->type = append_ptrchain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
+ { $$ = $3; $$->type = append_chain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
| callconv m_any_declarator { $$ = $2; $$->type->attrs = append_attr($$->type->attrs, make_attrp(ATTR_CALLCONV, $1)); }
;
any_direct_declarator:
ident { $$ = make_declarator($1); }
| '(' any_declarator_no_direct ')' { $$ = $2; }
- | any_direct_declarator array { $$ = $1; $$->array = append_array($$->array, $2); }
- | array { $$ = make_declarator(NULL); $$->array = append_array($$->array, $1); }
+ | any_direct_declarator array { $$ = $1; $$->type = append_array($$->type, $2); }
+ | array { $$ = make_declarator(NULL); $$->type = append_array($$->type, $1); }
| '(' m_args ')'
{ $$ = make_declarator(NULL);
- $$->func_type = append_ptrchain_type($$->type, type_new_function($2));
+ $$->func_type = append_chain_type($$->type, type_new_function($2));
$$->type = NULL;
}
| any_direct_declarator '(' m_args ')'
{ $$ = $1;
- $$->func_type = append_ptrchain_type($$->type, type_new_function($3));
+ $$->func_type = append_chain_type($$->type, type_new_function($3));
$$->type = NULL;
}
;
;
pointer_type:
- tREF { $$ = RPC_FC_RP; }
- | tUNIQUE { $$ = RPC_FC_UP; }
- | tPTR { $$ = RPC_FC_FP; }
+ tREF { $$ = FC_RP; }
+ | tUNIQUE { $$ = FC_UP; }
+ | tPTR { $$ = FC_FP; }
;
structdef: tSTRUCT t_ident '{' fields '}' { $$ = type_new_struct($2, current_namespace, TRUE, $4); }
| aHEXNUM { $$ = $1; }
;
+acf_statements
+ : /* empty */
+ | acf_interface acf_statements
+
+acf_int_statements
+ : /* empty */
+ | acf_int_statement acf_int_statements
+
+acf_int_statement
+ : tTYPEDEF acf_attributes aKNOWNTYPE ';'
+ { type_t *type = find_type_or_error($3, 0);
+ type->attrs = append_attr_list(type->attrs, $2);
+ }
+acf_interface
+ : acf_attributes tINTERFACE aKNOWNTYPE '{' acf_int_statements '}'
+ { type_t *iface = find_type_or_error2($3, 0);
+ if (type_get_type(iface) != TYPE_INTERFACE)
+ error_loc("%s is not an interface\n", iface->name);
+ iface->attrs = append_attr_list(iface->attrs, $1);
+ }
+
+acf_attributes
+ : /* empty */ { $$ = NULL; };
+ | '[' acf_attribute_list ']' { $$ = $2; };
+
+acf_attribute_list
+ : acf_attribute { $$ = append_attr(NULL, $1); }
+ | acf_attribute_list ',' acf_attribute { $$ = append_attr($1, $3); }
+
+acf_attribute
+ : tENCODE { $$ = make_attr(ATTR_ENCODE); }
+ | tDECODE { $$ = make_attr(ATTR_DECODE); }
+ | tEXPLICITHANDLE { $$ = make_attr(ATTR_EXPLICIT_HANDLE); }
+
%%
static void decl_builtin_basic(const char *name, enum type_basic_type type)
return new_list;
}
-static attr_list_t *dupattrs(const attr_list_t *list)
+typedef int (*map_attrs_filter_t)(attr_list_t*,const attr_t*);
+
+static attr_list_t *map_attrs(const attr_list_t *list, map_attrs_filter_t filter)
{
attr_list_t *new_list;
const attr_t *attr;
+ attr_t *new_attr;
if (!list) return NULL;
list_init( new_list );
LIST_FOR_EACH_ENTRY(attr, list, const attr_t, entry)
{
- attr_t *new_attr = xmalloc(sizeof(*new_attr));
+ if (filter && !filter(new_list, attr)) continue;
+ new_attr = xmalloc(sizeof(*new_attr));
*new_attr = *attr;
list_add_tail(new_list, &new_attr->entry);
}
{
attr_list_t *attrs;
declspec->type = duptype(type, 1);
- attrs = dupattrs(type->attrs);
+ attrs = map_attrs(type->attrs, NULL);
declspec->type->attrs = append_attr_list(attrs, declspec->attrs);
declspec->attrs = NULL;
}
return list;
}
-static array_dims_t *append_array(array_dims_t *list, expr_t *expr)
+static type_t *append_array(type_t *chain, expr_t *expr)
{
- if (!expr) return list;
- if (!list)
- {
- list = xmalloc( sizeof(*list) );
- list_init( list );
- }
- list_add_tail( list, &expr->entry );
- return list;
+ type_t *array;
+
+ if (!expr)
+ return chain;
+
+ /* An array is always a reference pointer unless explicitly marked otherwise
+ * (regardless of what the default pointer attribute is). */
+ array = type_new_array(NULL, NULL, FALSE, expr->is_const ? expr->cval : 0,
+ expr->is_const ? NULL : expr, NULL, FC_RP);
+
+ return append_chain_type(chain, array);
}
static struct list type_pool = LIST_INIT(type_pool);
case TYPE_BASIC_INT64:
case TYPE_BASIC_INT:
case TYPE_BASIC_INT3264:
+ case TYPE_BASIC_LONG:
case TYPE_BASIC_BYTE:
case TYPE_BASIC_CHAR:
case TYPE_BASIC_WCHAR:
}
}
-static type_t *append_ptrchain_type(type_t *ptrchain, type_t *type)
+static type_t *get_array_or_ptr_ref(type_t *type)
{
- type_t *ptrchain_type;
- if (!ptrchain)
- return type;
- for (ptrchain_type = ptrchain; type_pointer_get_ref(ptrchain_type); ptrchain_type = type_pointer_get_ref(ptrchain_type))
- ;
- assert(ptrchain_type->type_type == TYPE_POINTER);
- ptrchain_type->details.pointer.ref = type;
- return ptrchain;
+ if (is_ptr(type))
+ return type_pointer_get_ref(type);
+ else if (is_array(type))
+ return type_array_get_element(type);
+ return NULL;
+}
+
+static type_t *append_chain_type(type_t *chain, type_t *type)
+{
+ type_t *chain_type;
+
+ if (!chain)
+ return type;
+ for (chain_type = chain; get_array_or_ptr_ref(chain_type); chain_type = get_array_or_ptr_ref(chain_type))
+ ;
+
+ if (is_ptr(chain_type))
+ chain_type->details.pointer.ref = type;
+ else if (is_array(chain_type))
+ chain_type->details.array.elem = type;
+ else
+ assert(0);
+
+ return chain;
}
static warning_list_t *append_warning(warning_list_t *list, int num)
var_t *v = decl->var;
expr_list_t *sizes = get_attrp(attrs, ATTR_SIZEIS);
expr_list_t *lengs = get_attrp(attrs, ATTR_LENGTHIS);
- int sizeless;
expr_t *dim;
type_t **ptype;
- array_dims_t *arr = decl ? decl->array : NULL;
type_t *func_type = decl ? decl->func_type : NULL;
type_t *type = decl_spec->type;
}
/* add type onto the end of the pointers in pident->type */
- v->type = append_ptrchain_type(decl ? decl->type : NULL, type);
+ v->type = append_chain_type(decl ? decl->type : NULL, type);
v->stgclass = decl_spec->stgclass;
v->attrs = attrs;
/* check for pointer attribute being applied to non-pointer, non-array
* type */
- if (!arr)
+ if (!is_array(v->type))
{
int ptr_attr = get_attrv(v->attrs, ATTR_POINTERTYPE);
const type_t *ptr = NULL;
}
if (is_ptr(ptr))
{
- if (ptr_attr && ptr_attr != RPC_FC_UP &&
+ if (ptr_attr && ptr_attr != FC_UP &&
type_get_type(type_pointer_get_ref(ptr)) == TYPE_INTERFACE)
warning_loc_info(&v->loc_info,
"%s: pointer attribute applied to interface "
"pointer type has no effect\n", v->name);
- if (!ptr_attr && top && (*pt)->details.pointer.def_fc != RPC_FC_RP)
+ if (!ptr_attr && top && (*pt)->details.pointer.def_fc != FC_RP)
{
/* FIXME: this is a horrible hack to cope with the issue that we
* store an offset to the typeformat string in the type object, but
{
type_t *t = type;
- if (!is_ptr(v->type) && !arr)
+ if (!is_ptr(v->type) && !is_array(v->type))
error_loc("'%s': [string] attribute applied to non-pointer, non-array type\n",
v->name);
- while (is_ptr(t))
- t = type_pointer_get_ref(t);
+ for (;;)
+ {
+ if (is_ptr(t))
+ t = type_pointer_get_ref(t);
+ else if (is_array(t))
+ t = type_array_get_element(t);
+ else
+ break;
+ }
if (type_get_type(t) != TYPE_BASIC &&
- (get_basic_fc(t) != RPC_FC_CHAR &&
- get_basic_fc(t) != RPC_FC_BYTE &&
- get_basic_fc(t) != RPC_FC_WCHAR))
+ (get_basic_fc(t) != FC_CHAR &&
+ get_basic_fc(t) != FC_BYTE &&
+ get_basic_fc(t) != FC_WCHAR))
{
error_loc("'%s': [string] attribute is only valid on 'char', 'byte', or 'wchar_t' pointers and arrays\n",
v->name);
error_loc("'%s': [range] attribute applied to non-integer type\n",
v->name);
- ptype = &v->type;
- sizeless = FALSE;
- if (arr) LIST_FOR_EACH_ENTRY_REV(dim, arr, expr_t, entry)
- {
- if (sizeless)
- error_loc("%s: only the first array dimension can be unspecified\n", v->name);
-
- if (dim->is_const)
- {
- if (dim->cval <= 0)
- error_loc("%s: array dimension must be positive\n", v->name);
-
- /* FIXME: should use a type_memsize that allows us to pass in a pointer size */
- if (0)
- {
- unsigned int size = type_memsize(v->type);
-
- if (0xffffffffu / size < dim->cval)
- error_loc("%s: total array size is too large\n", v->name);
- }
- }
- else
- sizeless = TRUE;
-
- *ptype = type_new_array(NULL, *ptype, FALSE,
- dim->is_const ? dim->cval : 0,
- dim->is_const ? NULL : dim, NULL,
- pointer_default);
- }
-
ptype = &v->type;
if (sizes) LIST_FOR_EACH_ENTRY(dim, sizes, expr_t, entry)
{
return v;
}
+static var_t *copy_var(var_t *src, char *name, map_attrs_filter_t attr_filter)
+{
+ var_t *v = xmalloc(sizeof(var_t));
+ v->name = name;
+ v->type = src->type;
+ v->attrs = map_attrs(src->attrs, attr_filter);
+ v->eval = src->eval;
+ v->stgclass = src->stgclass;
+ v->loc_info = src->loc_info;
+ return v;
+}
+
static declarator_list_t *append_declarator(declarator_list_t *list, declarator_t *d)
{
if (!d) return list;
d->var = var ? var : make_var(NULL);
d->type = NULL;
d->func_type = NULL;
- d->array = NULL;
d->bits = NULL;
return d;
}
static type_t *make_safearray(type_t *type)
{
return type_new_array(NULL, type_new_alias(type, "SAFEARRAY"), TRUE, 0,
- NULL, NULL, RPC_FC_RP);
+ NULL, NULL, FC_RP);
}
static typelib_t *make_library(const char *name, const attr_list_t *attrs)
case TYPE_BASIC_INT32:
case TYPE_BASIC_INT64:
case TYPE_BASIC_INT:
+ case TYPE_BASIC_LONG:
case TYPE_BASIC_CHAR:
case TYPE_BASIC_HYPER:
case TYPE_BASIC_BYTE:
}
}
+static char *concat_str(const char *prefix, const char *str)
+{
+ char *ret = xmalloc(strlen(prefix) + strlen(str) + 1);
+ strcpy(ret, prefix);
+ strcat(ret, str);
+ return ret;
+}
+
+static int async_iface_attrs(attr_list_t *attrs, const attr_t *attr)
+{
+ switch(attr->type)
+ {
+ case ATTR_UUID:
+ return 0;
+ case ATTR_ASYNCUUID:
+ append_attr(attrs, make_attrp(ATTR_UUID, attr->u.pval));
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+static int arg_in_attrs(attr_list_t *attrs, const attr_t *attr)
+{
+ return attr->type != ATTR_OUT && attr->type != ATTR_RETVAL;
+}
+
+static int arg_out_attrs(attr_list_t *attrs, const attr_t *attr)
+{
+ return attr->type != ATTR_IN;
+}
+
+static void check_async_uuid(type_t *iface)
+{
+ statement_list_t *stmts = NULL;
+ statement_t *stmt;
+ type_t *async_iface;
+ type_t *inherit;
+
+ if (!is_attr(iface->attrs, ATTR_ASYNCUUID)) return;
+
+ inherit = iface->details.iface->inherit;
+ if (inherit && strcmp(inherit->name, "IUnknown"))
+ inherit = inherit->details.iface->async_iface;
+ if (!inherit)
+ error_loc("async_uuid applied to an interface with incompatible parent\n");
+
+ async_iface = get_type(TYPE_INTERFACE, concat_str("Async", iface->name), iface->namespace, 0);
+ async_iface->attrs = map_attrs(iface->attrs, async_iface_attrs);
+
+ STATEMENTS_FOR_EACH_FUNC( stmt, type_iface_get_stmts(iface) )
+ {
+ var_t *begin_func, *finish_func, *func = stmt->u.var, *arg;
+ var_list_t *begin_args = NULL, *finish_args = NULL, *args;
+
+ args = func->type->details.function->args;
+ if (args) LIST_FOR_EACH_ENTRY(arg, args, var_t, entry)
+ {
+ if (is_attr(arg->attrs, ATTR_IN) || !is_attr(arg->attrs, ATTR_OUT))
+ begin_args = append_var(begin_args, copy_var(arg, strdup(arg->name), arg_in_attrs));
+ if (is_attr(arg->attrs, ATTR_OUT))
+ finish_args = append_var(finish_args, copy_var(arg, strdup(arg->name), arg_out_attrs));
+ }
+
+ begin_func = copy_var(func, concat_str("Begin_", func->name), NULL);
+ begin_func->type = type_new_function(begin_args);
+ begin_func->type->attrs = func->attrs;
+ begin_func->type->details.function->retval = func->type->details.function->retval;
+ stmts = append_statement(stmts, make_statement_declaration(begin_func));
+
+ finish_func = copy_var(func, concat_str("Finish_", func->name), NULL);
+ finish_func->type = type_new_function(finish_args);
+ finish_func->type->attrs = func->attrs;
+ finish_func->type->details.function->retval = func->type->details.function->retval;
+ stmts = append_statement(stmts, make_statement_declaration(finish_func));
+ }
+
+ type_interface_define(async_iface, inherit, stmts);
+ iface->details.iface->async_iface = async_iface->details.iface->async_iface = async_iface;
+}
+
static void check_statements(const statement_list_t *stmts, int is_inside_library)
{
const statement_t *stmt;