#include "gmqcc.h"
#include "ast.h"
-#include "parser.h"
+#include "fold.h"
+//#include "parser.h"
+
+#include "algo.h"
#define ast_instantiate(T, ctx, destroyfn) \
T* self = (T*)mem_a(sizeof(T)); \
if (!self) { \
- return NULL; \
+ return nullptr; \
} \
new (self) T(); \
ast_node_init((ast_node*)self, ctx, TYPE_##T); \
}
/* Initialize main ast node aprts */
-static void ast_node_init(ast_node *self, lex_ctx_t ctx, int nodetype)
+static void ast_node_init(ast_node *self, lex_ctx_t ctx, int node_type)
{
self->context = ctx;
- self->destroy = &_ast_node_destroy;
- self->keep = false;
- self->nodetype = nodetype;
+ self->destroy = &_ast_node_destroy;
+ self->keep_node = false;
+ self->node_type = node_type;
self->side_effects = false;
}
{
self->codegen = codegen;
self->vtype = TYPE_VOID;
- self->next = NULL;
- self->outl = NULL;
- self->outr = NULL;
+ self->next = nullptr;
+ self->outl = nullptr;
+ self->outr = nullptr;
self->count = 0;
- self->varparam = NULL;
+ self->varparam = nullptr;
self->flags = 0;
if (OPTS_OPTION_BOOL(OPTION_COVERAGE))
self->flags |= AST_FLAG_BLOCK_COVERAGE;
{
if (self->next)
ast_delete(self->next);
- for (auto &it : self->params)
+ for (auto &it : self->type_params)
ast_delete(it);
if (self->varparam)
ast_delete(self->varparam);
ast_value* ast_value_copy(const ast_value *self)
{
- const ast_expression *fromex;
- ast_expression *selfex;
- ast_value *cp = ast_value_new(self->expression.node.context, self->name, self->expression.vtype);
- if (self->expression.next) {
- cp->expression.next = ast_type_copy(self->expression.node.context, self->expression.next);
+ ast_value *cp = ast_value_new(self->context, self->name, self->vtype);
+ if (self->next) {
+ cp->next = ast_type_copy(self->context, self->next);
}
- fromex = &self->expression;
- selfex = &cp->expression;
+ const ast_expression *fromex = self;
+ ast_expression *selfex = cp;
selfex->count = fromex->count;
selfex->flags = fromex->flags;
- for (auto &it : fromex->params) {
+ for (auto &it : fromex->type_params) {
ast_value *v = ast_value_copy(it);
- selfex->params.push_back(v);
+ selfex->type_params.push_back(v);
}
return cp;
}
selfex = self;
selfex->count = fromex->count;
selfex->flags = fromex->flags;
- for (auto &it : fromex->params) {
+ for (auto &it : fromex->type_params) {
ast_value *v = ast_value_copy(it);
- selfex->params.push_back(v);
+ selfex->type_params.push_back(v);
}
}
-static ast_expression* ast_shallow_type(lex_ctx_t ctx, int vtype)
+static ast_expression* ast_shallow_type(lex_ctx_t ctx, qc_type vtype)
{
ast_instantiate(ast_expression, ctx, ast_expression_delete_full);
- ast_expression_init(self, NULL);
- self->codegen = NULL;
- self->next = NULL;
+ ast_expression_init(self, nullptr);
+ self->codegen = nullptr;
+ self->next = nullptr;
self->vtype = vtype;
return self;
}
ast_expression *selfex;
if (!ex)
- return NULL;
+ return nullptr;
else
{
ast_instantiate(ast_expression, ctx, ast_expression_delete_full);
- ast_expression_init(self, NULL);
+ ast_expression_init(self, nullptr);
fromex = ex;
selfex = self;
/* This may never be codegen()d */
- selfex->codegen = NULL;
+ selfex->codegen = nullptr;
selfex->vtype = fromex->vtype;
if (fromex->next)
selfex->next = ast_type_copy(ctx, fromex->next);
else
- selfex->next = NULL;
+ selfex->next = nullptr;
selfex->count = fromex->count;
selfex->flags = fromex->flags;
- for (auto &it : fromex->params) {
+ for (auto &it : fromex->type_params) {
ast_value *v = ast_value_copy(it);
- selfex->params.push_back(v);
+ selfex->type_params.push_back(v);
}
return self;
return false;
if (!a->next != !b->next)
return false;
- if (a->params.size() != b->params.size())
+ if (a->type_params.size() != b->type_params.size())
return false;
if ((a->flags & AST_FLAG_TYPE_MASK) !=
(b->flags & AST_FLAG_TYPE_MASK) )
{
return false;
}
- if (a->params.size()) {
+ if (a->type_params.size()) {
size_t i;
- for (i = 0; i < a->params.size(); ++i) {
- if (!ast_compare_type((ast_expression*)a->params[i],
- (ast_expression*)b->params[i]))
+ for (i = 0; i < a->type_params.size(); ++i) {
+ if (!ast_compare_type((ast_expression*)a->type_params[i],
+ (ast_expression*)b->type_params[i]))
return false;
}
}
pos = ast_type_to_string_impl(e->next, buf, bufsize, pos);
if (pos + 2 >= bufsize)
goto full;
- if (e->params.empty()) {
+ if (e->type_params.empty()) {
buf[pos++] = '(';
buf[pos++] = ')';
return pos;
}
buf[pos++] = '(';
- pos = ast_type_to_string_impl((ast_expression*)(e->params[0]), buf, bufsize, pos);
- for (i = 1; i < e->params.size(); ++i) {
+ pos = ast_type_to_string_impl((ast_expression*)(e->type_params[0]), buf, bufsize, pos);
+ for (i = 1; i < e->type_params.size(); ++i) {
if (pos + 2 >= bufsize)
goto full;
buf[pos++] = ',';
buf[pos++] = ' ';
- pos = ast_type_to_string_impl((ast_expression*)(e->params[i]), buf, bufsize, pos);
+ pos = ast_type_to_string_impl((ast_expression*)(e->type_params[i]), buf, bufsize, pos);
}
if (pos + 1 >= bufsize)
goto full;
}
static bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_value **out);
-ast_value* ast_value_new(lex_ctx_t ctx, const char *name, int t)
+ast_value* ast_value_new(lex_ctx_t ctx, const char *name, qc_type t)
{
ast_instantiate(ast_value, ctx, ast_value_delete);
ast_expression_init((ast_expression*)self,
(ast_expression_codegen*)&ast_value_codegen);
- self->expression.node.keep = true; /* keep */
+ self->keep_node = true; /* keep */
- self->name = name ? util_strdup(name) : NULL;
- self->expression.vtype = t;
- self->expression.next = NULL;
+ self->name = name ? util_strdup(name) : nullptr;
+ self->vtype = t;
+ self->next = nullptr;
self->isfield = false;
self->cvq = CV_NONE;
self->hasvalue = false;
self->inexact = false;
self->uses = 0;
memset(&self->constval, 0, sizeof(self->constval));
- self->initlist = NULL;
- self->ir_v = NULL;
- self->ir_values = NULL;
+ self->ir_v = nullptr;
+ self->ir_values = nullptr;
self->ir_value_count = 0;
- self->setter = NULL;
- self->getter = NULL;
- self->desc = NULL;
+ self->setter = nullptr;
+ self->getter = nullptr;
+ self->desc = nullptr;
- self->argcounter = NULL;
+ self->argcounter = nullptr;
self->intrinsic = false;
return self;
if (self->argcounter)
mem_d((void*)self->argcounter);
if (self->hasvalue) {
- switch (self->expression.vtype)
+ switch (self->vtype)
{
case TYPE_STRING:
mem_d((void*)self->constval.vstring);
break;
case TYPE_FUNCTION:
/* unlink us from the function node */
- self->constval.vfunc->vtype = NULL;
+ self->constval.vfunc->function_type = nullptr;
break;
/* NOTE: delete function? currently collected in
* the parser structure
if (self->desc)
mem_d(self->desc);
- if (self->initlist) {
- if (self->expression.next->vtype == TYPE_STRING) {
- /* strings are allocated, free them */
- size_t i, len = vec_size(self->initlist);
- /* in theory, len should be expression.count
- * but let's not take any chances */
- for (i = 0; i < len; ++i) {
- if (self->initlist[i].vstring)
- mem_d(self->initlist[i].vstring);
- }
- }
- vec_free(self->initlist);
+ // initlist imples an array which implies .next in the expression exists.
+ if (self->initlist.size() && self->next->vtype == TYPE_STRING) {
+ for (auto &it : self->initlist)
+ if (it.vstring)
+ mem_d(it.vstring);
}
ast_expression_delete((ast_expression*)self);
+ self->~ast_value();
mem_d(self);
}
void ast_value_params_add(ast_value *self, ast_value *p)
{
- self->expression.params.push_back(p);
+ self->type_params.push_back(p);
}
bool ast_value_set_name(ast_value *self, const char *name)
ast_propagate_effects(self, right);
if (op >= INSTR_EQ_F && op <= INSTR_GT)
- self->expression.vtype = TYPE_FLOAT;
+ self->vtype = TYPE_FLOAT;
else if (op == INSTR_AND || op == INSTR_OR) {
if (OPTS_FLAG(PERL_LOGIC))
ast_type_adopt(self, right);
else
- self->expression.vtype = TYPE_FLOAT;
+ self->vtype = TYPE_FLOAT;
}
else if (op == INSTR_BITAND || op == INSTR_BITOR)
- self->expression.vtype = TYPE_FLOAT;
+ self->vtype = TYPE_FLOAT;
else if (op == INSTR_MUL_VF || op == INSTR_MUL_FV)
- self->expression.vtype = TYPE_VECTOR;
+ self->vtype = TYPE_VECTOR;
else if (op == INSTR_MUL_V)
- self->expression.vtype = TYPE_FLOAT;
+ self->vtype = TYPE_FLOAT;
else
- self->expression.vtype = left->vtype;
+ self->vtype = left->vtype;
/* references all */
self->refs = AST_REF_ALL;
if (self->refs & AST_REF_RIGHT) ast_unref(self->right);
ast_expression_delete((ast_expression*)self);
+ self->~ast_binary();
mem_d(self);
}
ast_unref(self->dest);
ast_unref(self->source);
ast_expression_delete((ast_expression*)self);
+ self->~ast_binstore();
mem_d(self);
}
ast_propagate_effects(self, expr);
if ((op >= INSTR_NOT_F && op <= INSTR_NOT_FNC) || op == VINSTR_NEG_F) {
- self->expression.vtype = TYPE_FLOAT;
+ self->vtype = TYPE_FLOAT;
} else if (op == VINSTR_NEG_V) {
- self->expression.vtype = TYPE_VECTOR;
+ self->vtype = TYPE_VECTOR;
} else {
compile_error(ctx, "cannot determine type of unary operation %s", util_instr_str[op]);
}
{
if (self->operand) ast_unref(self->operand);
ast_expression_delete((ast_expression*)self);
+ self->~ast_unary();
mem_d(self);
}
if (self->operand)
ast_unref(self->operand);
ast_expression_delete((ast_expression*)self);
+ self->~ast_return();
mem_d(self);
}
{
if (field->vtype != TYPE_FIELD) {
compile_error(ctx, "ast_entfield_new with expression not of type field");
- return NULL;
+ return nullptr;
}
return ast_entfield_new_force(ctx, entity, field, field->next);
}
if (!outtype) {
mem_d(self);
/* Error: field has no type... */
- return NULL;
+ return nullptr;
}
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_entfield_codegen);
ast_unref(self->entity);
ast_unref(self->field);
ast_expression_delete((ast_expression*)self);
+ self->~ast_entfield();
mem_d(self);
}
ast_instantiate(ast_member, ctx, ast_member_delete);
if (field >= 3) {
mem_d(self);
- return NULL;
+ return nullptr;
}
if (owner->vtype != TYPE_VECTOR &&
owner->vtype != TYPE_FIELD) {
compile_error(ctx, "member-access on an invalid owner of type %s", type_name[owner->vtype]);
mem_d(self);
- return NULL;
+ return nullptr;
}
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_member_codegen);
- self->expression.node.keep = true; /* keep */
+ self->keep_node = true; /* keep */
if (owner->vtype == TYPE_VECTOR) {
- self->expression.vtype = TYPE_FLOAT;
- self->expression.next = NULL;
+ self->vtype = TYPE_FLOAT;
+ self->next = nullptr;
} else {
- self->expression.vtype = TYPE_FIELD;
- self->expression.next = ast_shallow_type(ctx, TYPE_FLOAT);
+ self->vtype = TYPE_FIELD;
+ self->next = ast_shallow_type(ctx, TYPE_FLOAT);
}
self->rvalue = false;
if (name)
self->name = util_strdup(name);
else
- self->name = NULL;
+ self->name = nullptr;
return self;
}
void ast_member_delete(ast_member *self)
{
- /* The owner is always an ast_value, which has .keep=true,
+ /* The owner is always an ast_value, which has .keep_node=true,
* also: ast_members are usually deleted after the owner, thus
* this will cause invalid access
ast_unref(self->owner);
*/
ast_expression_delete((ast_expression*)self);
mem_d(self->name);
+ self->~ast_member();
mem_d(self);
}
if (!outtype) {
mem_d(self);
/* Error: field has no type... */
- return NULL;
+ return nullptr;
}
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_array_index_codegen);
ast_type_adopt(self, outtype);
if (array->vtype == TYPE_FIELD && outtype->vtype == TYPE_ARRAY) {
- if (self->expression.vtype != TYPE_ARRAY) {
+ if (self->vtype != TYPE_ARRAY) {
compile_error(ast_ctx(self), "array_index node on type");
ast_array_index_delete(self);
- return NULL;
+ return nullptr;
}
self->array = outtype;
- self->expression.vtype = TYPE_FIELD;
+ self->vtype = TYPE_FIELD;
}
return self;
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;
+ self->vtype = TYPE_NOEXPR;
return self;
}
if (self->index)
ast_unref(self->index);
ast_expression_delete((ast_expression*)self);
+ self->~ast_argpipe();
mem_d(self);
}
if (!ontrue && !onfalse) {
/* because it is invalid */
mem_d(self);
- return NULL;
+ return nullptr;
}
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_ifthen_codegen);
if (self->on_false)
ast_unref(self->on_false);
ast_expression_delete((ast_expression*)self);
+ self->~ast_ifthen();
mem_d(self);
}
{
ast_expression *exprtype = ontrue;
ast_instantiate(ast_ternary, ctx, ast_ternary_delete);
- /* This time NEITHER must be NULL */
+ /* This time NEITHER must be nullptr */
if (!ontrue || !onfalse) {
mem_d(self);
- return NULL;
+ return nullptr;
}
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_ternary_codegen);
void ast_ternary_delete(ast_ternary *self)
{
/* the if()s are only there because computed-gotos can set them
- * to NULL
+ * to nullptr
*/
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);
+ self->~ast_ternary();
mem_d(self);
}
if (self->body)
ast_unref(self->body);
ast_expression_delete((ast_expression*)self);
+ self->~ast_loop();
mem_d(self);
}
void ast_breakcont_delete(ast_breakcont *self)
{
ast_expression_delete((ast_expression*)self);
+ self->~ast_breakcont();
mem_d(self);
}
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_switch_codegen);
self->operand = op;
- self->cases = NULL;
ast_propagate_effects(self, op);
void ast_switch_delete(ast_switch *self)
{
- size_t i;
ast_unref(self->operand);
- for (i = 0; i < vec_size(self->cases); ++i) {
- if (self->cases[i].value)
- ast_unref(self->cases[i].value);
- ast_unref(self->cases[i].code);
+ for (auto &it : self->cases) {
+ if (it.value)
+ ast_unref(it.value);
+ ast_unref(it.code);
}
- vec_free(self->cases);
ast_expression_delete((ast_expression*)self);
+ self->~ast_switch();
mem_d(self);
}
ast_instantiate(ast_label, ctx, ast_label_delete);
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_label_codegen);
- self->expression.vtype = TYPE_NOEXPR;
+ self->vtype = TYPE_NOEXPR;
self->name = util_strdup(name);
- self->irblock = NULL;
+ self->irblock = nullptr;
self->undefined = undefined;
return self;
{
mem_d((void*)self->name);
ast_expression_delete((ast_expression*)self);
+ self->~ast_label();
mem_d(self);
}
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_goto_codegen);
self->name = util_strdup(name);
- self->target = NULL;
- self->irblock_from = NULL;
+ self->target = nullptr;
+ self->irblock_from = nullptr;
return self;
}
{
mem_d((void*)self->name);
ast_expression_delete((ast_expression*)self);
+ self->~ast_goto();
mem_d(self);
}
ast_unref(self->nextthink);
ast_expression_delete((ast_expression*)self);
+ self->~ast_state();
mem_d(self);
}
if (!funcexpr->next) {
compile_error(ctx, "not a function");
mem_d(self);
- return NULL;
+ return nullptr;
}
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_call_codegen);
ast_side_effects(self) = true;
self->func = funcexpr;
- self->va_count = NULL;
+ self->va_count = nullptr;
ast_type_adopt(self, funcexpr->next);
ast_unref(self->va_count);
ast_expression_delete((ast_expression*)self);
+ self->~ast_call();
mem_d(self);
}
bool retval = true;
const ast_expression *func = self->func;
size_t count = self->params.size();
- if (count > func->params.size())
- count = func->params.size();
+ if (count > func->type_params.size())
+ count = func->type_params.size();
for (i = 0; i < count; ++i) {
if (ast_istype(self->params[i], ast_argpipe)) {
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]))
+ if (!ast_call_check_vararg(self, va_type, (ast_expression*)func->type_params[i]))
retval = false;
}
- else if (!ast_compare_type(self->params[i], (ast_expression*)(func->params[i])))
+ else if (!ast_compare_type(self->params[i], (ast_expression*)(func->type_params[i])))
{
ast_type_to_string(self->params[i], tgot, sizeof(tgot));
- ast_type_to_string((ast_expression*)func->params[i], texp, sizeof(texp));
+ ast_type_to_string((ast_expression*)func->type_params[i], 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 */
}
}
count = self->params.size();
- if (count > func->params.size() && func->varparam) {
+ if (count > func->type_params.size() && func->varparam) {
for (; i < count; ++i) {
if (ast_istype(self->params[i], ast_argpipe)) {
/* warn about type safety instead */
ast_unref(self->dest);
ast_unref(self->source);
ast_expression_delete((ast_expression*)self);
+ self->~ast_store();
mem_d(self);
}
{
ast_propagate_effects(self, e);
self->exprs.push_back(e);
- if (self->expression.next) {
- ast_delete(self->expression.next);
- self->expression.next = NULL;
+ if (self->next) {
+ ast_delete(self->next);
+ self->next = nullptr;
}
ast_type_adopt(self, e);
return true;
void ast_block_collect(ast_block *self, ast_expression *expr)
{
self->collect.push_back(expr);
- expr->node.keep = true;
+ expr->keep_node = true;
}
void ast_block_delete(ast_block *self)
for (auto &it : self->locals) ast_delete(it);
for (auto &it : self->collect) ast_delete(it);
ast_expression_delete((ast_expression*)self);
+ self->~ast_block();
mem_d(self);
}
void ast_block_set_type(ast_block *self, ast_expression *from)
{
- if (self->expression.next)
- ast_delete(self->expression.next);
+ if (self->next)
+ ast_delete(self->next);
ast_type_adopt(self, from);
}
if (!vtype) {
compile_error(ast_ctx(self), "internal error: ast_function_new condition 0");
goto cleanup;
- } else if (vtype->hasvalue || vtype->expression.vtype != TYPE_FUNCTION) {
+ } else if (vtype->hasvalue || vtype->vtype != TYPE_FUNCTION) {
compile_error(ast_ctx(self), "internal error: ast_function_new condition %i %i type=%i (probably 2 bodies?)",
(int)!vtype,
(int)vtype->hasvalue,
- vtype->expression.vtype);
+ vtype->vtype);
goto cleanup;
}
- self->vtype = vtype;
- self->name = name ? util_strdup(name) : NULL;
- self->blocks = NULL;
+ self->function_type = vtype;
+ self->name = name ? util_strdup(name) : nullptr;
self->labelcount = 0;
self->builtin = 0;
- self->ir_func = NULL;
- self->curblock = NULL;
-
- self->breakblocks = NULL;
- self->continueblocks = NULL;
+ self->ir_func = nullptr;
+ self->curblock = nullptr;
vtype->hasvalue = true;
vtype->constval.vfunc = self;
- self->varargs = NULL;
- self->argc = NULL;
- self->fixedparams = NULL;
- self->return_value = NULL;
-
- self->static_names = NULL;
+ self->varargs = nullptr;
+ self->argc = nullptr;
+ self->fixedparams = nullptr;
+ self->return_value = nullptr;
self->static_count = 0;
return self;
cleanup:
mem_d(self);
- return NULL;
+ return nullptr;
}
void ast_function_delete(ast_function *self)
{
- size_t i;
if (self->name)
mem_d((void*)self->name);
- if (self->vtype) {
- /* ast_value_delete(self->vtype); */
- self->vtype->hasvalue = false;
- self->vtype->constval.vfunc = NULL;
+ if (self->function_type) {
+ /* ast_value_delete(self->function_type); */
+ self->function_type->hasvalue = false;
+ self->function_type->constval.vfunc = nullptr;
/* We use unref - if it was stored in a global table it is supposed
* to be deleted from *there*
*/
- ast_unref(self->vtype);
- }
- for (i = 0; i < vec_size(self->static_names); ++i)
- mem_d(self->static_names[i]);
- vec_free(self->static_names);
- 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);
+ ast_unref(self->function_type);
+ }
+ for (auto &it : self->static_names)
+ mem_d(it);
+ // FIXME::DELME:: unique_ptr used on ast_block
+ //for (auto &it : self->blocks)
+ // ast_delete(it);
if (self->varargs)
ast_delete(self->varargs);
if (self->argc)
ast_unref(self->fixedparams);
if (self->return_value)
ast_unref(self->return_value);
+ self->~ast_function();
mem_d(self);
}
!OPTS_OPTION_BOOL(OPTION_DUMPFIN) &&
!OPTS_OPTION_BOOL(OPTION_DEBUG))
{
- return NULL;
+ return nullptr;
}
id = (self->labelcount++);
/*********************************************************************/
/* AST codegen part
- * by convention you must never pass NULL to the 'ir_value **out'
+ * by convention you must never pass nullptr to the 'ir_value **out'
* parameter. If you really don't care about the output, pass a dummy.
* But I can't imagine a pituation where the output is truly unnecessary.
*/
out->outtype = self->next->vtype;
}
-#define codegen_output_type(a,o) (_ast_codegen_output_type(&((a)->expression),(o)))
+#define codegen_output_type(a,o) (_ast_codegen_output_type(static_cast<ast_expression*>((a)),(o)))
bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_value **out)
{
(void)func;
(void)lvalue;
- if (self->expression.vtype == TYPE_NIL) {
+ if (self->vtype == TYPE_NIL) {
*out = func->ir_func->owner->nil;
return true;
}
- /* NOTE: This is the codegen for a variable used in an expression.
+ /* NOTE: This is the codegen for a variable used in an
* 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
* is executed. ast_function_codegen should take care of its locals,
static bool ast_global_array_set(ast_value *self)
{
- size_t count = vec_size(self->initlist);
+ size_t count = self->initlist.size();
size_t i;
- if (count > self->expression.count) {
+ if (count > self->count) {
compile_error(ast_ctx(self), "too many elements in initializer");
- count = self->expression.count;
+ count = self->count;
}
- else if (count < self->expression.count) {
+ else if (count < self->count) {
/* add this?
compile_warning(ast_ctx(self), "not all elements are initialized");
*/
}
for (i = 0; i != count; ++i) {
- switch (self->expression.next->vtype) {
+ switch (self->next->vtype) {
case TYPE_FLOAT:
if (!ir_value_set_float(self->ir_values[i], self->initlist[i].vfloat))
return false;
return false;
break;
default:
- compile_error(ast_ctx(self), "TODO: global constant type %i", self->expression.vtype);
+ compile_error(ast_ctx(self), "TODO: global constant type %i", self->vtype);
break;
}
}
static bool check_array(ast_value *self, ast_value *array)
{
- if (array->expression.flags & AST_FLAG_ARRAY_INIT && !array->initlist) {
+ if (array->flags & AST_FLAG_ARRAY_INIT && array->initlist.empty()) {
compile_error(ast_ctx(self), "array without size: %s", self->name);
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_OPTION_U32(OPTION_MAX_ARRAY_SIZE)) {
- compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)array->expression.count);
+ if (!array->count || array->count > OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE)) {
+ compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)array->count);
return false;
}
return true;
bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
{
- ir_value *v = NULL;
+ ir_value *v = nullptr;
- if (self->expression.vtype == TYPE_NIL) {
+ if (self->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)
+ if (self->hasvalue && self->vtype == TYPE_FUNCTION)
{
- ir_function *func = ir_builder_create_function(ir, self->name, self->expression.next->vtype);
+ ir_function *func = ir_builder_create_function(ir, self->name, self->next->vtype);
if (!func)
return false;
func->context = ast_ctx(self);
self->constval.vfunc->ir_func = func;
self->ir_v = func->value;
- if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
+ if (self->flags & AST_FLAG_INCLUDE_DEF)
self->ir_v->flags |= IR_FLAG_INCLUDE_DEF;
- if (self->expression.flags & AST_FLAG_ERASEABLE)
+ if (self->flags & AST_FLAG_ERASEABLE)
self->ir_v->flags |= IR_FLAG_ERASABLE;
- if (self->expression.flags & AST_FLAG_BLOCK_COVERAGE)
+ if (self->flags & AST_FLAG_BLOCK_COVERAGE)
func->flags |= IR_FLAG_BLOCK_COVERAGE;
/* The function is filled later on ast_function_codegen... */
return true;
}
- if (isfield && self->expression.vtype == TYPE_FIELD) {
- ast_expression *fieldtype = self->expression.next;
+ if (isfield && self->vtype == TYPE_FIELD) {
+ ast_expression *fieldtype = self->next;
if (self->hasvalue) {
compile_error(ast_ctx(self), "TODO: constant field pointers with value");
size_t namelen;
ast_expression *elemtype;
- int vtype;
+ qc_type vtype;
ast_value *array = (ast_value*)fieldtype;
if (!ast_istype(fieldtype, ast_value)) {
if (!check_array(self, array))
return false;
- elemtype = array->expression.next;
+ elemtype = array->next;
vtype = elemtype->vtype;
v = ir_builder_create_field(ir, self->name, vtype);
v->locked = true;
array->ir_v = self->ir_v = v;
- if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
+ if (self->flags & AST_FLAG_INCLUDE_DEF)
self->ir_v->flags |= IR_FLAG_INCLUDE_DEF;
- if (self->expression.flags & AST_FLAG_ERASEABLE)
+ if (self->flags & AST_FLAG_ERASEABLE)
self->ir_v->flags |= IR_FLAG_ERASABLE;
namelen = strlen(self->name);
name = (char*)mem_a(namelen + 16);
util_strncpy(name, self->name, namelen);
- array->ir_values = (ir_value**)mem_a(sizeof(array->ir_values[0]) * array->expression.count);
+ array->ir_values = (ir_value**)mem_a(sizeof(array->ir_values[0]) * array->count);
array->ir_values[0] = v;
- for (ai = 1; ai < array->expression.count; ++ai) {
+ for (ai = 1; ai < array->count; ++ai) {
util_snprintf(name + namelen, 16, "[%u]", (unsigned int)ai);
array->ir_values[ai] = ir_builder_create_field(ir, name, vtype);
if (!array->ir_values[ai]) {
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)
+ if (self->flags & AST_FLAG_INCLUDE_DEF)
self->ir_values[ai]->flags |= IR_FLAG_INCLUDE_DEF;
}
mem_d(name);
}
else
{
- v = ir_builder_create_field(ir, self->name, self->expression.next->vtype);
+ v = ir_builder_create_field(ir, self->name, self->next->vtype);
if (!v)
return false;
v->context = ast_ctx(self);
self->ir_v = v;
- if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
+ if (self->flags & AST_FLAG_INCLUDE_DEF)
self->ir_v->flags |= IR_FLAG_INCLUDE_DEF;
- if (self->expression.flags & AST_FLAG_ERASEABLE)
+ if (self->flags & AST_FLAG_ERASEABLE)
self->ir_v->flags |= IR_FLAG_ERASABLE;
}
return true;
}
- if (self->expression.vtype == TYPE_ARRAY) {
+ if (self->vtype == TYPE_ARRAY) {
size_t ai;
char *name;
size_t namelen;
- ast_expression *elemtype = self->expression.next;
- int vtype = elemtype->vtype;
+ ast_expression *elemtype = self->next;
+ qc_type vtype = elemtype->vtype;
- if (self->expression.flags & AST_FLAG_ARRAY_INIT && !self->expression.count) {
+ if (self->flags & AST_FLAG_ARRAY_INIT && !self->count) {
compile_error(ast_ctx(self), "array `%s' has no size", self->name);
return false;
}
v->unique_life = true;
v->locked = true;
- if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
+ if (self->flags & AST_FLAG_INCLUDE_DEF)
v->flags |= IR_FLAG_INCLUDE_DEF;
- if (self->expression.flags & AST_FLAG_ERASEABLE)
+ if (self->flags & AST_FLAG_ERASEABLE)
self->ir_v->flags |= IR_FLAG_ERASABLE;
namelen = strlen(self->name);
name = (char*)mem_a(namelen + 16);
util_strncpy(name, self->name, namelen);
- self->ir_values = (ir_value**)mem_a(sizeof(self->ir_values[0]) * self->expression.count);
+ self->ir_values = (ir_value**)mem_a(sizeof(self->ir_values[0]) * self->count);
self->ir_values[0] = v;
- for (ai = 1; ai < self->expression.count; ++ai) {
+ for (ai = 1; ai < self->count; ++ai) {
util_snprintf(name + namelen, 16, "[%u]", (unsigned int)ai);
self->ir_values[ai] = ir_builder_create_global(ir, name, vtype);
if (!self->ir_values[ai]) {
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)
+ if (self->flags & AST_FLAG_INCLUDE_DEF)
self->ir_values[ai]->flags |= IR_FLAG_INCLUDE_DEF;
}
mem_d(name);
/* Arrays don't do this since there's no "array" value which spans across the
* whole thing.
*/
- v = ir_builder_create_global(ir, self->name, self->expression.vtype);
+ v = ir_builder_create_global(ir, self->name, self->vtype);
if (!v) {
compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name);
return false;
v->cvq = self->cvq;
self->ir_v = v;
- if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
+ if (self->flags & AST_FLAG_INCLUDE_DEF)
self->ir_v->flags |= IR_FLAG_INCLUDE_DEF;
- if (self->expression.flags & AST_FLAG_ERASEABLE)
+ if (self->flags & AST_FLAG_ERASEABLE)
self->ir_v->flags |= IR_FLAG_ERASABLE;
/* initialize */
if (self->hasvalue) {
- switch (self->expression.vtype)
+ switch (self->vtype)
{
case TYPE_FLOAT:
if (!ir_value_set_float(v, self->constval.vfloat))
goto error;
break;
default:
- compile_error(ast_ctx(self), "TODO: global constant type %i", self->expression.vtype);
+ compile_error(ast_ctx(self), "TODO: global constant type %i", self->vtype);
break;
}
}
return true;
error: /* clean up */
- if(v) ir_value_delete(v);
+ if (v) delete v;
return false;
}
static bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
{
- ir_value *v = NULL;
+ ir_value *v = nullptr;
- if (self->expression.vtype == TYPE_NIL) {
+ if (self->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)
+ if (self->hasvalue && self->vtype == TYPE_FUNCTION)
{
/* Do we allow local functions? I think not...
* this is NOT a function pointer atm.
return false;
}
- if (self->expression.vtype == TYPE_ARRAY) {
+ if (self->vtype == TYPE_ARRAY) {
size_t ai;
char *name;
size_t namelen;
- ast_expression *elemtype = self->expression.next;
- int vtype = elemtype->vtype;
+ ast_expression *elemtype = self->next;
+ qc_type vtype = elemtype->vtype;
func->flags |= IR_FLAG_HAS_ARRAYS;
- if (param && !(self->expression.flags & AST_FLAG_IS_VARARG)) {
+ if (param && !(self->flags & AST_FLAG_IS_VARARG)) {
compile_error(ast_ctx(self), "array-parameters are not supported");
return false;
}
if (!check_array(self, self))
return false;
- self->ir_values = (ir_value**)mem_a(sizeof(self->ir_values[0]) * self->expression.count);
+ self->ir_values = (ir_value**)mem_a(sizeof(self->ir_values[0]) * self->count);
if (!self->ir_values) {
compile_error(ast_ctx(self), "failed to allocate array values");
return false;
util_strncpy(name, self->name, namelen);
self->ir_values[0] = v;
- for (ai = 1; ai < self->expression.count; ++ai) {
+ for (ai = 1; ai < self->count; ++ai) {
util_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]) {
}
else
{
- v = ir_function_create_local(func, self->name, self->expression.vtype, param);
+ v = ir_function_create_local(func, self->name, self->vtype, param);
if (!v)
return false;
codegen_output_type(self, v);
* I suppose the IR will have to deal with this
*/
if (self->hasvalue) {
- switch (self->expression.vtype)
+ switch (self->vtype)
{
case TYPE_FLOAT:
if (!ir_value_set_float(v, self->constval.vfloat))
goto error;
break;
default:
- compile_error(ast_ctx(self), "TODO: global constant type %i", self->expression.vtype);
+ compile_error(ast_ctx(self), "TODO: global constant type %i", self->vtype);
break;
}
}
return true;
error: /* clean up */
- ir_value_delete(v);
+ delete v;
return false;
}
bool warn = OPTS_WARN(WARN_USED_UNINITIALIZED);
if (!self->setter || !self->getter)
return true;
- for (i = 0; i < self->expression.count; ++i) {
+ for (i = 0; i < self->count; ++i) {
if (!self->ir_values) {
compile_error(ast_ctx(self), "internal error: no array values generated for `%s`", self->name);
return false;
compile_error(ast_ctx(self), "internal error: not all array values have been generated for `%s`", self->name);
return false;
}
- if (self->ir_values[i]->life) {
+ if (!self->ir_values[i]->life.empty()) {
compile_error(ast_ctx(self), "internal error: function containing `%s` already generated", self->name);
return false;
}
return false;
}
}
- for (i = 0; i < self->expression.count; ++i) {
- vec_free(self->ir_values[i]->life);
- }
+ for (i = 0; i < self->count; ++i)
+ self->ir_values[i]->life.clear();
opts_set(opts.warn, WARN_USED_UNINITIALIZED, warn);
return true;
}
ast_expression *ec;
ast_expression_codegen *cgen;
- size_t i;
-
(void)ir;
irf = self->ir_func;
}
/* fill the parameter list */
- ec = &self->vtype->expression;
- for (auto &it : ec->params) {
- if (it->expression.vtype == TYPE_FIELD)
- vec_push(irf->params, it->expression.next->vtype);
+ ec = self->function_type;
+ for (auto &it : ec->type_params) {
+ if (it->vtype == TYPE_FIELD)
+ vec_push(irf->params, it->next->vtype);
else
- vec_push(irf->params, it->expression.vtype);
+ vec_push(irf->params, it->vtype);
if (!self->builtin) {
if (!ast_local_codegen(it, self->ir_func, true))
return false;
if (self->varargs) {
if (!ast_local_codegen(self->varargs, self->ir_func, true))
return false;
- irf->max_varargs = self->varargs->expression.count;
+ irf->max_varargs = self->varargs->count;
}
if (self->builtin) {
return false;
}
- if (!vec_size(self->blocks)) {
+ if (self->blocks.empty()) {
compile_error(ast_ctx(self), "function `%s` has no body", self->name);
return false;
}
ir_value *sub;
if (!ast_local_codegen(self->argc, self->ir_func, true))
return false;
- cgen = self->argc->expression.codegen;
+ cgen = self->argc->codegen;
if (!(*cgen)((ast_expression*)(self->argc), self, false, &va_count))
return false;
- cgen = self->fixedparams->expression.codegen;
+ cgen = self->fixedparams->codegen;
if (!(*cgen)((ast_expression*)(self->fixedparams), self, false, &fixed))
return false;
sub = ir_block_create_binop(self->curblock, ast_ctx(self),
}
}
- for (i = 0; i < vec_size(self->blocks); ++i) {
- cgen = self->blocks[i]->expression.codegen;
- if (!(*cgen)((ast_expression*)self->blocks[i], self, false, &dummy))
+ for (auto &it : self->blocks) {
+ cgen = it->codegen;
+ if (!(*cgen)(it.get(), self, false, &dummy))
return false;
}
/* TODO: check return types */
if (!self->curblock->final)
{
- if (!self->vtype->expression.next ||
- self->vtype->expression.next->vtype == TYPE_VOID)
+ if (!self->function_type->next ||
+ self->function_type->next->vtype == TYPE_VOID)
{
- return ir_block_create_return(self->curblock, ast_ctx(self), NULL);
+ return ir_block_create_return(self->curblock, ast_ctx(self), nullptr);
}
else if (vec_size(self->curblock->entries) || self->curblock == irf->first)
{
if (self->return_value) {
- cgen = self->return_value->expression.codegen;
+ cgen = self->return_value->codegen;
if (!(*cgen)((ast_expression*)(self->return_value), self, false, &dummy))
return false;
return ir_block_create_return(self->curblock, ast_ctx(self), dummy);
}
else 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))
+ self->name, self->curblock->label.c_str()))
{
return false;
}
- return ir_block_create_return(self->curblock, ast_ctx(self), NULL);
+ return ir_block_create_return(self->curblock, ast_ctx(self), nullptr);
}
}
return true;
return false;
}
- if (self->expression.outr) {
- *out = self->expression.outr;
+ if (self->outr) {
+ *out = self->outr;
return true;
}
- /* output is NULL at first, we'll have each expression
+ /* output is nullptr at first, we'll have each expression
* assign to out output, thus, a comma-operator represention
* using an ast_block will return the last generated value,
* so: (b, c) + a executed both b and c, and returns c,
* which is then added to a.
*/
- *out = NULL;
+ *out = nullptr;
/* generate locals */
for (auto &it : self->locals) {
return false;
}
- self->expression.outr = *out;
+ self->outr = *out;
return true;
}
bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_value **out)
{
ast_expression_codegen *cgen;
- ir_value *left = NULL;
- ir_value *right = NULL;
+ ir_value *left = nullptr;
+ ir_value *right = nullptr;
ast_value *arr;
ast_value *idx = 0;
- ast_array_index *ai = NULL;
+ ast_array_index *ai = nullptr;
- if (lvalue && self->expression.outl) {
- *out = self->expression.outl;
+ if (lvalue && self->outl) {
+ *out = self->outl;
return true;
}
- if (!lvalue && self->expression.outr) {
- *out = self->expression.outr;
+ if (!lvalue && self->outr) {
+ *out = self->outr;
return true;
}
idx = (ast_value*)ai->index;
if (ast_istype(ai->index, ast_value) && idx->hasvalue && idx->cvq == CV_CONST)
- ai = NULL;
+ ai = nullptr;
}
if (ai) {
return false;
}
- cgen = idx->expression.codegen;
+ cgen = idx->codegen;
if (!(*cgen)((ast_expression*)(idx), func, false, &iridx))
return false;
- cgen = arr->setter->expression.codegen;
+ cgen = arr->setter->codegen;
if (!(*cgen)((ast_expression*)(arr->setter), func, true, &funval))
return false;
return false;
ir_call_param(call, iridx);
ir_call_param(call, right);
- self->expression.outr = right;
+ self->outr = right;
}
else
{
/* lvalue! */
if (!(*cgen)((ast_expression*)(self->dest), func, true, &left))
return false;
- self->expression.outl = left;
+ self->outl = left;
cgen = self->source->codegen;
/* rvalue! */
if (!ir_block_create_store_op(func->curblock, ast_ctx(self), self->op, left, right))
return false;
- self->expression.outr = right;
+ self->outr = right;
}
/* Theoretically, an assinment returns its left side as an
return false;
}
- if (self->expression.outr) {
- *out = self->expression.outr;
+ if (self->outr) {
+ *out = self->outr;
return true;
}
size_t merge_id;
/* prepare end-block */
- merge_id = vec_size(func->ir_func->blocks);
+ merge_id = func->ir_func->blocks.size();
merge = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "sce_merge"));
/* generate the left expression */
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);
+ algo::shiftback(func->ir_func->blocks.begin() + merge_id,
+ func->ir_func->blocks.end());
+ // FIXME::DELME::
+ //func->ir_func->blocks[merge_id].release();
+ //func->ir_func->blocks.erase(func->ir_func->blocks.begin() + merge_id);
+ //func->ir_func->blocks.emplace_back(merge);
func->curblock = merge;
phi = ir_block_create_phi(func->curblock, ast_ctx(self),
ast_function_label(func, "sce_value"),
- self->expression.vtype);
+ self->vtype);
ir_phi_add(phi, from_left, left);
ir_phi_add(phi, from_right, right);
*out = ir_phi_value(phi);
}
}
- self->expression.outr = *out;
+ self->outr = *out;
codegen_output_type(self, *out);
return true;
}
self->op, left, right);
if (!*out)
return false;
- self->expression.outr = *out;
+ self->outr = *out;
codegen_output_type(self, *out);
return true;
bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, ir_value **out)
{
ast_expression_codegen *cgen;
- ir_value *leftl = NULL, *leftr, *right, *bin;
+ ir_value *leftl = nullptr, *leftr, *right, *bin;
ast_value *arr;
ast_value *idx = 0;
- ast_array_index *ai = NULL;
- ir_value *iridx = NULL;
+ ast_array_index *ai = nullptr;
+ ir_value *iridx = nullptr;
- if (lvalue && self->expression.outl) {
- *out = self->expression.outl;
+ if (lvalue && self->outl) {
+ *out = self->outl;
return true;
}
- if (!lvalue && self->expression.outr) {
- *out = self->expression.outr;
+ if (!lvalue && self->outr) {
+ *out = self->outr;
return true;
}
idx = (ast_value*)ai->index;
if (ast_istype(ai->index, ast_value) && idx->hasvalue && idx->cvq == CV_CONST)
- ai = NULL;
+ ai = nullptr;
}
/* for a binstore we need both an lvalue and an rvalue for the left side */
/* rvalue of destination! */
if (ai) {
- cgen = idx->expression.codegen;
+ cgen = idx->codegen;
if (!(*cgen)((ast_expression*)(idx), func, false, &iridx))
return false;
}
/* now the binary */
bin = ir_block_create_binop(func->curblock, ast_ctx(self), ast_function_label(func, "binst"),
self->opbin, leftr, right);
- self->expression.outr = bin;
-
+ self->outr = bin;
if (ai) {
/* we need to call the setter */
return false;
}
- cgen = arr->setter->expression.codegen;
+ cgen = arr->setter->codegen;
if (!(*cgen)((ast_expression*)(arr->setter), func, true, &funval))
return false;
return false;
ir_call_param(call, iridx);
ir_call_param(call, bin);
- self->expression.outr = bin;
+ self->outr = bin;
} else {
/* now store them */
cgen = self->dest->codegen;
/* lvalue of destination */
if (!(*cgen)((ast_expression*)(self->dest), func, true, &leftl))
return false;
- self->expression.outl = leftl;
+ self->outl = leftl;
if (!ir_block_create_store_op(func->curblock, ast_ctx(self), self->opstore, leftl, bin))
return false;
- self->expression.outr = bin;
+ self->outr = bin;
}
/* Theoretically, an assinment returns its left side as an
return false;
}
- if (self->expression.outr) {
- *out = self->expression.outr;
+ if (self->outr) {
+ *out = self->outr;
return true;
}
self->op, operand);
if (!*out)
return false;
- self->expression.outr = *out;
+ self->outr = *out;
return true;
}
ast_expression_codegen *cgen;
ir_value *operand;
- *out = NULL;
+ *out = nullptr;
/* In the context of a return operation, we don't actually return
* anything...
return false;
}
- if (self->expression.outr) {
+ if (self->outr) {
compile_error(ast_ctx(self), "internal error: ast_return cannot be reused, it bears no result!");
return false;
}
- self->expression.outr = (ir_value*)1;
+ self->outr = (ir_value*)1;
if (self->operand) {
cgen = self->operand->codegen;
if (!ir_block_create_return(func->curblock, ast_ctx(self), operand))
return false;
} else {
- if (!ir_block_create_return(func->curblock, ast_ctx(self), NULL))
+ if (!ir_block_create_return(func->curblock, ast_ctx(self), nullptr))
return false;
}
* value in a temp.
*/
- if (lvalue && self->expression.outl) {
- *out = self->expression.outl;
+ if (lvalue && self->outl) {
+ *out = self->outl;
return true;
}
- if (!lvalue && self->expression.outr) {
- *out = self->expression.outr;
+ if (!lvalue && self->outr) {
+ *out = self->outr;
return true;
}
ent, field);
} else {
*out = ir_block_create_load_from_ent(func->curblock, ast_ctx(self), ast_function_label(func, "efv"),
- ent, field, self->expression.vtype);
+ ent, field, self->vtype);
/* Done AFTER error checking:
codegen_output_type(self, *out);
*/
if (!*out) {
compile_error(ast_ctx(self), "failed to create %s instruction (output type %s)",
(lvalue ? "ADDRESS" : "FIELD"),
- type_name[self->expression.vtype]);
+ type_name[self->vtype]);
return false;
}
if (!lvalue)
codegen_output_type(self, *out);
if (lvalue)
- self->expression.outl = *out;
+ self->outl = *out;
else
- self->expression.outr = *out;
+ self->outr = *out;
/* Hm that should be it... */
return true;
compile_error(ast_ctx(self), "not an l-value (member access)");
return false;
}
- if (self->expression.outl) {
- *out = self->expression.outl;
+ if (self->outl) {
+ *out = self->outl;
return true;
}
}
*out = ir_value_vector_member(vec, self->field);
- self->expression.outl = *out;
+ self->outl = *out;
- return (*out != NULL);
+ return (*out != nullptr);
}
bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lvalue, ir_value **out)
ast_value *arr;
ast_value *idx;
- if (!lvalue && self->expression.outr) {
- *out = self->expression.outr;
+ if (!lvalue && self->outr) {
+ *out = self->outr;
return true;
}
- if (lvalue && self->expression.outl) {
- *out = self->expression.outl;
+ if (lvalue && self->outl) {
+ *out = self->outl;
return true;
}
if (!(*cgen)((ast_expression*)(self->index), func, false, &iridx))
return false;
- cgen = arr->getter->expression.codegen;
+ cgen = arr->getter->codegen;
if (!(*cgen)((ast_expression*)(arr->getter), func, true, &funval))
return false;
ir_call_param(call, iridx);
*out = ir_call_value(call);
- self->expression.outr = *out;
- (*out)->vtype = self->expression.vtype;
+ self->outr = *out;
+ (*out)->vtype = self->vtype;
codegen_output_type(self, *out);
return true;
}
- if (idx->expression.vtype == TYPE_FLOAT) {
+ if (idx->vtype == TYPE_FLOAT) {
unsigned int arridx = idx->constval.vfloat;
if (arridx >= self->array->count)
{
}
*out = arr->ir_values[arridx];
}
- else if (idx->expression.vtype == TYPE_INTEGER) {
+ else if (idx->vtype == TYPE_INTEGER) {
unsigned int arridx = idx->constval.vint;
if (arridx >= self->array->count)
{
compile_error(ast_ctx(self), "array indexing here needs an integer constant");
return false;
}
- (*out)->vtype = self->expression.vtype;
+ (*out)->vtype = self->vtype;
codegen_output_type(self, *out);
return true;
}
bool ast_argpipe_codegen(ast_argpipe *self, ast_function *func, bool lvalue, ir_value **out)
{
- *out = NULL;
+ *out = nullptr;
if (lvalue) {
compile_error(ast_ctx(self), "argpipe node: not an lvalue");
return false;
ir_block *cond;
ir_block *ontrue;
ir_block *onfalse;
- ir_block *ontrue_endblock = NULL;
- ir_block *onfalse_endblock = NULL;
- ir_block *merge = NULL;
- int fold = 0;
+ ir_block *ontrue_endblock = nullptr;
+ ir_block *onfalse_endblock = nullptr;
+ ir_block *merge = nullptr;
+ int folded = 0;
/* We don't output any value, thus also don't care about r/lvalue */
(void)out;
(void)lvalue;
- if (self->expression.outr) {
+ if (self->outr) {
compile_error(ast_ctx(self), "internal error: ast_ifthen cannot be reused, it bears no result!");
return false;
}
- self->expression.outr = (ir_value*)1;
+ self->outr = (ir_value*)1;
/* generate the condition */
cgen = self->cond->codegen;
cond = func->curblock;
/* try constant folding away the condition */
- if ((fold = fold_cond_ifthen(condval, func, self)) != -1)
- return fold;
+ if ((folded = fold::cond_ifthen(condval, func, self)) != -1)
+ return folded;
if (self->on_true) {
/* create on-true block */
/* we now need to work from the current endpoint */
ontrue_endblock = func->curblock;
} else
- ontrue = NULL;
+ ontrue = nullptr;
/* on-false path */
if (self->on_false) {
/* we now need to work from the current endpoint */
onfalse_endblock = func->curblock;
} else
- onfalse = NULL;
+ onfalse = nullptr;
/* Merge block were they all merge in to */
if (!ontrue || !onfalse || !ontrue_endblock->final || !onfalse_endblock->final)
ir_instr *phi;
ir_block *cond = func->curblock;
- ir_block *cond_out = NULL;
- ir_block *ontrue, *ontrue_out = NULL;
- ir_block *onfalse, *onfalse_out = NULL;
+ ir_block *cond_out = nullptr;
+ ir_block *ontrue, *ontrue_out = nullptr;
+ ir_block *onfalse, *onfalse_out = nullptr;
ir_block *merge;
- int fold = 0;
+ int folded = 0;
/* Ternary can never create an lvalue... */
if (lvalue)
* may still happen, thus we remember a created ir_value and simply return one
* if it already exists.
*/
- if (self->expression.outr) {
- *out = self->expression.outr;
+ if (self->outr) {
+ *out = self->outr;
return true;
}
cond_out = func->curblock;
/* try constant folding away the condition */
- if ((fold = fold_cond_ternary(condval, func, self)) != -1)
- return fold;
+ if ((folded = fold::cond_ternary(condval, func, self)) != -1)
+ return folded;
/* create on-true block */
ontrue = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "tern_T"));
}
/* create PHI */
- phi = ir_block_create_phi(merge, ast_ctx(self), ast_function_label(func, "phi"), self->expression.vtype);
+ phi = ir_block_create_phi(merge, ast_ctx(self), ast_function_label(func, "phi"), self->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);
- self->expression.outr = ir_phi_value(phi);
- *out = self->expression.outr;
+ self->outr = ir_phi_value(phi);
+ *out = self->outr;
codegen_output_type(self, *out);
{
ast_expression_codegen *cgen;
- ir_value *dummy = NULL;
- ir_value *precond = NULL;
- ir_value *postcond = NULL;
+ ir_value *dummy = nullptr;
+ ir_value *precond = nullptr;
+ ir_value *postcond = nullptr;
/* Since we insert some jumps "late" so we have blocks
* ordered "nicely", we need to keep track of the actual end-blocks
* of expressions to add the jumps to.
*/
- ir_block *bbody = NULL, *end_bbody = NULL;
- ir_block *bprecond = NULL, *end_bprecond = NULL;
- ir_block *bpostcond = NULL, *end_bpostcond = NULL;
- ir_block *bincrement = NULL, *end_bincrement = NULL;
- ir_block *bout = NULL, *bin = NULL;
+ ir_block *bbody = nullptr, *end_bbody = nullptr;
+ ir_block *bprecond = nullptr, *end_bprecond = nullptr;
+ ir_block *bpostcond = nullptr, *end_bpostcond = nullptr;
+ ir_block *bincrement = nullptr, *end_bincrement = nullptr;
+ ir_block *bout = nullptr, *bin = nullptr;
/* let's at least move the outgoing block to the end */
size_t bout_id;
/* 'break' and 'continue' need to be able to find the right blocks */
- ir_block *bcontinue = NULL;
- ir_block *bbreak = NULL;
+ ir_block *bcontinue = nullptr;
+ ir_block *bbreak = nullptr;
- ir_block *tmpblock = NULL;
+ ir_block *tmpblock = nullptr;
(void)lvalue;
(void)out;
- if (self->expression.outr) {
+ if (self->outr) {
compile_error(ast_ctx(self), "internal error: ast_loop cannot be reused, it bears no result!");
return false;
}
- self->expression.outr = (ir_value*)1;
+ self->outr = (ir_value*)1;
/* NOTE:
* Should we ever need some kind of block ordering, better make this function
end_bprecond = func->curblock;
} else {
- bprecond = end_bprecond = NULL;
+ bprecond = end_bprecond = nullptr;
}
/* Now the next blocks won't be ordered nicely, but we need to
return false;
bcontinue = bincrement; /* increment comes before the pre-loop-condition */
} else {
- bincrement = end_bincrement = NULL;
+ bincrement = end_bincrement = nullptr;
}
if (self->postcond) {
return false;
bcontinue = bpostcond; /* postcond comes before the increment */
} else {
- bpostcond = end_bpostcond = NULL;
+ bpostcond = end_bpostcond = nullptr;
}
- bout_id = vec_size(func->ir_func->blocks);
+ bout_id = func->ir_func->blocks.size();
bout = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "after_loop"));
if (!bout)
return false;
/* enter */
func->curblock = bbody;
- vec_push(func->breakblocks, bbreak);
+ func->breakblocks.push_back(bbreak);
if (bcontinue)
- vec_push(func->continueblocks, bcontinue);
+ func->continueblocks.push_back(bcontinue);
else
- vec_push(func->continueblocks, bbody);
+ func->continueblocks.push_back(bbody);
/* generate */
if (self->body) {
}
end_bbody = func->curblock;
- vec_pop(func->breakblocks);
- vec_pop(func->continueblocks);
+ func->breakblocks.pop_back();
+ func->continueblocks.pop_back();
}
/* post-loop-condition */
}
/* Move 'bout' to the end */
- vec_remove(func->ir_func->blocks, bout_id, 1);
- vec_push(func->ir_func->blocks, bout);
+ algo::shiftback(func->ir_func->blocks.begin() + bout_id,
+ func->ir_func->blocks.end());
+ // FIXME::DELME::
+ //func->ir_func->blocks[bout_id].release(); // it's a vector<unique_ptr<>>
+ //func->ir_func->blocks.erase(func->ir_func->blocks.begin() + bout_id);
+ //func->ir_func->blocks.emplace_back(bout);
return true;
}
{
ir_block *target;
- *out = NULL;
+ *out = nullptr;
if (lvalue) {
compile_error(ast_ctx(self), "break/continue expression is not an l-value");
return false;
}
- if (self->expression.outr) {
+ if (self->outr) {
compile_error(ast_ctx(self), "internal error: ast_breakcont cannot be reused!");
return false;
}
- self->expression.outr = (ir_value*)1;
+ self->outr = (ir_value*)1;
if (self->is_continue)
- target = func->continueblocks[vec_size(func->continueblocks)-1-self->levels];
+ target = func->continueblocks[func->continueblocks.size()-1-self->levels];
else
- target = func->breakblocks[vec_size(func->breakblocks)-1-self->levels];
+ target = func->breakblocks[func->breakblocks.size()-1-self->levels];
if (!target) {
compile_error(ast_ctx(self), "%s is lacking a target block", (self->is_continue ? "continue" : "break"));
{
ast_expression_codegen *cgen;
- ast_switch_case *def_case = NULL;
- ir_block *def_bfall = NULL;
- ir_block *def_bfall_to = NULL;
+ ast_switch_case *def_case = nullptr;
+ ir_block *def_bfall = nullptr;
+ ir_block *def_bfall_to = nullptr;
bool set_def_bfall_to = false;
- ir_value *dummy = NULL;
- ir_value *irop = NULL;
- ir_block *bout = NULL;
- ir_block *bfall = NULL;
+ ir_value *dummy = nullptr;
+ ir_value *irop = nullptr;
+ ir_block *bout = nullptr;
+ ir_block *bfall = nullptr;
size_t bout_id;
- size_t c;
char typestr[1024];
uint16_t cmpinstr;
return false;
}
- if (self->expression.outr) {
+ if (self->outr) {
compile_error(ast_ctx(self), "internal error: ast_switch cannot be reused!");
return false;
}
- self->expression.outr = (ir_value*)1;
+ self->outr = (ir_value*)1;
(void)lvalue;
(void)out;
if (!(*cgen)((ast_expression*)(self->operand), func, false, &irop))
return false;
- if (!vec_size(self->cases))
+ if (self->cases.empty())
return true;
cmpinstr = type_eq_instr[irop->vtype];
return false;
}
- bout_id = vec_size(func->ir_func->blocks);
+ bout_id = func->ir_func->blocks.size();
bout = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "after_switch"));
if (!bout)
return false;
/* setup the break block */
- vec_push(func->breakblocks, bout);
+ func->breakblocks.push_back(bout);
/* Now create all cases */
- for (c = 0; c < vec_size(self->cases); ++c) {
+ for (auto &it : self->cases) {
ir_value *cond, *val;
ir_block *bcase, *bnot;
size_t bnot_id;
- ast_switch_case *swcase = &self->cases[c];
+ ast_switch_case *swcase = ⁢
if (swcase->value) {
/* A regular case */
return false;
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_id = func->ir_func->blocks.size();
bnot = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "not_case"));
if (!bcase || !bnot)
return false;
/* enter the else and move it down */
func->curblock = bnot;
- vec_remove(func->ir_func->blocks, bnot_id, 1);
- vec_push(func->ir_func->blocks, bnot);
+ algo::shiftback(func->ir_func->blocks.begin() + bnot_id,
+ func->ir_func->blocks.end());
+ // FIXME::DELME::
+ //func->ir_func->blocks[bnot_id].release();
+ //func->ir_func->blocks.erase(func->ir_func->blocks.begin() + bnot_id);
+ //func->ir_func->blocks.emplace_back(bnot);
} else {
/* The default case */
/* Remember where to fall through from: */
def_bfall = bfall;
- bfall = NULL;
+ bfall = nullptr;
/* remember which case it was */
def_case = swcase;
/* And the next case will be remembered */
func->curblock = bout;
/* restore the break block */
- vec_pop(func->breakblocks);
+ func->breakblocks.pop_back();
/* Move 'bout' to the end, it's nicer */
- vec_remove(func->ir_func->blocks, bout_id, 1);
- vec_push(func->ir_func->blocks, bout);
+ algo::shiftback(func->ir_func->blocks.begin() + bout_id,
+ func->ir_func->blocks.end());
+ // FIXME::DELME::
+ //func->ir_func->blocks[bout_id].release();
+ //func->ir_func->blocks.erase(func->ir_func->blocks.begin() + bout_id);
+ //func->ir_func->blocks.emplace_back(bout);
return true;
}
return false;
}
- *out = NULL;
+ *out = nullptr;
if (lvalue) {
compile_error(ast_ctx(self), "internal error: ast_label cannot be an lvalue");
return false;
bool ast_goto_codegen(ast_goto *self, ast_function *func, bool lvalue, ir_value **out)
{
- *out = NULL;
+ *out = nullptr;
if (lvalue) {
compile_error(ast_ctx(self), "internal error: ast_goto cannot be an lvalue");
return false;
compile_error(ast_ctx(self), "not an l-value (state operation)");
return false;
}
- if (self->expression.outr) {
+ if (self->outr) {
compile_error(ast_ctx(self), "internal error: ast_state cannot be reused!");
return false;
}
- *out = NULL;
+ *out = nullptr;
cgen = self->framenum->codegen;
if (!(*cgen)((ast_expression*)(self->framenum), func, false, &frameval))
return false;
}
- self->expression.outr = (ir_value*)1;
+ self->outr = (ir_value*)1;
return true;
}
bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value **out)
{
ast_expression_codegen *cgen;
- ir_value **params;
- ir_instr *callinstr;
- size_t i;
+ std::vector<ir_value*> params;
+ ir_instr *callinstr;
- ir_value *funval = NULL;
+ ir_value *funval = nullptr;
/* return values are never lvalues */
if (lvalue) {
return false;
}
- if (self->expression.outr) {
- *out = self->expression.outr;
+ if (self->outr) {
+ *out = self->outr;
return true;
}
if (!funval)
return false;
- params = NULL;
-
/* parameters */
for (auto &it : self->params) {
ir_value *param;
cgen = it->codegen;
if (!(*cgen)(it, func, false, ¶m))
- goto error;
+ return false;
if (!param)
- goto error;
- vec_push(params, param);
+ return false;
+ params.push_back(param);
}
/* varargs counter */
ast_function_label(func, "call"),
funval, !!(self->func->flags & AST_FLAG_NORETURN));
if (!callinstr)
- goto error;
+ return false;
- for (i = 0; i < vec_size(params); ++i) {
- ir_call_param(callinstr, params[i]);
- }
+ for (auto &it : params)
+ ir_call_param(callinstr, it);
*out = ir_call_value(callinstr);
- self->expression.outr = *out;
+ self->outr = *out;
codegen_output_type(self, *out);
- vec_free(params);
return true;
-error:
- vec_free(params);
- return false;
}