( (ast_node*)self )->node.destroy = (ast_node_delete*)destroyfn
-/* error handling */
-static void asterror(lex_ctx ctx, const char *msg, ...)
-{
- va_list ap;
- va_start(ap, msg);
- con_cvprintmsg((void*)&ctx, LVL_ERROR, "error", msg, ap);
- va_end(ap);
-}
-
/* It must not be possible to get here. */
static GMQCC_NORETURN void _ast_node_destroy(ast_node *self)
{
self->name = name ? util_strdup(name) : NULL;
self->expression.vtype = t;
self->expression.next = NULL;
- self->constant = false;
+ self->cvq = CV_NONE;
self->hasvalue = false;
self->uses = 0;
memset(&self->constval, 0, sizeof(self->constval));
self->dest = left;
self->source = right;
+ self->keep_dest = false;
+
self->expression.vtype = left->expression.vtype;
if (left->expression.next) {
self->expression.next = ast_type_copy(ctx, left);
void ast_binstore_delete(ast_binstore *self)
{
- ast_unref(self->dest);
+ if (!self->keep_dest)
+ ast_unref(self->dest);
ast_unref(self->source);
ast_expression_delete((ast_expression*)self);
mem_d(self);
if (op >= INSTR_NOT_F && op <= INSTR_NOT_FNC) {
self->expression.vtype = TYPE_FLOAT;
} else
- asterror(ctx, "cannot determine type of unary operation %s", asm_instr[op].m);
+ compile_error(ctx, "cannot determine type of unary operation %s", asm_instr[op].m);
return self;
}
ast_entfield* ast_entfield_new(lex_ctx ctx, ast_expression *entity, ast_expression *field)
{
if (field->expression.vtype != TYPE_FIELD) {
- asterror(ctx, "ast_entfield_new with expression not of type field");
+ compile_error(ctx, "ast_entfield_new with expression not of type field");
return NULL;
}
return ast_entfield_new_force(ctx, entity, field, field->expression.next);
if (owner->expression.vtype != TYPE_VECTOR &&
owner->expression.vtype != TYPE_FIELD) {
- asterror(ctx, "member-access on an invalid owner of type %s", type_name[owner->expression.vtype]);
+ compile_error(ctx, "member-access on an invalid owner of type %s", type_name[owner->expression.vtype]);
mem_d(self);
return NULL;
}
}
if (array->expression.vtype == TYPE_FIELD && outtype->expression.vtype == TYPE_ARRAY) {
if (self->expression.vtype != TYPE_ARRAY) {
- asterror(ast_ctx(self), "array_index node on type");
+ compile_error(ast_ctx(self), "array_index node on type");
ast_array_index_delete(self);
return NULL;
}
char tgot[1024];
ast_type_to_string(self->params[i], tgot, sizeof(tgot));
ast_type_to_string((ast_expression*)func->expression.params[i], texp, sizeof(texp));
- asterror(ast_ctx(self), "invalid type for parameter %u in function call: expected %s, got %s",
+ 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;
vtype->hasvalue ||
vtype->expression.vtype != TYPE_FUNCTION)
{
- asterror(ast_ctx(self), "internal error: ast_function_new condition %i %i type=%i",
+ compile_error(ast_ctx(self), "internal error: ast_function_new condition %i %i type=%i",
(int)!vtype,
(int)vtype->hasvalue,
vtype->expression.vtype);
if (!self->ir_v) {
char typename[1024];
ast_type_to_string((ast_expression*)self, typename, sizeof(typename));
- asterror(ast_ctx(self), "ast_value used before generated %s %s", typename, self->name);
+ compile_error(ast_ctx(self), "ast_value used before generated %s %s", typename, self->name);
return false;
}
*out = self->ir_v;
ast_expression *fieldtype = self->expression.next;
if (self->hasvalue) {
- asterror(ast_ctx(self), "TODO: constant field pointers with value");
+ compile_error(ast_ctx(self), "TODO: constant field pointers with value");
goto error;
}
ast_value *array = (ast_value*)fieldtype;
if (!ast_istype(fieldtype, ast_value)) {
- asterror(ast_ctx(self), "internal error: ast_value required");
+ compile_error(ast_ctx(self), "internal error: ast_value required");
return false;
}
/* 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)
- asterror(ast_ctx(self), "Invalid array of size %lu", (unsigned long)array->expression.count);
+ compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)array->expression.count);
elemtype = &array->expression.next->expression;
vtype = elemtype->vtype;
v = ir_builder_create_field(ir, self->name, vtype);
if (!v) {
- asterror(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name);
+ compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name);
return false;
}
if (vtype == TYPE_FIELD)
array->ir_values[ai] = ir_builder_create_field(ir, name, vtype);
if (!array->ir_values[ai]) {
mem_d(name);
- asterror(ast_ctx(self), "ir_builder_create_global failed on `%s`", name);
+ compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", name);
return false;
}
if (vtype == TYPE_FIELD)
/* same as with field arrays */
if (!self->expression.count || self->expression.count > opts_max_array_size)
- asterror(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count);
+ compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count);
v = ir_builder_create_global(ir, self->name, vtype);
if (!v) {
- asterror(ast_ctx(self), "ir_builder_create_global failed `%s`", self->name);
+ compile_error(ast_ctx(self), "ir_builder_create_global failed `%s`", self->name);
return false;
}
if (vtype == TYPE_FIELD)
self->ir_values[ai] = ir_builder_create_global(ir, name, vtype);
if (!self->ir_values[ai]) {
mem_d(name);
- asterror(ast_ctx(self), "ir_builder_create_global failed `%s`", name);
+ compile_error(ast_ctx(self), "ir_builder_create_global failed `%s`", name);
return false;
}
if (vtype == TYPE_FIELD)
*/
v = ir_builder_create_global(ir, self->name, self->expression.vtype);
if (!v) {
- asterror(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name);
+ compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name);
return false;
}
if (self->expression.vtype == TYPE_FIELD)
goto error;
break;
case TYPE_ARRAY:
- asterror(ast_ctx(self), "TODO: global constant array");
+ compile_error(ast_ctx(self), "TODO: global constant array");
break;
case TYPE_FUNCTION:
- asterror(ast_ctx(self), "global of type function not properly generated");
+ compile_error(ast_ctx(self), "global of type function not properly generated");
goto error;
/* Cannot generate an IR value for a function,
* need a pointer pointing to a function rather.
*/
default:
- asterror(ast_ctx(self), "TODO: global constant type %i", self->expression.vtype);
+ compile_error(ast_ctx(self), "TODO: global constant type %i", self->expression.vtype);
break;
}
}
/* link us to the ir_value */
+ v->cvq = self->cvq;
self->ir_v = v;
return true;
int vtype = elemtype->vtype;
if (param) {
- asterror(ast_ctx(self), "array-parameters are not supported");
+ 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) {
- asterror(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count);
+ compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count);
}
self->ir_values = (ir_value**)mem_a(sizeof(self->ir_values[0]) * self->expression.count);
if (!self->ir_values) {
- asterror(ast_ctx(self), "failed to allocate array values");
+ compile_error(ast_ctx(self), "failed to allocate array values");
return false;
}
v = ir_function_create_local(func, self->name, vtype, param);
if (!v) {
- asterror(ast_ctx(self), "ir_function_create_local failed");
+ compile_error(ast_ctx(self), "ir_function_create_local failed");
return false;
}
if (vtype == TYPE_FIELD)
snprintf(name + namelen, 16, "[%u]", (unsigned int)ai);
self->ir_values[ai] = ir_function_create_local(func, name, vtype, param);
if (!self->ir_values[ai]) {
- asterror(ast_ctx(self), "ir_builder_create_global failed on `%s`", name);
+ compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", name);
return false;
}
if (vtype == TYPE_FIELD)
goto error;
break;
default:
- asterror(ast_ctx(self), "TODO: global constant type %i", self->expression.vtype);
+ compile_error(ast_ctx(self), "TODO: global constant type %i", self->expression.vtype);
break;
}
}
/* link us to the ir_value */
+ v->cvq = self->cvq;
self->ir_v = v;
if (self->setter) {
irf = self->ir_func;
if (!irf) {
- asterror(ast_ctx(self), "ast_function's related ast_value was not generated yet");
+ compile_error(ast_ctx(self), "ast_function's related ast_value was not generated yet");
return false;
}
}
if (!vec_size(self->blocks)) {
- asterror(ast_ctx(self), "function `%s` has no body", self->name);
+ compile_error(ast_ctx(self), "function `%s` has no body", self->name);
return false;
}
- self->curblock = ir_function_create_block(irf, "entry");
+ self->curblock = ir_function_create_block(ast_ctx(self), irf, "entry");
if (!self->curblock) {
- asterror(ast_ctx(self), "failed to allocate entry block for `%s`", self->name);
+ compile_error(ast_ctx(self), "failed to allocate entry block for `%s`", self->name);
return false;
}
/* TODO: check return types */
if (!self->curblock->is_return)
{
- return ir_block_create_return(self->curblock, NULL);
- /* From now on the parser has to handle this situation */
-#if 0
if (!self->vtype->expression.next ||
self->vtype->expression.next->expression.vtype == TYPE_VOID)
{
- return ir_block_create_return(self->curblock, NULL);
+ return ir_block_create_return(self->curblock, ast_ctx(self), NULL);
}
- else
+ else if (vec_size(self->curblock->entries))
{
/* error("missing return"); */
- asterror(ast_ctx(self), "function `%s` missing return value", self->name);
- return false;
+ if (compile_warning(ast_ctx(self), WARN_MISSING_RETURN_VALUES,
+ "control reaches end of non-void function (`%s`) via %s",
+ self->name, self->curblock->label))
+ {
+ return false;
+ }
+ return ir_block_create_return(self->curblock, ast_ctx(self), NULL);
}
-#endif
}
return true;
}
* of the form: (a, b, c) = x should not assign to c...
*/
if (lvalue) {
- asterror(ast_ctx(self), "not an l-value (code-block)");
+ compile_error(ast_ctx(self), "not an l-value (code-block)");
return false;
}
{
if (!ast_local_codegen(self->locals[i], func->ir_func, false)) {
if (opts_debug)
- asterror(ast_ctx(self), "failed to generate local `%s`", self->locals[i]->name);
+ compile_error(ast_ctx(self), "failed to generate local `%s`", self->locals[i]->name);
return false;
}
}
{
ast_expression_codegen *gen = self->exprs[i]->expression.codegen;
if (func->curblock->final && !ast_istype(self->exprs[i], ast_label)) {
- asterror(ast_ctx(self->exprs[i]), "unreachable statement");
+ compile_error(ast_ctx(self->exprs[i]), "unreachable statement");
return false;
}
if (!(*gen)(self->exprs[i], func, false, out))
ai = (ast_array_index*)self->dest;
idx = (ast_value*)ai->index;
- if (ast_istype(ai->index, ast_value) && idx->hasvalue)
+ if (ast_istype(ai->index, ast_value) && idx->hasvalue && idx->cvq == CV_CONST)
ai = NULL;
}
ir_instr *call;
if (lvalue) {
- asterror(ast_ctx(self), "array-subscript assignment cannot produce lvalues");
+ compile_error(ast_ctx(self), "array-subscript assignment cannot produce lvalues");
return false;
}
arr = (ast_value*)ai->array;
if (!ast_istype(ai->array, ast_value) || !arr->setter) {
- asterror(ast_ctx(self), "value has no setter (%s)", arr->name);
+ compile_error(ast_ctx(self), "value has no setter (%s)", arr->name);
return false;
}
if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
return false;
- call = ir_block_create_call(func->curblock, ast_function_label(func, "store"), funval);
+ call = ir_block_create_call(func->curblock, ast_ctx(self), ast_function_label(func, "store"), funval);
if (!call)
return false;
ir_call_param(call, iridx);
if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
return false;
- if (!ir_block_create_store_op(func->curblock, self->op, left, right))
+ if (!ir_block_create_store_op(func->curblock, ast_ctx(self), self->op, left, right))
return false;
self->expression.outr = right;
}
/* A binary operation cannot yield an l-value */
if (lvalue) {
- asterror(ast_ctx(self), "not an l-value (binop)");
+ compile_error(ast_ctx(self), "not an l-value (binop)");
return false;
}
*/
merge_id = vec_size(func->ir_func->blocks);
- merge = ir_function_create_block(func->ir_func, ast_function_label(func, "sce_merge"));
+ merge = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "sce_merge"));
cgen = self->left->expression.codegen;
if (!(*cgen)((ast_expression*)(self->left), func, false, &left))
if (!OPTS_FLAG(PERL_LOGIC)) {
notop = type_not_instr[left->vtype];
if (notop == AINSTR_END) {
- asterror(ast_ctx(self), "don't know how to cast to bool...");
+ compile_error(ast_ctx(self), "don't know how to cast to bool...");
return false;
}
- left = ir_block_create_unary(func->curblock,
+ left = ir_block_create_unary(func->curblock, ast_ctx(self),
ast_function_label(func, "sce_not"),
notop,
left);
}
from_left = func->curblock;
- other = ir_function_create_block(func->ir_func, ast_function_label(func, "sce_other"));
+ other = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "sce_other"));
if ( !(self->op == INSTR_OR) != !OPTS_FLAG(PERL_LOGIC) ) {
- if (!ir_block_create_if(func->curblock, left, other, merge))
+ if (!ir_block_create_if(func->curblock, ast_ctx(self), left, other, merge))
return false;
} else {
- if (!ir_block_create_if(func->curblock, left, merge, other))
+ if (!ir_block_create_if(func->curblock, ast_ctx(self), left, merge, other))
return false;
}
/* use the likely flag */
if (!OPTS_FLAG(PERL_LOGIC)) {
notop = type_not_instr[right->vtype];
if (notop == AINSTR_END) {
- asterror(ast_ctx(self), "don't know how to cast to bool...");
+ compile_error(ast_ctx(self), "don't know how to cast to bool...");
return false;
}
- right = ir_block_create_unary(func->curblock,
+ right = ir_block_create_unary(func->curblock, ast_ctx(self),
ast_function_label(func, "sce_not"),
notop,
right);
}
from_right = func->curblock;
- if (!ir_block_create_jump(func->curblock, merge))
+ if (!ir_block_create_jump(func->curblock, ast_ctx(self), merge))
return false;
vec_remove(func->ir_func->blocks, merge_id, 1);
vec_push(func->ir_func->blocks, merge);
func->curblock = merge;
- phi = ir_block_create_phi(func->curblock, ast_function_label(func, "sce_value"), TYPE_FLOAT);
+ phi = ir_block_create_phi(func->curblock, ast_ctx(self), ast_function_label(func, "sce_value"), TYPE_FLOAT);
ir_phi_add(phi, from_left, left);
ir_phi_add(phi, from_right, right);
*out = ir_phi_value(phi);
if (!OPTS_FLAG(PERL_LOGIC)) {
notop = type_not_instr[(*out)->vtype];
if (notop == AINSTR_END) {
- asterror(ast_ctx(self), "don't know how to cast to bool...");
+ compile_error(ast_ctx(self), "don't know how to cast to bool...");
return false;
}
- *out = ir_block_create_unary(func->curblock,
+ *out = ir_block_create_unary(func->curblock, ast_ctx(self),
ast_function_label(func, "sce_final_not"),
notop,
*out);
if (!(*cgen)((ast_expression*)(self->right), func, false, &right))
return false;
- *out = ir_block_create_binop(func->curblock, ast_function_label(func, "bin"),
+ *out = ir_block_create_binop(func->curblock, ast_ctx(self), ast_function_label(func, "bin"),
self->op, left, right);
if (!*out)
return false;
ai = (ast_array_index*)self->dest;
idx = (ast_value*)ai->index;
- if (ast_istype(ai->index, ast_value) && idx->hasvalue)
+ if (ast_istype(ai->index, ast_value) && idx->hasvalue && idx->cvq == CV_CONST)
ai = NULL;
}
return false;
/* now the binary */
- bin = ir_block_create_binop(func->curblock, ast_function_label(func, "binst"),
+ bin = ir_block_create_binop(func->curblock, ast_ctx(self), ast_function_label(func, "binst"),
self->opbin, leftr, right);
self->expression.outr = bin;
ir_instr *call;
if (lvalue) {
- asterror(ast_ctx(self), "array-subscript assignment cannot produce lvalues");
+ compile_error(ast_ctx(self), "array-subscript assignment cannot produce lvalues");
return false;
}
arr = (ast_value*)ai->array;
if (!ast_istype(ai->array, ast_value) || !arr->setter) {
- asterror(ast_ctx(self), "value has no setter (%s)", arr->name);
+ compile_error(ast_ctx(self), "value has no setter (%s)", arr->name);
return false;
}
if (!(*cgen)((ast_expression*)(arr->setter), func, true, &funval))
return false;
- call = ir_block_create_call(func->curblock, ast_function_label(func, "store"), funval);
+ call = ir_block_create_call(func->curblock, ast_ctx(self), ast_function_label(func, "store"), funval);
if (!call)
return false;
ir_call_param(call, iridx);
return false;
self->expression.outl = leftl;
- if (!ir_block_create_store_op(func->curblock, self->opstore, leftl, bin))
+ if (!ir_block_create_store_op(func->curblock, ast_ctx(self), self->opstore, leftl, bin))
return false;
self->expression.outr = bin;
}
/* An unary operation cannot yield an l-value */
if (lvalue) {
- asterror(ast_ctx(self), "not an l-value (binop)");
+ compile_error(ast_ctx(self), "not an l-value (binop)");
return false;
}
if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand))
return false;
- *out = ir_block_create_unary(func->curblock, ast_function_label(func, "unary"),
+ *out = ir_block_create_unary(func->curblock, ast_ctx(self), ast_function_label(func, "unary"),
self->op, operand);
if (!*out)
return false;
* anything...
*/
if (lvalue) {
- asterror(ast_ctx(self), "return-expression is not an l-value");
+ compile_error(ast_ctx(self), "return-expression is not an l-value");
return false;
}
if (self->expression.outr) {
- asterror(ast_ctx(self), "internal error: ast_return cannot be reused, it bears no result!");
+ compile_error(ast_ctx(self), "internal error: ast_return cannot be reused, it bears no result!");
return false;
}
self->expression.outr = (ir_value*)1;
if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand))
return false;
- if (!ir_block_create_return(func->curblock, operand))
+ if (!ir_block_create_return(func->curblock, ast_ctx(self), operand))
return false;
} else {
- if (!ir_block_create_return(func->curblock, NULL))
+ if (!ir_block_create_return(func->curblock, ast_ctx(self), NULL))
return false;
}
if (lvalue) {
/* address! */
- *out = ir_block_create_fieldaddress(func->curblock, ast_function_label(func, "efa"),
+ *out = ir_block_create_fieldaddress(func->curblock, ast_ctx(self), ast_function_label(func, "efa"),
ent, field);
} else {
- *out = ir_block_create_load_from_ent(func->curblock, ast_function_label(func, "efv"),
+ *out = ir_block_create_load_from_ent(func->curblock, ast_ctx(self), ast_function_label(func, "efv"),
ent, field, self->expression.vtype);
}
if (!*out) {
- asterror(ast_ctx(self), "failed to create %s instruction (output type %s)",
+ compile_error(ast_ctx(self), "failed to create %s instruction (output type %s)",
(lvalue ? "ADDRESS" : "FIELD"),
type_name[self->expression.vtype]);
return false;
}
if (!ast_istype(self->array, ast_value)) {
- asterror(ast_ctx(self), "array indexing this way is not supported");
+ compile_error(ast_ctx(self), "array indexing this way is not supported");
/* note this would actually be pointer indexing because the left side is
* not an actual array but (hopefully) an indexable expression.
* Once we get integer arithmetic, and GADDRESS/GSTORE/GLOAD instruction
arr = (ast_value*)self->array;
idx = (ast_value*)self->index;
- if (!ast_istype(self->index, ast_value) || !idx->hasvalue) {
+ if (!ast_istype(self->index, ast_value) || !idx->hasvalue || idx->cvq != CV_CONST) {
/* Time to use accessor functions */
ast_expression_codegen *cgen;
ir_value *iridx, *funval;
ir_instr *call;
if (lvalue) {
- asterror(ast_ctx(self), "(.2) array indexing here needs a compile-time constant");
+ compile_error(ast_ctx(self), "(.2) array indexing here needs a compile-time constant");
return false;
}
if (!arr->getter) {
- asterror(ast_ctx(self), "value has no getter, don't know how to index it");
+ compile_error(ast_ctx(self), "value has no getter, don't know how to index it");
return false;
}
cgen = self->index->expression.codegen;
- if (!(*cgen)((ast_expression*)(self->index), func, true, &iridx))
+ if (!(*cgen)((ast_expression*)(self->index), func, false, &iridx))
return false;
cgen = arr->getter->expression.codegen;
if (!(*cgen)((ast_expression*)(arr->getter), func, true, &funval))
return false;
- call = ir_block_create_call(func->curblock, ast_function_label(func, "fetch"), funval);
+ call = ir_block_create_call(func->curblock, ast_ctx(self), ast_function_label(func, "fetch"), funval);
if (!call)
return false;
ir_call_param(call, iridx);
return true;
}
- if (idx->expression.vtype == TYPE_FLOAT)
- *out = arr->ir_values[(int)idx->constval.vfloat];
- else if (idx->expression.vtype == TYPE_INTEGER)
- *out = arr->ir_values[idx->constval.vint];
+ if (idx->expression.vtype == TYPE_FLOAT) {
+ unsigned int arridx = idx->constval.vfloat;
+ if (arridx >= self->array->expression.count)
+ {
+ compile_error(ast_ctx(self), "array index out of bounds: %i", arridx);
+ return false;
+ }
+ *out = arr->ir_values[arridx];
+ }
+ else if (idx->expression.vtype == TYPE_INTEGER) {
+ unsigned int arridx = idx->constval.vint;
+ if (arridx >= self->array->expression.count)
+ {
+ compile_error(ast_ctx(self), "array index out of bounds: %i", arridx);
+ return false;
+ }
+ *out = arr->ir_values[arridx];
+ }
else {
- asterror(ast_ctx(self), "array indexing here needs an integer constant");
+ compile_error(ast_ctx(self), "array indexing here needs an integer constant");
return false;
}
return true;
ir_block *onfalse;
ir_block *ontrue_endblock = NULL;
ir_block *onfalse_endblock = NULL;
- ir_block *merge;
+ ir_block *merge = NULL;
/* We don't output any value, thus also don't care about r/lvalue */
(void)out;
(void)lvalue;
if (self->expression.outr) {
- asterror(ast_ctx(self), "internal error: ast_ifthen cannot be reused, it bears no result!");
+ compile_error(ast_ctx(self), "internal error: ast_ifthen cannot be reused, it bears no result!");
return false;
}
self->expression.outr = (ir_value*)1;
if (self->on_true) {
/* create on-true block */
- ontrue = ir_function_create_block(func->ir_func, ast_function_label(func, "ontrue"));
+ ontrue = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "ontrue"));
if (!ontrue)
return false;
/* on-false path */
if (self->on_false) {
/* create on-false block */
- onfalse = ir_function_create_block(func->ir_func, ast_function_label(func, "onfalse"));
+ onfalse = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "onfalse"));
if (!onfalse)
return false;
onfalse = NULL;
/* Merge block were they all merge in to */
- merge = ir_function_create_block(func->ir_func, ast_function_label(func, "endif"));
- if (!merge)
- return false;
- /* add jumps ot the merge block */
- if (ontrue && !ontrue_endblock->final && !ir_block_create_jump(ontrue_endblock, merge))
- return false;
- if (onfalse && !onfalse_endblock->final && !ir_block_create_jump(onfalse_endblock, merge))
- return false;
+ if (!ontrue || !onfalse || !ontrue_endblock->final || !onfalse_endblock->final)
+ {
+ merge = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "endif"));
+ if (!merge)
+ return false;
+ /* add jumps ot the merge block */
+ if (ontrue && !ontrue_endblock->final && !ir_block_create_jump(ontrue_endblock, ast_ctx(self), merge))
+ return false;
+ if (onfalse && !onfalse_endblock->final && !ir_block_create_jump(onfalse_endblock, ast_ctx(self), merge))
+ return false;
+
+ /* Now enter the merge block */
+ func->curblock = merge;
+ }
/* we create the if here, that way all blocks are ordered :)
*/
- if (!ir_block_create_if(cond, condval,
+ if (!ir_block_create_if(cond, ast_ctx(self), condval,
(ontrue ? ontrue : merge),
(onfalse ? onfalse : merge)))
{
return false;
}
- /* Now enter the merge block */
- func->curblock = merge;
-
return true;
}
ir_instr *phi;
ir_block *cond = func->curblock;
- ir_block *ontrue;
- ir_block *onfalse;
+ ir_block *cond_out = NULL;
+ ir_block *ontrue, *ontrue_out = NULL;
+ ir_block *onfalse, *onfalse_out = NULL;
ir_block *merge;
/* Ternary can never create an lvalue... */
cgen = self->cond->expression.codegen;
if (!(*cgen)((ast_expression*)(self->cond), func, false, &condval))
return false;
+ cond_out = func->curblock;
/* create on-true block */
- ontrue = ir_function_create_block(func->ir_func, ast_function_label(func, "tern_T"));
+ ontrue = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "tern_T"));
if (!ontrue)
return false;
else
cgen = self->on_true->expression.codegen;
if (!(*cgen)((ast_expression*)(self->on_true), func, false, &trueval))
return false;
+
+ ontrue_out = func->curblock;
}
/* create on-false block */
- onfalse = ir_function_create_block(func->ir_func, ast_function_label(func, "tern_F"));
+ onfalse = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "tern_F"));
if (!onfalse)
return false;
else
cgen = self->on_false->expression.codegen;
if (!(*cgen)((ast_expression*)(self->on_false), func, false, &falseval))
return false;
+
+ onfalse_out = func->curblock;
}
/* create merge block */
- merge = ir_function_create_block(func->ir_func, ast_function_label(func, "tern_out"));
+ merge = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "tern_out"));
if (!merge)
return false;
/* jump to merge block */
- if (!ir_block_create_jump(ontrue, merge))
+ if (!ir_block_create_jump(ontrue_out, ast_ctx(self), merge))
return false;
- if (!ir_block_create_jump(onfalse, merge))
+ if (!ir_block_create_jump(onfalse_out, ast_ctx(self), merge))
return false;
/* create if instruction */
- if (!ir_block_create_if(cond, condval, ontrue, onfalse))
+ if (!ir_block_create_if(cond_out, ast_ctx(self), condval, ontrue, onfalse))
return false;
/* Now enter the merge block */
}
/* create PHI */
- phi = ir_block_create_phi(merge, ast_function_label(func, "phi"), trueval->vtype);
+ phi = ir_block_create_phi(merge, ast_ctx(self), ast_function_label(func, "phi"), trueval->vtype);
if (!phi)
return false;
- ir_phi_add(phi, ontrue, trueval);
- ir_phi_add(phi, onfalse, falseval);
+ ir_phi_add(phi, ontrue_out, trueval);
+ ir_phi_add(phi, onfalse_out, falseval);
self->expression.outr = ir_phi_value(phi);
*out = self->expression.outr;
(void)out;
if (self->expression.outr) {
- asterror(ast_ctx(self), "internal error: ast_loop cannot be reused, it bears no result!");
+ compile_error(ast_ctx(self), "internal error: ast_loop cannot be reused, it bears no result!");
return false;
}
self->expression.outr = (ir_value*)1;
*/
if (self->precond)
{
- bprecond = ir_function_create_block(func->ir_func, ast_function_label(func, "pre_loop_cond"));
+ bprecond = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "pre_loop_cond"));
if (!bprecond)
return false;
* generate them this early for 'break' and 'continue'.
*/
if (self->increment) {
- bincrement = ir_function_create_block(func->ir_func, ast_function_label(func, "loop_increment"));
+ bincrement = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "loop_increment"));
if (!bincrement)
return false;
bcontinue = bincrement; /* increment comes before the pre-loop-condition */
}
if (self->postcond) {
- bpostcond = ir_function_create_block(func->ir_func, ast_function_label(func, "post_loop_cond"));
+ bpostcond = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "post_loop_cond"));
if (!bpostcond)
return false;
bcontinue = bpostcond; /* postcond comes before the increment */
}
bout_id = vec_size(func->ir_func->blocks);
- bout = ir_function_create_block(func->ir_func, ast_function_label(func, "after_loop"));
+ bout = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "after_loop"));
if (!bout)
return false;
bbreak = bout;
/* The loop body... */
if (self->body)
{
- bbody = ir_function_create_block(func->ir_func, ast_function_label(func, "loop_body"));
+ bbody = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "loop_body"));
if (!bbody)
return false;
old_bcontinue = func->continueblock;
func->breakblock = bbreak;
func->continueblock = bcontinue;
+ if (!func->continueblock)
+ func->continueblock = bbody;
/* generate */
cgen = self->body->expression.codegen;
else if (bbody) tmpblock = bbody;
else if (bpostcond) tmpblock = bpostcond;
else tmpblock = bout;
- if (!ir_block_create_jump(bin, tmpblock))
+ if (!ir_block_create_jump(bin, ast_ctx(self), tmpblock))
return false;
/* From precond */
else if (bpostcond) ontrue = bpostcond;
else ontrue = bprecond;
onfalse = bout;
- if (!ir_block_create_if(end_bprecond, precond, ontrue, onfalse))
+ if (!ir_block_create_if(end_bprecond, ast_ctx(self), precond, ontrue, onfalse))
return false;
}
if (bincrement) tmpblock = bincrement;
else if (bpostcond) tmpblock = bpostcond;
else if (bprecond) tmpblock = bprecond;
- else tmpblock = bout;
- if (!end_bbody->final && !ir_block_create_jump(end_bbody, tmpblock))
+ else tmpblock = bbody;
+ if (!end_bbody->final && !ir_block_create_jump(end_bbody, ast_ctx(self), tmpblock))
return false;
}
else if (bprecond) tmpblock = bprecond;
else if (bbody) tmpblock = bbody;
else tmpblock = bout;
- if (!ir_block_create_jump(end_bincrement, tmpblock))
+ if (!ir_block_create_jump(end_bincrement, ast_ctx(self), tmpblock))
return false;
}
else if (bincrement) ontrue = bincrement;
else ontrue = bpostcond;
onfalse = bout;
- if (!ir_block_create_if(end_bpostcond, postcond, ontrue, onfalse))
+ if (!ir_block_create_if(end_bpostcond, ast_ctx(self), postcond, ontrue, onfalse))
return false;
}
*out = NULL;
if (lvalue) {
- asterror(ast_ctx(self), "break/continue expression is not an l-value");
+ compile_error(ast_ctx(self), "break/continue expression is not an l-value");
return false;
}
if (self->expression.outr) {
- asterror(ast_ctx(self), "internal error: ast_breakcont cannot be reused!");
+ compile_error(ast_ctx(self), "internal error: ast_breakcont cannot be reused!");
return false;
}
self->expression.outr = (ir_value*)1;
else
target = func->breakblock;
- if (!ir_block_create_jump(func->curblock, target))
+ if (!target) {
+ compile_error(ast_ctx(self), "%s is lacking a target block", (self->is_continue ? "continue" : "break"));
+ return false;
+ }
+
+ if (!ir_block_create_jump(func->curblock, ast_ctx(self), target))
return false;
return true;
}
uint16_t cmpinstr;
if (lvalue) {
- asterror(ast_ctx(self), "switch expression is not an l-value");
+ compile_error(ast_ctx(self), "switch expression is not an l-value");
return false;
}
if (self->expression.outr) {
- asterror(ast_ctx(self), "internal error: ast_switch cannot be reused!");
+ compile_error(ast_ctx(self), "internal error: ast_switch cannot be reused!");
return false;
}
self->expression.outr = (ir_value*)1;
cmpinstr = type_eq_instr[irop->vtype];
if (cmpinstr >= AINSTR_END) {
ast_type_to_string(self->operand, typestr, sizeof(typestr));
- asterror(ast_ctx(self), "invalid type to perform a switch on: %s", typestr);
+ compile_error(ast_ctx(self), "invalid type to perform a switch on: %s", typestr);
return false;
}
bout_id = vec_size(func->ir_func->blocks);
- bout = ir_function_create_block(func->ir_func, ast_function_label(func, "after_switch"));
+ bout = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "after_switch"));
if (!bout)
return false;
if (!(*cgen)((ast_expression*)(swcase->value), func, false, &val))
return false;
/* generate the condition */
- cond = ir_block_create_binop(func->curblock, ast_function_label(func, "switch_eq"), cmpinstr, irop, val);
+ cond = ir_block_create_binop(func->curblock, ast_ctx(self), ast_function_label(func, "switch_eq"), cmpinstr, irop, val);
if (!cond)
return false;
- bcase = ir_function_create_block(func->ir_func, ast_function_label(func, "case"));
+ bcase = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "case"));
bnot_id = vec_size(func->ir_func->blocks);
- bnot = ir_function_create_block(func->ir_func, ast_function_label(func, "not_case"));
+ bnot = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "not_case"));
if (!bcase || !bnot)
return false;
- if (!ir_block_create_if(func->curblock, cond, bcase, bnot))
+ if (!ir_block_create_if(func->curblock, ast_ctx(self), cond, bcase, bnot))
return false;
/* Make the previous case-end fall through */
if (bfall && !bfall->final) {
- if (!ir_block_create_jump(bfall, bcase))
+ if (!ir_block_create_jump(bfall, ast_ctx(self), bcase))
return false;
}
}
/* Jump from the last bnot to bout */
- if (bfall && !bfall->final && !ir_block_create_jump(bfall, bout)) {
+ if (bfall && !bfall->final && !ir_block_create_jump(bfall, ast_ctx(self), bout)) {
/*
astwarning(ast_ctx(bfall), WARN_???, "missing break after last case");
*/
/* Insert the fallthrough jump */
if (def_bfall && !def_bfall->final) {
- if (!ir_block_create_jump(def_bfall, bcase))
+ if (!ir_block_create_jump(def_bfall, ast_ctx(self), bcase))
return false;
}
}
/* Jump from the last bnot to bout */
- if (!func->curblock->final && !ir_block_create_jump(func->curblock, bout))
+ if (!func->curblock->final && !ir_block_create_jump(func->curblock, ast_ctx(self), bout))
return false;
/* enter the outgoing block */
func->curblock = bout;
*out = NULL;
if (lvalue) {
- asterror(ast_ctx(self), "internal error: ast_label cannot be an lvalue");
+ compile_error(ast_ctx(self), "internal error: ast_label cannot be an lvalue");
return false;
}
/* simply create a new block and jump to it */
- self->irblock = ir_function_create_block(func->ir_func, self->name);
+ self->irblock = ir_function_create_block(ast_ctx(self), func->ir_func, self->name);
if (!self->irblock) {
- asterror(ast_ctx(self), "failed to allocate label block `%s`", self->name);
+ compile_error(ast_ctx(self), "failed to allocate label block `%s`", self->name);
return false;
}
if (!func->curblock->final) {
- if (!ir_block_create_jump(func->curblock, self->irblock))
+ if (!ir_block_create_jump(func->curblock, ast_ctx(self), self->irblock))
return false;
}
{
*out = NULL;
if (lvalue) {
- asterror(ast_ctx(self), "internal error: ast_goto cannot be an lvalue");
+ compile_error(ast_ctx(self), "internal error: ast_goto cannot be an lvalue");
return false;
}
if (self->irblock_from) {
/* we already tried once, this is the callback */
self->irblock_from->final = false;
- if (!ir_block_create_jump(self->irblock_from, self->target->irblock)) {
- asterror(ast_ctx(self), "failed to generate goto to `%s`", self->name);
+ if (!ir_block_create_jump(self->irblock_from, ast_ctx(self), self->target->irblock)) {
+ compile_error(ast_ctx(self), "failed to generate goto to `%s`", self->name);
return false;
}
}
else
{
- if (!ir_block_create_jump(func->curblock, self->target->irblock)) {
- asterror(ast_ctx(self), "failed to generate goto to `%s`", self->name);
+ if (!ir_block_create_jump(func->curblock, ast_ctx(self), self->target->irblock)) {
+ compile_error(ast_ctx(self), "failed to generate goto to `%s`", self->name);
return false;
}
}
/* return values are never lvalues */
if (lvalue) {
- asterror(ast_ctx(self), "not an l-value (function call)");
+ compile_error(ast_ctx(self), "not an l-value (function call)");
return false;
}
vec_push(params, param);
}
- callinstr = ir_block_create_call(func->curblock, ast_function_label(func, "call"), funval);
+ callinstr = ir_block_create_call(func->curblock, ast_ctx(self), ast_function_label(func, "call"), funval);
if (!callinstr)
goto error;