/*
- * Copyright (C) 2012
+ * Copyright (C) 2012, 2013
* Wolfgang Bumiller
+ * Dale Weiler
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
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)
return false;
if (vec_size(a->expression.params) != vec_size(b->expression.params))
return false;
- if (a->expression.flags != b->expression.flags)
+ if ((a->expression.flags & AST_FLAG_TYPE_MASK) !=
+ (b->expression.flags & AST_FLAG_TYPE_MASK) )
+ {
return false;
+ }
if (vec_size(a->expression.params)) {
size_t i;
for (i = 0; i < vec_size(a->expression.params); ++i) {
self->setter = NULL;
self->getter = NULL;
+ self->desc = NULL;
return self;
}
}
if (self->ir_values)
mem_d(self->ir_values);
+
+ if (self->desc)
+ mem_d(self->desc);
+
ast_expression_delete((ast_expression*)self);
mem_d(self);
}
self->expression.next = ast_shallow_type(ctx, TYPE_FLOAT);
}
- self->owner = owner;
+ self->rvalue = false;
+ self->owner = owner;
ast_propagate_effects(self, owner);
self->field = field;
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_breakcont* ast_breakcont_new(lex_ctx ctx, bool iscont)
+ast_breakcont* ast_breakcont_new(lex_ctx ctx, bool iscont, unsigned int levels)
{
ast_instantiate(ast_breakcont, ctx, ast_breakcont_delete);
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_breakcont_codegen);
self->is_continue = iscont;
+ self->levels = levels;
return 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;
}
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]))) {
+ if (!ast_compare_type(self->params[i], (ast_expression*)(func->expression.params[i])))
+ {
char texp[1024];
char tgot[1024];
ast_type_to_string(self->params[i], tgot, sizeof(tgot));
self->ir_func = NULL;
self->curblock = NULL;
- self->breakblock = NULL;
- self->continueblock = NULL;
+ self->breakblocks = NULL;
+ self->continueblocks = NULL;
vtype->hasvalue = true;
vtype->constval.vfunc = self;
for (i = 0; i < vec_size(self->blocks); ++i)
ast_delete(self->blocks[i]);
vec_free(self->blocks);
+ vec_free(self->breakblocks);
+ vec_free(self->continueblocks);
mem_d(self);
}
{
(void)func;
(void)lvalue;
+ if (self->expression.vtype == TYPE_NIL) {
+ *out = func->ir_func->owner->nil;
+ return true;
+ }
/* NOTE: This is the codegen for a variable used in an expression.
* It is not the codegen to generate the value. For this purpose,
* ast_local_codegen and ast_global_codegen are to be used before this
{
ir_value *v = NULL;
+ if (self->expression.vtype == TYPE_NIL) {
+ compile_error(ast_ctx(self), "internal error: trying to generate a variable of TYPE_NIL");
+ return false;
+ }
+
if (self->hasvalue && self->expression.vtype == TYPE_FUNCTION)
{
ir_function *func = ir_builder_create_function(ir, self->name, self->expression.next->expression.vtype);
bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
{
ir_value *v = NULL;
+
+ if (self->expression.vtype == TYPE_NIL) {
+ compile_error(ast_ctx(self), "internal error: trying to generate a variable of TYPE_NIL");
+ return false;
+ }
+
if (self->hasvalue && self->expression.vtype == TYPE_FUNCTION)
{
/* Do we allow local functions? I think not...
}
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;
}
ir_value *vec;
/* in QC this is always an lvalue */
- (void)lvalue;
+ if (lvalue && self->rvalue) {
+ compile_error(ast_ctx(self), "not an l-value (member access)");
+ return false;
+ }
if (self->expression.outl) {
*out = self->expression.outl;
return true;
}
cgen = self->owner->expression.codegen;
- if (!(*cgen)((ast_expression*)(self->owner), func, true, &vec))
+ if (!(*cgen)((ast_expression*)(self->owner), func, false, &vec))
return false;
if (vec->vtype != TYPE_VECTOR &&
/* 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);
ir_block *bcontinue = NULL;
ir_block *bbreak = NULL;
- ir_block *old_bcontinue = NULL;
- ir_block *old_bbreak = NULL;
-
ir_block *tmpblock = NULL;
(void)lvalue;
/* enter */
func->curblock = bbody;
- old_bbreak = func->breakblock;
- old_bcontinue = func->continueblock;
- func->breakblock = bbreak;
- func->continueblock = bcontinue;
- if (!func->continueblock)
- func->continueblock = bbody;
+ vec_push(func->breakblocks, bbreak);
+ if (bcontinue)
+ vec_push(func->continueblocks, bcontinue);
+ else
+ vec_push(func->continueblocks, bbody);
/* generate */
if (self->body) {
}
end_bbody = func->curblock;
- func->breakblock = old_bbreak;
- func->continueblock = old_bcontinue;
+ vec_pop(func->breakblocks);
+ vec_pop(func->continueblocks);
}
/* post-loop-condition */
self->expression.outr = (ir_value*)1;
if (self->is_continue)
- target = func->continueblock;
+ target = func->continueblocks[vec_size(func->continueblocks)-1-self->levels];
else
- target = func->breakblock;
+ target = func->breakblocks[vec_size(func->breakblocks)-1-self->levels];
if (!target) {
compile_error(ast_ctx(self), "%s is lacking a target block", (self->is_continue ? "continue" : "break"));
ir_value *dummy = NULL;
ir_value *irop = NULL;
- ir_block *old_break = NULL;
ir_block *bout = NULL;
ir_block *bfall = NULL;
size_t bout_id;
return false;
/* setup the break block */
- old_break = func->breakblock;
- func->breakblock = bout;
+ vec_push(func->breakblocks, bout);
/* Now create all cases */
for (c = 0; c < vec_size(self->cases); ++c) {
func->curblock = bout;
/* restore the break block */
- func->breakblock = old_break;
+ vec_pop(func->breakblocks);
/* Move 'bout' to the end, it's nicer */
vec_remove(func->ir_func->blocks, bout_id, 1);
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");