static ast_expression* parse_expression(parser_t *parser, bool stopatcomma, bool with_labels);
static ast_value* parser_create_array_setter_proto(parser_t *parser, ast_value *array, const char *funcname);
static ast_value* parser_create_array_getter_proto(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname);
-static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef);
+static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef, bool *is_vararg);
static void parseerror(parser_t *parser, const char *fmt, ...)
{
return NULL;
}
- typevar = parse_typename(parser, NULL, NULL);
+ typevar = parse_typename(parser, NULL, NULL, NULL);
if (!typevar) {
ast_unref(idx);
return NULL;
}
}
- if (var->hasvalue && !(var->expression.flags & AST_FLAG_ACCUMULATE)) {
- parseerror(parser, "function `%s` declared with multiple bodies", var->name);
- ast_block_delete(block);
- goto enderr;
- }
-
- /* accumulation? */
- if (var->hasvalue && var->expression.vtype == TYPE_FUNCTION) {
- ast_value *accum = NULL;
- ast_function *previous = NULL;
- char acname[1024];
-
- /* only void please */
- if (var->expression.next->vtype != TYPE_VOID) {
- parseerror(parser, "accumulated function `%s` declared with return type `%s` (accumulated functions must return void)",
- var->name,
- type_name[var->expression.next->vtype]
- );
+ if (var->hasvalue) {
+ if (!(var->expression.flags & AST_FLAG_ACCUMULATE)) {
+ parseerror(parser, "function `%s` declared with multiple bodies", var->name);
ast_block_delete(block);
goto enderr;
}
+ func = var->constval.vfunc;
- /* generate a new name increasing the accumulation count*/
- util_snprintf(acname, sizeof(acname), "##ACCUMULATE_%s_%d", var->name, var->constval.vfunc->accumulation++);
- accum = ast_value_new(parser_ctx(parser), acname, ((ast_expression*)var)->vtype);
- if (!accum)
- return false;
-
- ast_type_adopt(accum, var);
- func = ast_function_new(ast_ctx(var), NULL, accum);
- if (!func)
- return false;
-
- parser_addglobal(parser, acname, (ast_expression*)accum);
- vec_push(parser->functions, func);
-
- /* update the previous calls accumulate pointer for the codegen */
- previous = var->constval.vfunc;
- while (previous->accumulate)
- previous = previous->accumulate;
-
- if (ast_istype(previous, ast_function))
- previous->accumulate = func;
-
+ if (!func) {
+ parseerror(parser, "internal error: NULL function: `%s`", var->name);
+ ast_block_delete(block);
+ goto enderr;
+ }
} else {
func = ast_function_new(ast_ctx(var), var->name, var);
- vec_push(parser->functions, func);
- }
- if (!func) {
- parseerror(parser, "failed to allocate function for `%s`", var->name);
- ast_block_delete(block);
- goto enderr;
+ if (!func) {
+ parseerror(parser, "failed to allocate function for `%s`", var->name);
+ ast_block_delete(block);
+ goto enderr;
+ }
+ vec_push(parser->functions, func);
}
parser_enterblock(parser);
}
}
- if (var->argcounter) {
+ if (var->argcounter && !func->argc) {
ast_value *argc = ast_value_new(ast_ctx(var), var->argcounter, TYPE_FLOAT);
parser_addlocal(parser, argc->name, (ast_expression*)argc);
func->argc = argc;
}
- if (OPTS_FLAG(VARIADIC_ARGS) && var->expression.flags & AST_FLAG_VARIADIC) {
+ if (OPTS_FLAG(VARIADIC_ARGS) && var->expression.flags & AST_FLAG_VARIADIC && !func->varargs) {
char name[1024];
ast_value *varargs = ast_value_new(ast_ctx(var), "reserved:va_args", TYPE_ARRAY);
varargs->expression.flags |= AST_FLAG_IS_VARARG;
vec_push(func->blocks, block);
-
parser->function = old;
if (!parser_leaveblock(parser))
retval = false;
return parser_create_array_getter_impl(parser, array);
}
-static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef);
static ast_value *parse_parameter_list(parser_t *parser, ast_value *var)
{
lex_ctx_t ctx;
/* parse variables until we hit a closing paren */
while (parser->tok != ')') {
+ bool is_varargs = false;
+
if (!first) {
/* there must be commas between them */
if (parser->tok != ',') {
}
first = false;
- if (parser->tok == TOKEN_DOTS) {
+ param = parse_typename(parser, NULL, NULL, &is_varargs);
+ if (!param && !is_varargs)
+ goto on_error;
+ if (is_varargs) {
/* '...' indicates a varargs function */
variadic = true;
- if (!parser_next(parser) || (parser->tok != ')' && parser->tok != TOKEN_IDENT)) {
+ if (parser->tok != ')' && parser->tok != TOKEN_IDENT) {
parseerror(parser, "`...` must be the last parameter of a variadic function declaration");
goto on_error;
}
goto on_error;
}
}
- }
- else
- {
- /* for anything else just parse a typename */
- param = parse_typename(parser, NULL, NULL);
- if (!param)
- goto on_error;
+ } else {
vec_push(params, param);
if (param->expression.vtype >= TYPE_VARIANT) {
char tname[1024]; /* typename is reserved in C++ */
* void() foo(), bar
* then the type-information 'void()' can be stored in 'storebase'
*/
-static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef)
+static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef, bool *is_vararg)
{
ast_value *var, *tmp;
lex_ctx_t ctx;
bool wasarray = false;
size_t morefields = 0;
+ bool vararg = (parser->tok == TOKEN_DOTS);
+
ctx = parser_ctx(parser);
/* types may start with a dot */
morefields += 3;
else
break;
+ vararg = false;
if (!parser_next(parser)) {
parseerror(parser, "expected typename for field definition");
return NULL;
if (parser->tok == TOKEN_IDENT)
cached_typedef = parser_find_typedef(parser, parser_tokval(parser), 0);
if (!cached_typedef && parser->tok != TOKEN_TYPENAME) {
+ if (vararg && is_vararg) {
+ *is_vararg = true;
+ return NULL;
+ }
parseerror(parser, "expected typename");
return NULL;
}
}
/* there may be a name now */
- if (parser->tok == TOKEN_IDENT) {
+ if (parser->tok == TOKEN_IDENT || parser->tok == TOKEN_KEYWORD) {
+ if (!strcmp(parser_tokval(parser), "break"))
+ (void)!parsewarning(parser, WARN_BREAKDEF, "break definition ignored (suggest removing it)");
+ else if (parser->tok == TOKEN_KEYWORD)
+ goto leave;
+
name = util_strdup(parser_tokval(parser));
+
/* parse on */
if (!parser_next(parser)) {
ast_delete(var);
}
}
+ leave:
/* now this may be an array */
if (parser->tok == '[') {
wasarray = true;
ast_value *typevar, *oldtype;
ast_expression *old;
- typevar = parse_typename(parser, NULL, NULL);
+ typevar = parse_typename(parser, NULL, NULL, NULL);
if (!typevar)
return false;
parseerror(parser, "`static` qualifier is not supported in global scope");
/* get the first complete variable */
- var = parse_typename(parser, &basetype, cached_typedef);
+ var = parse_typename(parser, &basetype, cached_typedef, NULL);
if (!var) {
if (basetype)
ast_delete(basetype);
if (parser->tok != '{' || var->expression.vtype != TYPE_FUNCTION) {
if (parser->tok != '=') {
- if (!strcmp(parser_tokval(parser), "break")) {
- if (!parser_next(parser)) {
- parseerror(parser, "error parsing break definition");
- break;
- }
- (void)!parsewarning(parser, WARN_BREAKDEF, "break definition ignored (suggest removing it)");
- } else {
- parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser));
- break;
- }
+ parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser));
+ break;
}
if (!parser_next(parser)) {