static bool ast_member_codegen(ast_member*, ast_function*, bool lvalue, ir_value**);
static void ast_array_index_delete(ast_array_index*);
static bool ast_array_index_codegen(ast_array_index*, ast_function*, bool lvalue, ir_value**);
+static void ast_argpipe_delete(ast_argpipe*);
+static bool ast_argpipe_codegen(ast_argpipe*, ast_function*, bool lvalue, ir_value**);
static void ast_store_delete(ast_store*);
static bool ast_store_codegen(ast_store*, ast_function*, bool lvalue, ir_value**);
static void ast_ifthen_delete(ast_ifthen*);
mem_d(self);
}
+ast_argpipe* ast_argpipe_new(lex_ctx ctx, ast_expression *index)
+{
+ ast_instantiate(ast_argpipe, ctx, ast_argpipe_delete);
+ ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_argpipe_codegen);
+ self->index = index;
+ self->expression.vtype = TYPE_NOEXPR;
+ return self;
+}
+
+void ast_argpipe_delete(ast_argpipe *self)
+{
+ if (self->index)
+ ast_unref(self->index);
+ ast_expression_delete((ast_expression*)self);
+ mem_d(self);
+}
+
ast_ifthen* ast_ifthen_new(lex_ctx ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse)
{
ast_instantiate(ast_ifthen, ctx, ast_ifthen_delete);
mem_d(self);
}
-bool ast_call_check_types(ast_call *self)
+static bool ast_call_check_vararg(ast_call *self, ast_expression *va_type, ast_expression *exp_type)
+{
+ char texp[1024];
+ char tgot[1024];
+ if (!exp_type)
+ return true;
+ if (!va_type || !ast_compare_type(va_type, exp_type))
+ {
+ if (va_type && exp_type)
+ {
+ ast_type_to_string(va_type, tgot, sizeof(tgot));
+ ast_type_to_string(exp_type, texp, sizeof(texp));
+ if (OPTS_FLAG(UNSAFE_VARARGS)) {
+ if (compile_warning(ast_ctx(self), WARN_UNSAFE_TYPES,
+ "piped variadic argument differs in type: constrained to type %s, expected type %s",
+ tgot, texp))
+ return false;
+ } else {
+ compile_error(ast_ctx(self),
+ "piped variadic argument differs in type: constrained to type %s, expected type %s",
+ tgot, texp);
+ return false;
+ }
+ }
+ else
+ {
+ ast_type_to_string(exp_type, texp, sizeof(texp));
+ if (OPTS_FLAG(UNSAFE_VARARGS)) {
+ if (compile_warning(ast_ctx(self), WARN_UNSAFE_TYPES,
+ "piped variadic argument may differ in type: expected type %s",
+ texp))
+ return false;
+ } else {
+ compile_error(ast_ctx(self),
+ "piped variadic argument may differ in type: expected type %s",
+ texp);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool ast_call_check_types(ast_call *self, ast_expression *va_type)
{
char texp[1024];
char tgot[1024];
count = vec_size(func->params);
for (i = 0; i < count; ++i) {
- if (!ast_compare_type(self->params[i], (ast_expression*)(func->params[i])))
+ if (ast_istype(self->params[i], ast_argpipe)) {
+ // warn about type safety instead
+ if (i+1 != count) {
+ compile_error(ast_ctx(self), "argpipe must be the last parameter to a function call");
+ return false;
+ }
+ if (!ast_call_check_vararg(self, va_type, (ast_expression*)func->params[i]))
+ retval = false;
+ }
+ else if (!ast_compare_type(self->params[i], (ast_expression*)(func->params[i])))
{
ast_type_to_string(self->params[i], tgot, sizeof(tgot));
ast_type_to_string((ast_expression*)func->params[i], texp, sizeof(texp));
count = vec_size(self->params);
if (count > vec_size(func->params) && func->varparam) {
for (; i < count; ++i) {
+ if (ast_istype(self->params[i], ast_argpipe)) {
+ // warn about type safety instead
+ if (i+1 != count) {
+ compile_error(ast_ctx(self), "argpipe must be the last parameter to a function call");
+ return false;
+ }
+ if (!ast_call_check_vararg(self, va_type, func->varparam))
+ retval = false;
+ }
if (!ast_compare_type(self->params[i], func->varparam))
{
ast_type_to_string(self->params[i], tgot, sizeof(tgot));
return true;
}
+bool ast_argpipe_codegen(ast_argpipe *self, ast_function *func, bool lvalue, ir_value **out)
+{
+ *out = NULL;
+ if (lvalue) {
+ compile_error(ast_ctx(self), "argpipe node: not an lvalue");
+ return false;
+ }
+ (void)func;
+ (void)out;
+ compile_error(ast_ctx(self), "TODO: argpipe codegen not implemented");
+ return false;
+}
+
bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_value **out)
{
ast_expression_codegen *cgen;
typedef struct ast_switch_s ast_switch;
typedef struct ast_label_s ast_label;
typedef struct ast_goto_s ast_goto;
+typedef struct ast_argpipe_s ast_argpipe;
enum {
TYPE_ast_node, /* 0 */
TYPE_ast_breakcont, /* 17 */
TYPE_ast_switch, /* 18 */
TYPE_ast_label, /* 19 */
- TYPE_ast_goto /* 20 */
+ TYPE_ast_goto, /* 20 */
+ TYPE_ast_argpipe /* 21 */
};
#define ast_istype(x, t) ( ((ast_node*)x)->nodetype == (TYPE_##t) )
};
ast_array_index* ast_array_index_new(lex_ctx ctx, ast_expression *array, ast_expression *index);
+/* Vararg pipe node:
+ *
+ * copy all varargs starting from a specific index
+ */
+struct ast_argpipe_s
+{
+ ast_expression expression;
+ ast_expression *index;
+};
+ast_argpipe* ast_argpipe_new(lex_ctx ctx, ast_expression *index);
+
/* Store
*
* Stores left<-right and returns left.
};
ast_call* ast_call_new(lex_ctx ctx,
ast_expression *funcexpr);
-bool ast_call_check_types(ast_call*);
+bool ast_call_check_types(ast_call*, ast_expression *this_func_va_type);
/* Blocks
*
for (i = 0; i < paramcount; ++i)
vec_push(call->params, sy->out[fid+1 + i].out);
vec_shrinkby(sy->out, paramcount);
- (void)!ast_call_check_types(call);
+ (void)!ast_call_check_types(call, parser->function->vtype->expression.varparam);
if (parser->max_param_count < paramcount)
parser->max_param_count = paramcount;
ast_value *typevar;
ast_value *funtype = parser->function->vtype;
+ if (!parser->function->varargs) {
+ parseerror(parser, "function has no variable argument list");
+ return NULL;
+ }
+
lex_ctx ctx = parser_ctx(parser);
if (!parser_next(parser) || parser->tok != '(') {
return NULL;
if (parser->tok != ',') {
- ast_unref(idx);
- parseerror(parser, "expected comma after parameter index");
- return NULL;
+ if (parser->tok != ')') {
+ ast_unref(idx);
+ parseerror(parser, "expected comma after parameter index");
+ return NULL;
+ }
+ /* vararg piping: ...(start) */
+ out = (ast_expression*)ast_argpipe_new(ctx, idx);
+ return out;
}
if (!parser_next(parser) || (parser->tok != TOKEN_IDENT && parser->tok != TOKEN_TYPENAME)) {
return NULL;
}
-#if 0
- if (!parser_next(parser)) {
- ast_unref(idx);
- ast_delete(typevar);
- parseerror(parser, "parse error after vararg");
- return NULL;
- }
-#endif
-
- if (!parser->function->varargs) {
- ast_unref(idx);
- ast_delete(typevar);
- parseerror(parser, "function has no variable argument list");
- return NULL;
- }
-
if (funtype->expression.varparam &&
!ast_compare_type((ast_expression*)typevar, (ast_expression*)funtype->expression.varparam))
{