/*
- * Copyright (C) 2012
+ * Copyright (C) 2012, 2013
* Wolfgang Bumiller
* Dale Weiler
*
self->expression.params = NULL;
self->expression.count = 0;
self->expression.flags = 0;
+ self->expression.varparam = NULL;
}
static void ast_expression_delete(ast_expression *self)
bool ast_compare_type(ast_expression *a, ast_expression *b)
{
+ if (a->expression.vtype == TYPE_NIL ||
+ b->expression.vtype == TYPE_NIL)
+ return true;
if (a->expression.vtype != b->expression.vtype)
return false;
if (!a->expression.next != !b->expression.next)
self->getter = NULL;
self->desc = NULL;
+ self->argcounter = NULL;
+
return self;
}
{
if (self->name)
mem_d((void*)self->name);
+ if (self->argcounter)
+ mem_d((void*)self->argcounter);
if (self->hasvalue) {
switch (self->expression.vtype)
{
ast_ternary* ast_ternary_new(lex_ctx ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse)
{
+ ast_expression *exprtype = ontrue;
ast_instantiate(ast_ternary, ctx, ast_ternary_delete);
/* This time NEITHER must be NULL */
if (!ontrue || !onfalse) {
ast_propagate_effects(self, ontrue);
ast_propagate_effects(self, onfalse);
- if (!ast_type_adopt(self, ontrue)) {
+ if (ontrue->expression.vtype == TYPE_NIL)
+ exprtype = onfalse;
+ if (!ast_type_adopt(self, exprtype)) {
ast_ternary_delete(self);
return NULL;
}
void ast_ternary_delete(ast_ternary *self)
{
- ast_unref(self->cond);
- ast_unref(self->on_true);
- ast_unref(self->on_false);
+ /* the if()s are only there because computed-gotos can set them
+ * to NULL
+ */
+ if (self->cond) ast_unref(self->cond);
+ if (self->on_true) ast_unref(self->on_true);
+ if (self->on_false) ast_unref(self->on_false);
ast_expression_delete((ast_expression*)self);
mem_d(self);
}
mem_d(self);
}
-ast_label* ast_label_new(lex_ctx ctx, const char *name)
+ast_label* ast_label_new(lex_ctx ctx, const char *name, bool undefined)
{
ast_instantiate(ast_label, ctx, ast_label_delete);
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_label_codegen);
- self->name = util_strdup(name);
- self->irblock = NULL;
- self->gotos = NULL;
+ self->expression.vtype = TYPE_NOEXPR;
+
+ self->name = util_strdup(name);
+ self->irblock = NULL;
+ self->gotos = NULL;
+ self->undefined = undefined;
return self;
}
ast_expression *funcexpr)
{
ast_instantiate(ast_call, ctx, ast_call_delete);
+ if (!funcexpr->expression.next) {
+ compile_error(ctx, "not a function");
+ mem_d(self);
+ return NULL;
+ }
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_call_codegen);
ast_side_effects(self) = true;
- self->params = NULL;
- self->func = funcexpr;
+ self->params = NULL;
+ self->func = funcexpr;
+ self->va_count = NULL;
ast_type_adopt(self, funcexpr->expression.next);
if (self->func)
ast_unref(self->func);
+ if (self->va_count)
+ ast_unref(self->va_count);
+
ast_expression_delete((ast_expression*)self);
mem_d(self);
}
bool ast_call_check_types(ast_call *self)
{
+ char texp[1024];
+ char tgot[1024];
size_t i;
bool retval = true;
const ast_expression *func = self->func;
count = vec_size(func->expression.params);
for (i = 0; i < count; ++i) {
- if (!ast_compare_type(self->params[i], (ast_expression*)(func->expression.params[i]))) {
- char texp[1024];
- char tgot[1024];
+ if (!ast_compare_type(self->params[i], (ast_expression*)(func->expression.params[i])))
+ {
ast_type_to_string(self->params[i], tgot, sizeof(tgot));
ast_type_to_string((ast_expression*)func->expression.params[i], texp, sizeof(texp));
compile_error(ast_ctx(self), "invalid type for parameter %u in function call: expected %s, got %s",
retval = false;
}
}
+ count = vec_size(self->params);
+ if (count > vec_size(func->expression.params) && func->expression.varparam) {
+ for (; i < count; ++i) {
+ if (!ast_compare_type(self->params[i], func->expression.varparam))
+ {
+ ast_type_to_string(self->params[i], tgot, sizeof(tgot));
+ ast_type_to_string(func->expression.varparam, texp, sizeof(texp));
+ compile_error(ast_ctx(self), "invalid type for parameter %u in function call: expected %s, got %s",
+ (unsigned int)(i+1), texp, tgot);
+ /* we don't immediately return */
+ retval = false;
+ }
+ }
+ }
return retval;
}
vtype->hasvalue = true;
vtype->constval.vfunc = self;
+ self->varargs = NULL;
+ self->argc = NULL;
+ self->fixedparams = NULL;
+
return self;
}
vec_free(self->blocks);
vec_free(self->breakblocks);
vec_free(self->continueblocks);
+ if (self->varargs)
+ ast_delete(self->varargs);
+ if (self->argc)
+ ast_delete(self->argc);
+ if (self->fixedparams)
+ ast_unref(self->fixedparams);
mem_d(self);
}
size_t len;
char *from;
- if (!opts.dump && !opts.dumpfin && !opts.debug)
+ if (!OPTS_OPTION_BOOL(OPTION_DUMP) &&
+ !OPTS_OPTION_BOOL(OPTION_DUMPFIN) &&
+ !OPTS_OPTION_BOOL(OPTION_DEBUG))
+ {
return NULL;
+ }
id = (self->labelcount++);
len = strlen(prefix);
self->constval.vfunc->ir_func = func;
self->ir_v = func->value;
+ if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
+ self->ir_v->flags |= IR_FLAG_INCLUDE_DEF;
/* The function is filled later on ast_function_codegen... */
return true;
}
}
/* we are lame now - considering the way QC works we won't tolerate arrays > 1024 elements */
- if (!array->expression.count || array->expression.count > opts.max_array_size)
+ if (!array->expression.count || array->expression.count > OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE))
compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)array->expression.count);
elemtype = &array->expression.next->expression;
v->unique_life = true;
v->locked = true;
array->ir_v = self->ir_v = v;
+ if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
+ self->ir_v->flags |= IR_FLAG_INCLUDE_DEF;
namelen = strlen(self->name);
name = (char*)mem_a(namelen + 16);
array->ir_values[ai]->context = ast_ctx(self);
array->ir_values[ai]->unique_life = true;
array->ir_values[ai]->locked = true;
+ if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
+ self->ir_values[ai]->flags |= IR_FLAG_INCLUDE_DEF;
}
mem_d(name);
}
return false;
v->context = ast_ctx(self);
self->ir_v = v;
+ if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
+ self->ir_v->flags |= IR_FLAG_INCLUDE_DEF;
}
return true;
}
int vtype = elemtype->vtype;
/* same as with field arrays */
- if (!self->expression.count || self->expression.count > opts.max_array_size)
+ if (!self->expression.count || self->expression.count > OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE))
compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count);
v = ir_builder_create_global(ir, self->name, vtype);
v->context = ast_ctx(self);
v->unique_life = true;
v->locked = true;
+ if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
+ v->flags |= IR_FLAG_INCLUDE_DEF;
namelen = strlen(self->name);
name = (char*)mem_a(namelen + 16);
self->ir_values[ai]->context = ast_ctx(self);
self->ir_values[ai]->unique_life = true;
self->ir_values[ai]->locked = true;
+ if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
+ self->ir_values[ai]->flags |= IR_FLAG_INCLUDE_DEF;
}
mem_d(name);
}
/* link us to the ir_value */
v->cvq = self->cvq;
self->ir_v = v;
+ if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
+ self->ir_v->flags |= IR_FLAG_INCLUDE_DEF;
return true;
error: /* clean up */
func->flags |= IR_FLAG_HAS_ARRAYS;
- if (param) {
+ if (param && !(self->expression.flags & AST_FLAG_IS_VARARG)) {
compile_error(ast_ctx(self), "array-parameters are not supported");
return false;
}
/* we are lame now - considering the way QC works we won't tolerate arrays > 1024 elements */
- if (!self->expression.count || self->expression.count > opts.max_array_size) {
+ if (!self->expression.count || self->expression.count > OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE)) {
compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count);
}
{
ir_function *irf;
ir_value *dummy;
- ast_expression_common *ec;
+ ast_expression_common *ec;
+ ast_expression_codegen *cgen;
size_t i;
(void)ir;
}
}
+ if (self->varargs) {
+ if (!ast_local_codegen(self->varargs, self->ir_func, true))
+ return false;
+ irf->max_varargs = self->varargs->expression.count;
+ }
+
if (self->builtin) {
irf->builtin = self->builtin;
return true;
return false;
}
- self->curblock = ir_function_create_block(ast_ctx(self), irf, "entry");
+ irf->first = self->curblock = ir_function_create_block(ast_ctx(self), irf, "entry");
if (!self->curblock) {
compile_error(ast_ctx(self), "failed to allocate entry block for `%s`", self->name);
return false;
}
+ if (self->argc) {
+ ir_value *va_count;
+ ir_value *fixed;
+ ir_value *sub;
+ if (!ast_local_codegen(self->argc, self->ir_func, true))
+ return false;
+ cgen = self->argc->expression.codegen;
+ if (!(*cgen)((ast_expression*)(self->argc), self, false, &va_count))
+ return false;
+ cgen = self->fixedparams->expression.codegen;
+ if (!(*cgen)((ast_expression*)(self->fixedparams), self, false, &fixed))
+ return false;
+ sub = ir_block_create_binop(self->curblock, ast_ctx(self),
+ ast_function_label(self, "va_count"), INSTR_SUB_F,
+ ir_builder_get_va_count(ir), fixed);
+ if (!sub)
+ return false;
+ if (!ir_block_create_store_op(self->curblock, ast_ctx(self), INSTR_STORE_F,
+ va_count, sub))
+ {
+ return false;
+ }
+ }
+
for (i = 0; i < vec_size(self->blocks); ++i) {
- ast_expression_codegen *gen = self->blocks[i]->expression.codegen;
- if (!(*gen)((ast_expression*)self->blocks[i], self, false, &dummy))
+ cgen = self->blocks[i]->expression.codegen;
+ if (!(*cgen)((ast_expression*)self->blocks[i], self, false, &dummy))
return false;
}
{
return ir_block_create_return(self->curblock, ast_ctx(self), NULL);
}
- else if (vec_size(self->curblock->entries))
+ else if (vec_size(self->curblock->entries) || self->curblock == irf->first)
{
/* error("missing return"); */
if (compile_warning(ast_ctx(self), WARN_MISSING_RETURN_VALUES,
for (i = 0; i < vec_size(self->locals); ++i)
{
if (!ast_local_codegen(self->locals[i], func->ir_func, false)) {
- if (opts.debug)
+ if (OPTS_OPTION_BOOL(OPTION_DEBUG))
compile_error(ast_ctx(self), "failed to generate local `%s`", self->locals[i]->name);
return false;
}
}
self->expression.outr = *out;
+ codegen_output_type(self, *out);
return true;
}
if (!*out)
return false;
self->expression.outr = *out;
+ codegen_output_type(self, *out);
return true;
}
*out = ir_call_value(call);
self->expression.outr = *out;
+ (*out)->vtype = self->expression.vtype;
+ codegen_output_type(self, *out);
return true;
}
compile_error(ast_ctx(self), "array indexing here needs an integer constant");
return false;
}
+ (*out)->vtype = self->expression.vtype;
+ codegen_output_type(self, *out);
return true;
}
/* Here, now, we need a PHI node
* but first some sanity checking...
*/
- if (trueval->vtype != falseval->vtype) {
+ if (trueval->vtype != falseval->vtype && trueval->vtype != TYPE_NIL && falseval->vtype != TYPE_NIL) {
/* error("ternary with different types on the two sides"); */
+ compile_error(ast_ctx(self), "internal error: ternary operand types invalid");
return false;
}
/* create PHI */
- phi = ir_block_create_phi(merge, ast_ctx(self), ast_function_label(func, "phi"), trueval->vtype);
- if (!phi)
+ phi = ir_block_create_phi(merge, ast_ctx(self), ast_function_label(func, "phi"), self->expression.vtype);
+ if (!phi) {
+ compile_error(ast_ctx(self), "internal error: failed to generate phi node");
return false;
+ }
ir_phi_add(phi, ontrue_out, trueval);
ir_phi_add(phi, onfalse_out, falseval);
return true;
cmpinstr = type_eq_instr[irop->vtype];
- if (cmpinstr >= AINSTR_END) {
+ if (cmpinstr >= VINSTR_END) {
ast_type_to_string(self->operand, typestr, sizeof(typestr));
compile_error(ast_ctx(self), "invalid type to perform a switch on: %s", typestr);
return false;
size_t i;
ir_value *dummy;
+ if (self->undefined) {
+ compile_error(ast_ctx(self), "internal error: ast_label never defined");
+ return false;
+ }
+
*out = NULL;
if (lvalue) {
compile_error(ast_ctx(self), "internal error: ast_label cannot be an lvalue");
vec_push(params, param);
}
+ /* varargs counter */
+ if (self->va_count) {
+ ir_value *va_count;
+ ir_builder *builder = func->curblock->owner->owner;
+ cgen = self->va_count->expression.codegen;
+ if (!(*cgen)((ast_expression*)(self->va_count), func, false, &va_count))
+ return false;
+ if (!ir_block_create_store_op(func->curblock, ast_ctx(self), INSTR_STORE_F,
+ ir_builder_get_va_count(builder), va_count))
+ {
+ return false;
+ }
+ }
+
callinstr = ir_block_create_call(func->curblock, ast_ctx(self),
ast_function_label(func, "call"),
funval, !!(self->func->expression.flags & AST_FLAG_NORETURN));