mem_d(self);
}
+bool ast_member_set_name(ast_member *self, const char *name)
+{
+ if (self->name)
+ mem_d((void*)self->name);
+ self->name = util_strdup(name);
+ return !!self->name;
+}
+
ast_array_index* ast_array_index_new(lex_ctx ctx, ast_expression *array, ast_expression *index)
{
ast_expression *outtype;
ast_loop* ast_loop_new(lex_ctx ctx,
ast_expression *initexpr,
- ast_expression *precond,
- ast_expression *postcond,
+ ast_expression *precond, bool pre_not,
+ ast_expression *postcond, bool post_not,
ast_expression *increment,
ast_expression *body)
{
self->increment = increment;
self->body = body;
+ self->pre_not = pre_not;
+ self->post_not = post_not;
+
if (initexpr)
ast_propagate_effects(self, initexpr);
if (precond)
from = self->labelbuf + sizeof(self->labelbuf)-1;
*from-- = 0;
do {
- unsigned int digit = id % 10;
- *from = digit + '0';
+ *from-- = (id%10) + '0';
id /= 10;
} while (id);
+ ++from;
memcpy(from - len, prefix, len);
return from - len;
}
}
#define codegen_output_type(a,o) (_ast_codegen_output_type(&((a)->expression),(o)))
-#define codegen_output_type_expr(a,o) (_ast_codegen_output_type(a,(o)))
bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_value **out)
{
* on all the globals.
*/
if (!self->ir_v) {
- char typename[1024];
- ast_type_to_string((ast_expression*)self, typename, sizeof(typename));
- compile_error(ast_ctx(self), "ast_value used before generated %s %s", typename, self->name);
+ char tname[1024]; /* typename is reserved in C++ */
+ ast_type_to_string((ast_expression*)self, tname, sizeof(tname));
+ compile_error(ast_ctx(self), "ast_value used before generated %s %s", tname, self->name);
return false;
}
*out = self->ir_v;
}
v->context = ast_ctx(self);
v->unique_life = true;
+ v->locked = true;
array->ir_v = self->ir_v = v;
namelen = strlen(self->name);
}
array->ir_values[ai]->context = ast_ctx(self);
array->ir_values[ai]->unique_life = true;
+ array->ir_values[ai]->locked = true;
}
mem_d(name);
}
}
v->context = ast_ctx(self);
v->unique_life = true;
+ v->locked = true;
namelen = strlen(self->name);
name = (char*)mem_a(namelen + 16);
}
self->ir_values[ai]->context = ast_ctx(self);
self->ir_values[ai]->unique_life = true;
+ self->ir_values[ai]->locked = true;
}
mem_d(name);
}
ast_expression_common *elemtype = &self->expression.next->expression;
int vtype = elemtype->vtype;
+ func->flags |= IR_FLAG_HAS_ARRAYS;
+
if (param) {
compile_error(ast_ctx(self), "array-parameters are not supported");
return false;
}
v->context = ast_ctx(self);
v->unique_life = true;
+ v->locked = true;
namelen = strlen(self->name);
name = (char*)mem_a(namelen + 16);
}
self->ir_values[ai]->context = ast_ctx(self);
self->ir_values[ai]->unique_life = true;
+ self->ir_values[ai]->locked = true;
}
}
else
}
/* TODO: check return types */
- if (!self->curblock->is_return)
+ if (!self->curblock->final)
{
if (!self->vtype->expression.next ||
self->vtype->expression.next->expression.vtype == TYPE_VOID)
return true;
}
- if (OPTS_FLAG(SHORT_LOGIC) &&
+ if ((OPTS_FLAG(SHORT_LOGIC) || OPTS_FLAG(PERL_LOGIC)) &&
(self->op == INSTR_AND || self->op == INSTR_OR))
{
/* short circuit evaluation */
ir_block *from_left, *from_right;
ir_instr *phi;
size_t merge_id;
- uint16_t notop;
-
- /* Note about casting to true boolean values:
- * We use a single NOT for sub expressions, and an
- * overall NOT at the end, and for that purpose swap
- * all the jump conditions in order for the NOT to get
- * doubled.
- * ie: (a && b) usually becomes (!!a ? !!b : !!a)
- * but we translate this to (!(!a ? !a : !b))
- */
+ /* prepare end-block */
merge_id = vec_size(func->ir_func->blocks);
- merge = ir_function_create_block(ast_ctx(self), 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"));
+ /* generate the left expression */
cgen = self->left->expression.codegen;
if (!(*cgen)((ast_expression*)(self->left), func, false, &left))
return false;
- if (!OPTS_FLAG(PERL_LOGIC)) {
- notop = type_not_instr[left->vtype];
- if (notop == AINSTR_END) {
- compile_error(ast_ctx(self), "don't know how to cast to bool...");
- return false;
- }
- left = ir_block_create_unary(func->curblock, ast_ctx(self),
- ast_function_label(func, "sce_not"),
- notop,
- left);
- }
+ /* remember the block */
from_left = func->curblock;
+ /* create a new block for the right expression */
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 (self->op == INSTR_AND) {
+ /* on AND: left==true -> other */
if (!ir_block_create_if(func->curblock, ast_ctx(self), left, other, merge))
return false;
} else {
+ /* on OR: left==false -> other */
if (!ir_block_create_if(func->curblock, ast_ctx(self), left, merge, other))
return false;
}
/* use the likely flag */
vec_last(func->curblock->instr)->likely = true;
+ /* enter the right-expression's block */
func->curblock = other;
+ /* generate */
cgen = self->right->expression.codegen;
if (!(*cgen)((ast_expression*)(self->right), func, false, &right))
return false;
- if (!OPTS_FLAG(PERL_LOGIC)) {
- notop = type_not_instr[right->vtype];
- if (notop == AINSTR_END) {
- compile_error(ast_ctx(self), "don't know how to cast to bool...");
- return false;
- }
- right = ir_block_create_unary(func->curblock, ast_ctx(self),
- ast_function_label(func, "sce_not"),
- notop,
- right);
- }
+ /* remember block */
from_right = func->curblock;
+ /* jump to the merge block */
if (!ir_block_create_jump(func->curblock, ast_ctx(self), merge))
return false;
vec_push(func->ir_func->blocks, merge);
func->curblock = merge;
- phi = ir_block_create_phi(func->curblock, ast_ctx(self), ast_function_label(func, "sce_value"), TYPE_FLOAT);
+ phi = ir_block_create_phi(func->curblock, ast_ctx(self),
+ ast_function_label(func, "sce_value"),
+ self->expression.vtype);
ir_phi_add(phi, from_left, left);
ir_phi_add(phi, from_right, right);
*out = ir_phi_value(phi);
+ if (!*out)
+ return false;
+
if (!OPTS_FLAG(PERL_LOGIC)) {
- notop = type_not_instr[(*out)->vtype];
- if (notop == AINSTR_END) {
- compile_error(ast_ctx(self), "don't know how to cast to bool...");
- return false;
+ /* cast-to-bool */
+ if (OPTS_FLAG(CORRECT_LOGIC) && (*out)->vtype == TYPE_VECTOR) {
+ *out = ir_block_create_unary(func->curblock, ast_ctx(self),
+ ast_function_label(func, "sce_bool_v"),
+ INSTR_NOT_V, *out);
+ if (!*out)
+ return false;
+ *out = ir_block_create_unary(func->curblock, ast_ctx(self),
+ ast_function_label(func, "sce_bool"),
+ INSTR_NOT_F, *out);
+ if (!*out)
+ return false;
+ }
+ else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && (*out)->vtype == TYPE_STRING) {
+ *out = ir_block_create_unary(func->curblock, ast_ctx(self),
+ ast_function_label(func, "sce_bool_s"),
+ INSTR_NOT_S, *out);
+ if (!*out)
+ return false;
+ *out = ir_block_create_unary(func->curblock, ast_ctx(self),
+ ast_function_label(func, "sce_bool"),
+ INSTR_NOT_F, *out);
+ if (!*out)
+ return false;
+ }
+ else {
+ *out = ir_block_create_binop(func->curblock, ast_ctx(self),
+ ast_function_label(func, "sce_bool"),
+ INSTR_AND, *out, *out);
+ if (!*out)
+ return false;
}
- *out = ir_block_create_unary(func->curblock, ast_ctx(self),
- ast_function_label(func, "sce_final_not"),
- notop,
- *out);
}
- if (!*out)
- return false;
+
self->expression.outr = *out;
return true;
}
else if (bpostcond) ontrue = bpostcond;
else ontrue = bprecond;
onfalse = bout;
+ if (self->pre_not) {
+ tmpblock = ontrue;
+ ontrue = onfalse;
+ onfalse = tmpblock;
+ }
if (!ir_block_create_if(end_bprecond, ast_ctx(self), precond, ontrue, onfalse))
return false;
}
else if (bincrement) ontrue = bincrement;
else ontrue = bpostcond;
onfalse = bout;
+ if (self->post_not) {
+ tmpblock = ontrue;
+ ontrue = onfalse;
+ onfalse = tmpblock;
+ }
if (!ir_block_create_if(end_bpostcond, ast_ctx(self), postcond, ontrue, onfalse))
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, ast_ctx(self), self->target->irblock)) {
+ if (!ir_block_create_goto(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, ast_ctx(self), self->target->irblock)) {
+ if (!ir_block_create_goto(func->curblock, ast_ctx(self), self->target->irblock)) {
compile_error(ast_ctx(self), "failed to generate goto to `%s`", self->name);
return false;
}