( (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)
{
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;
}
}
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;
}
}
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(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;
}
{
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)
{
else
{
/* 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`)",
+ self->name))
+ {
+ return false;
+ }
}
-#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))
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;
}
/* 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;
}
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,
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,
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,
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;
}
/* 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;
}
* 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;
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
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;
}
else if (idx->expression.vtype == TYPE_INTEGER)
*out = arr->ir_values[idx->constval.vint];
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;
(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;
(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;
*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;
target = func->breakblock;
if (!target) {
- asterror(ast_ctx(self), "%s is lacking a target block", (self->is_continue ? "continue" : "break"));
+ compile_error(ast_ctx(self), "%s is lacking a target block", (self->is_continue ? "continue" : "break"));
return false;
}
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;
}
*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(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) {
{
*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;
}
/* 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);
+ 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);
+ 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;
}