mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-03-12 22:02:03 +00:00
BROKEN: in the middle of converting ast nodes to c++ with constructors and methods
This commit is contained in:
parent
9d98805dfb
commit
6149f6a1d0
3 changed files with 294 additions and 416 deletions
561
ast.cpp
561
ast.cpp
|
@ -57,174 +57,162 @@ static void ast_binary_delete(ast_binary*);
|
|||
static bool ast_binary_codegen(ast_binary*, ast_function*, bool lvalue, ir_value**);
|
||||
static bool ast_state_codegen(ast_state*, ast_function*, bool lvalue, ir_value**);
|
||||
|
||||
/* It must not be possible to get here. */
|
||||
static GMQCC_NORETURN void _ast_node_destroy(ast_node *self)
|
||||
/* Initialize main ast node aprts */
|
||||
ast_node::ast_node(lex_ctx_t ctx, int node_type)
|
||||
: m_context(ctx),
|
||||
m_node_type(node_type),
|
||||
m_keep_node(false),
|
||||
m_side_effects(false)
|
||||
{
|
||||
(void)self;
|
||||
con_err("ast node missing destroy()\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Initialize main ast node aprts */
|
||||
static void ast_node_init(ast_node *self, lex_ctx_t ctx, int node_type)
|
||||
ast_node::~ast_node()
|
||||
{
|
||||
self->m_context = ctx;
|
||||
self->m_destroy = &_ast_node_destroy;
|
||||
self->m_keep_node = false;
|
||||
self->m_node_type = node_type;
|
||||
self->m_side_effects = false;
|
||||
}
|
||||
|
||||
/* weight and side effects */
|
||||
static void _ast_propagate_effects(ast_node *self, ast_node *other)
|
||||
void ast_node::propagate_side_effects(ast_node *other) const
|
||||
{
|
||||
if (other->m_side_effects)
|
||||
self->m_side_effects = true;
|
||||
other->m_side_effects = m_side_effects;
|
||||
}
|
||||
#define ast_propagate_effects(s,o) _ast_propagate_effects(((ast_node*)(s)), ((ast_node*)(o)))
|
||||
|
||||
/* General expression initialization */
|
||||
static void ast_expression_init(ast_expression *self,
|
||||
ast_expression_codegen *codegen)
|
||||
ast_expression::ast_expression(lex_ctx_t ctx, int nodetype, qc_type type)
|
||||
: ast_node(ctx, nodetype),
|
||||
m_vtype(type)
|
||||
{
|
||||
self->m_codegen = codegen;
|
||||
self->m_vtype = TYPE_VOID;
|
||||
self->m_next = nullptr;
|
||||
self->m_outl = nullptr;
|
||||
self->m_outr = nullptr;
|
||||
self->m_count = 0;
|
||||
self->m_varparam = nullptr;
|
||||
self->m_flags = 0;
|
||||
if (OPTS_OPTION_BOOL(OPTION_COVERAGE))
|
||||
self->m_flags |= AST_FLAG_BLOCK_COVERAGE;
|
||||
m_flags |= AST_FLAG_BLOCK_COVERAGE;
|
||||
}
|
||||
ast_expression::ast_expression(lex_ctx_t ctx, int nodetype)
|
||||
: ast_expression(ctx, nodetype, TYPE_VOID)
|
||||
{}
|
||||
|
||||
ast_expression::~ast_expression()
|
||||
{
|
||||
if (m_next)
|
||||
delete m_next;
|
||||
if (m_varparam)
|
||||
delete m_varparam;
|
||||
}
|
||||
|
||||
static void ast_expression_delete(ast_expression *self)
|
||||
ast_expression::ast_expression(ast_copy_type_t, int nodetype, const ast_expression &other)
|
||||
: ast_expression(other.m_context, nodetype)
|
||||
{
|
||||
if (self->m_next)
|
||||
ast_delete(self->m_next);
|
||||
for (auto &it : self->m_type_params)
|
||||
ast_delete(it);
|
||||
if (self->m_varparam)
|
||||
ast_delete(self->m_varparam);
|
||||
m_vtype = other.m_vtype;
|
||||
m_count = other.m_count;
|
||||
m_flags = other.m_flags;
|
||||
if (other.m_next)
|
||||
m_next = new ast_expression(ast_copy_type, TYPE_ast_expression, *other.m_next);
|
||||
m_type_params.reserve(other.m_type_params.size());
|
||||
for (auto &it : other.m_type_params)
|
||||
m_type_params.emplace_back(new ast_value(ast_copy_type, *it));
|
||||
}
|
||||
|
||||
static void ast_expression_delete_full(ast_expression *self)
|
||||
{
|
||||
ast_expression_delete(self);
|
||||
mem_d(self);
|
||||
ast_expression::ast_expression(ast_copy_type_t, const ast_expression &other)
|
||||
: ast_expression(other.m_context, TYPE_ast_expression)
|
||||
{}
|
||||
|
||||
ast_expression *ast_expression::shallow_type(lex_ctx_t ctx, qc_type vtype) {
|
||||
auto expr = new ast_expression(ctx, TYPE_ast_expression);
|
||||
expr->m_vtype = vtype;
|
||||
return expr;
|
||||
}
|
||||
|
||||
ast_value* ast_value_copy(const ast_value *self)
|
||||
void ast_expression::adopt_type(const ast_expression &other)
|
||||
{
|
||||
ast_value *cp = ast_value_new(self->m_context, self->m_name, self->m_vtype);
|
||||
if (self->m_next) {
|
||||
cp->m_next = ast_type_copy(self->m_context, self->m_next);
|
||||
}
|
||||
const ast_expression *fromex = self;
|
||||
ast_expression *selfex = cp;
|
||||
selfex->m_count = fromex->m_count;
|
||||
selfex->m_flags = fromex->m_flags;
|
||||
for (auto &it : fromex->m_type_params) {
|
||||
ast_value *v = ast_value_copy(it);
|
||||
selfex->m_type_params.push_back(v);
|
||||
}
|
||||
return cp;
|
||||
m_vtype = other.m_vtype;
|
||||
if (other.m_next)
|
||||
m_next = new ast_expression(ast_copy_type, TYPE_ast_expression, *other.m_next);
|
||||
m_count = other.m_count;
|
||||
m_flags = other.m_flags;
|
||||
m_type_params.clear();
|
||||
m_type_params.reserve(other.m_type_params.size());
|
||||
for (auto &it : other.m_type_params)
|
||||
m_type_params.emplace_back(new ast_value(ast_copy_type, *it));
|
||||
}
|
||||
|
||||
void ast_type_adopt_impl(ast_expression *self, const ast_expression *other)
|
||||
bool ast_expression::compare_type(const ast_expression &other) const
|
||||
{
|
||||
const ast_expression *fromex;
|
||||
ast_expression *selfex;
|
||||
self->m_vtype = other->m_vtype;
|
||||
if (other->m_next) {
|
||||
self->m_next = (ast_expression*)ast_type_copy(self->m_context, other->m_next);
|
||||
}
|
||||
fromex = other;
|
||||
selfex = self;
|
||||
selfex->m_count = fromex->m_count;
|
||||
selfex->m_flags = fromex->m_flags;
|
||||
for (auto &it : fromex->m_type_params) {
|
||||
ast_value *v = ast_value_copy(it);
|
||||
selfex->m_type_params.push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
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, nullptr);
|
||||
self->m_codegen = nullptr;
|
||||
self->m_next = nullptr;
|
||||
self->m_vtype = vtype;
|
||||
return self;
|
||||
}
|
||||
|
||||
ast_expression* ast_type_copy(lex_ctx_t ctx, const ast_expression *ex)
|
||||
{
|
||||
const ast_expression *fromex;
|
||||
ast_expression *selfex;
|
||||
|
||||
if (!ex)
|
||||
return nullptr;
|
||||
else
|
||||
{
|
||||
ast_instantiate(ast_expression, ctx, ast_expression_delete_full);
|
||||
ast_expression_init(self, nullptr);
|
||||
|
||||
fromex = ex;
|
||||
selfex = self;
|
||||
|
||||
/* This may never be codegen()d */
|
||||
selfex->m_codegen = nullptr;
|
||||
|
||||
selfex->m_vtype = fromex->m_vtype;
|
||||
if (fromex->m_next)
|
||||
selfex->m_next = ast_type_copy(ctx, fromex->m_next);
|
||||
else
|
||||
selfex->m_next = nullptr;
|
||||
|
||||
selfex->m_count = fromex->m_count;
|
||||
selfex->m_flags = fromex->m_flags;
|
||||
for (auto &it : fromex->m_type_params) {
|
||||
ast_value *v = ast_value_copy(it);
|
||||
selfex->m_type_params.push_back(v);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
bool ast_compare_type(ast_expression *a, ast_expression *b)
|
||||
{
|
||||
if (a->m_vtype == TYPE_NIL ||
|
||||
b->m_vtype == TYPE_NIL)
|
||||
if (m_vtype == TYPE_NIL ||
|
||||
other.m_vtype == TYPE_NIL)
|
||||
return true;
|
||||
if (a->m_vtype != b->m_vtype)
|
||||
if (m_vtype != other.m_vtype)
|
||||
return false;
|
||||
if (!a->m_next != !b->m_next)
|
||||
if (!m_next != !other.m_next)
|
||||
return false;
|
||||
if (a->m_type_params.size() != b->m_type_params.size())
|
||||
if (m_type_params.size() != other.m_type_params.size())
|
||||
return false;
|
||||
if ((a->m_flags & AST_FLAG_TYPE_MASK) !=
|
||||
(b->m_flags & AST_FLAG_TYPE_MASK) )
|
||||
if ((m_flags & AST_FLAG_TYPE_MASK) !=
|
||||
(other.m_flags & AST_FLAG_TYPE_MASK) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (a->m_type_params.size()) {
|
||||
if (m_type_params.size()) {
|
||||
size_t i;
|
||||
for (i = 0; i < a->m_type_params.size(); ++i) {
|
||||
if (!ast_compare_type((ast_expression*)a->m_type_params[i],
|
||||
(ast_expression*)b->m_type_params[i]))
|
||||
for (i = 0; i < m_type_params.size(); ++i) {
|
||||
if (!m_type_params[i]->compare_type(*other.m_type_params[i]))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (a->m_next)
|
||||
return ast_compare_type(a->m_next, b->m_next);
|
||||
if (m_next)
|
||||
return m_next->compare_type(*other.m_next);
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t ast_type_to_string_impl(ast_expression *e, char *buf, size_t bufsize, size_t pos)
|
||||
ast_value::ast_value(ast_copy_type_t, const ast_value &other, const std::string &name)
|
||||
: ast_value(ast_copy_type, static_cast<const ast_expression&>(other), name)
|
||||
{}
|
||||
|
||||
ast_value::ast_value(ast_copy_type_t, const ast_value &other)
|
||||
: ast_value(ast_copy_type, static_cast<const ast_expression&>(other), other.m_name)
|
||||
{}
|
||||
|
||||
ast_value::ast_value(ast_copy_type_t, const ast_expression &other, const std::string &name)
|
||||
: ast_expression(ast_copy_type, other),
|
||||
m_name(name)
|
||||
{}
|
||||
|
||||
ast_value::ast_value(lex_ctx_t ctx, const std::string &name, qc_type t)
|
||||
: ast_expression(ctx, TYPE_ast_value, t),
|
||||
m_name(name)
|
||||
{
|
||||
m_keep_node = true; // keep values, always
|
||||
memset(&m_constval, 0, sizeof(m_constval));
|
||||
}
|
||||
|
||||
ast_value::~ast_value()
|
||||
{
|
||||
if (m_argcounter)
|
||||
mem_d((void*)m_argcounter);
|
||||
if (m_hasvalue) {
|
||||
switch (m_vtype)
|
||||
{
|
||||
case TYPE_STRING:
|
||||
mem_d((void*)m_constval.vstring);
|
||||
break;
|
||||
case TYPE_FUNCTION:
|
||||
// unlink us from the function node
|
||||
m_constval.vfunc->m_function_type = nullptr;
|
||||
break;
|
||||
// NOTE: delete function? currently collected in
|
||||
// the parser structure
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_ir_values)
|
||||
mem_d(m_ir_values);
|
||||
|
||||
// initlist imples an array which implies .next in the expression exists.
|
||||
if (m_initlist.size() && m_next->m_vtype == TYPE_STRING) {
|
||||
for (auto &it : m_initlist)
|
||||
if (it.vstring)
|
||||
mem_d(it.vstring);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t ast_type_to_string_impl(const ast_expression *e, char *buf, size_t bufsize, size_t pos)
|
||||
{
|
||||
const char *typestr;
|
||||
size_t typelen;
|
||||
|
@ -270,13 +258,13 @@ static size_t ast_type_to_string_impl(ast_expression *e, char *buf, size_t bufsi
|
|||
return pos;
|
||||
}
|
||||
buf[pos++] = '(';
|
||||
pos = ast_type_to_string_impl((ast_expression*)(e->m_type_params[0]), buf, bufsize, pos);
|
||||
pos = ast_type_to_string_impl(e->m_type_params[0].get(), buf, bufsize, pos);
|
||||
for (i = 1; i < e->m_type_params.size(); ++i) {
|
||||
if (pos + 2 >= bufsize)
|
||||
goto full;
|
||||
buf[pos++] = ',';
|
||||
buf[pos++] = ' ';
|
||||
pos = ast_type_to_string_impl((ast_expression*)(e->m_type_params[i]), buf, bufsize, pos);
|
||||
pos = ast_type_to_string_impl(e->m_type_params[i].get(), buf, bufsize, pos);
|
||||
}
|
||||
if (pos + 1 >= bufsize)
|
||||
goto full;
|
||||
|
@ -310,105 +298,24 @@ full:
|
|||
return bufsize;
|
||||
}
|
||||
|
||||
void ast_type_to_string(ast_expression *e, char *buf, size_t bufsize)
|
||||
void ast_type_to_string(const ast_expression *e, char *buf, size_t bufsize)
|
||||
{
|
||||
size_t pos = ast_type_to_string_impl(e, buf, bufsize-1, 0);
|
||||
buf[pos] = 0;
|
||||
}
|
||||
|
||||
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, qc_type t)
|
||||
void ast_value::add_param(ast_value *p)
|
||||
{
|
||||
ast_instantiate(ast_value, ctx, ast_value_delete);
|
||||
ast_expression_init((ast_expression*)self,
|
||||
(ast_expression_codegen*)&ast_value_codegen);
|
||||
self->m_keep_node = true; /* keep */
|
||||
|
||||
self->m_name = name ? util_strdup(name) : nullptr;
|
||||
self->m_vtype = t;
|
||||
self->m_next = nullptr;
|
||||
self->m_isfield = false;
|
||||
self->m_cvq = CV_NONE;
|
||||
self->m_hasvalue = false;
|
||||
self->m_isimm = false;
|
||||
self->m_inexact = false;
|
||||
self->m_uses = 0;
|
||||
memset(&self->m_constval, 0, sizeof(self->m_constval));
|
||||
|
||||
self->m_ir_v = nullptr;
|
||||
self->m_ir_values = nullptr;
|
||||
self->m_ir_value_count = 0;
|
||||
|
||||
self->m_setter = nullptr;
|
||||
self->m_getter = nullptr;
|
||||
self->m_desc = nullptr;
|
||||
|
||||
self->m_argcounter = nullptr;
|
||||
self->m_intrinsic = false;
|
||||
|
||||
return self;
|
||||
m_type_params.emplace_back(p);
|
||||
}
|
||||
|
||||
void ast_value_delete(ast_value* self)
|
||||
ast_binary::ast_binary(lex_ctx_t ctx, int op,
|
||||
ast_expression* left, ast_expression* right)
|
||||
: ast_expression(ctx, TYPE_ast_binary),
|
||||
m_op(op),
|
||||
// m_left/m_right happen after the peephole step right below
|
||||
m_right_first(false)
|
||||
{
|
||||
if (self->m_name)
|
||||
mem_d((void*)self->m_name);
|
||||
if (self->m_argcounter)
|
||||
mem_d((void*)self->m_argcounter);
|
||||
if (self->m_hasvalue) {
|
||||
switch (self->m_vtype)
|
||||
{
|
||||
case TYPE_STRING:
|
||||
mem_d((void*)self->m_constval.vstring);
|
||||
break;
|
||||
case TYPE_FUNCTION:
|
||||
/* unlink us from the function node */
|
||||
self->m_constval.vfunc->m_function_type = nullptr;
|
||||
break;
|
||||
/* NOTE: delete function? currently collected in
|
||||
* the parser structure
|
||||
*/
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (self->m_ir_values)
|
||||
mem_d(self->m_ir_values);
|
||||
|
||||
if (self->m_desc)
|
||||
mem_d(self->m_desc);
|
||||
|
||||
// initlist imples an array which implies .next in the expression exists.
|
||||
if (self->m_initlist.size() && self->m_next->m_vtype == TYPE_STRING) {
|
||||
for (auto &it : self->m_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->m_type_params.push_back(p);
|
||||
}
|
||||
|
||||
bool ast_value_set_name(ast_value *self, const char *name)
|
||||
{
|
||||
if (self->m_name)
|
||||
mem_d((void*)self->m_name);
|
||||
self->m_name = util_strdup(name);
|
||||
return !!self->m_name;
|
||||
}
|
||||
|
||||
ast_binary* ast_binary_new(lex_ctx_t ctx, int op,
|
||||
ast_expression* left, ast_expression* right)
|
||||
{
|
||||
ast_instantiate(ast_binary, ctx, ast_binary_delete);
|
||||
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_binary_codegen);
|
||||
|
||||
if (ast_istype(right, ast_unary) && OPTS_OPTIMIZATION(OPTIM_PEEPHOLE)) {
|
||||
ast_unary *unary = ((ast_unary*)right);
|
||||
ast_expression *normal = unary->m_operand;
|
||||
|
@ -427,86 +334,61 @@ ast_binary* ast_binary_new(lex_ctx_t ctx, int op,
|
|||
}
|
||||
}
|
||||
|
||||
self->m_op = op;
|
||||
self->m_left = left;
|
||||
self->m_right = right;
|
||||
self->m_right_first = false;
|
||||
m_left = left;
|
||||
m_right = right;
|
||||
|
||||
ast_propagate_effects(self, left);
|
||||
ast_propagate_effects(self, right);
|
||||
propagate_side_effects(left);
|
||||
propagate_side_effects(right);
|
||||
|
||||
if (op >= INSTR_EQ_F && op <= INSTR_GT)
|
||||
self->m_vtype = TYPE_FLOAT;
|
||||
m_vtype = TYPE_FLOAT;
|
||||
else if (op == INSTR_AND || op == INSTR_OR) {
|
||||
if (OPTS_FLAG(PERL_LOGIC))
|
||||
ast_type_adopt(self, right);
|
||||
adopt_type(*right);
|
||||
else
|
||||
self->m_vtype = TYPE_FLOAT;
|
||||
m_vtype = TYPE_FLOAT;
|
||||
}
|
||||
else if (op == INSTR_BITAND || op == INSTR_BITOR)
|
||||
self->m_vtype = TYPE_FLOAT;
|
||||
m_vtype = TYPE_FLOAT;
|
||||
else if (op == INSTR_MUL_VF || op == INSTR_MUL_FV)
|
||||
self->m_vtype = TYPE_VECTOR;
|
||||
m_vtype = TYPE_VECTOR;
|
||||
else if (op == INSTR_MUL_V)
|
||||
self->m_vtype = TYPE_FLOAT;
|
||||
m_vtype = TYPE_FLOAT;
|
||||
else
|
||||
self->m_vtype = left->m_vtype;
|
||||
m_vtype = left->m_vtype;
|
||||
|
||||
/* references all */
|
||||
self->m_refs = AST_REF_ALL;
|
||||
|
||||
return self;
|
||||
// references all
|
||||
m_refs = AST_REF_ALL;
|
||||
}
|
||||
|
||||
void ast_binary_delete(ast_binary *self)
|
||||
ast_binary::~ast_binary()
|
||||
{
|
||||
if (self->m_refs & AST_REF_LEFT) ast_unref(self->m_left);
|
||||
if (self->m_refs & AST_REF_RIGHT) ast_unref(self->m_right);
|
||||
|
||||
ast_expression_delete((ast_expression*)self);
|
||||
self->~ast_binary();
|
||||
mem_d(self);
|
||||
if (m_refs & AST_REF_LEFT) ast_unref(m_left);
|
||||
if (m_refs & AST_REF_RIGHT) ast_unref(m_right);
|
||||
}
|
||||
|
||||
ast_binstore* ast_binstore_new(lex_ctx_t ctx, int storop, int op,
|
||||
ast_expression* left, ast_expression* right)
|
||||
ast_binstore::ast_binstore(lex_ctx_t ctx, int storop, int mathop,
|
||||
ast_expression* left, ast_expression* right)
|
||||
: ast_expression(ctx, TYPE_ast_binstore),
|
||||
m_opstore(storop),
|
||||
m_opbin(mathop),
|
||||
m_dest(left),
|
||||
m_source(right),
|
||||
m_keep_dest(false)
|
||||
{
|
||||
ast_instantiate(ast_binstore, ctx, ast_binstore_delete);
|
||||
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_binstore_codegen);
|
||||
|
||||
self->m_side_effects = true;
|
||||
|
||||
self->m_opstore = storop;
|
||||
self->m_opbin = op;
|
||||
self->m_dest = left;
|
||||
self->m_source = right;
|
||||
|
||||
self->m_keep_dest = false;
|
||||
|
||||
ast_type_adopt(self, left);
|
||||
return self;
|
||||
m_side_effects = true;
|
||||
adopt_type(*left);
|
||||
}
|
||||
|
||||
void ast_binstore_delete(ast_binstore *self)
|
||||
ast_binstore::~ast_binstore()
|
||||
{
|
||||
if (!self->m_keep_dest)
|
||||
ast_unref(self->m_dest);
|
||||
ast_unref(self->m_source);
|
||||
ast_expression_delete((ast_expression*)self);
|
||||
self->~ast_binstore();
|
||||
mem_d(self);
|
||||
if (!m_keep_dest)
|
||||
ast_unref(m_dest);
|
||||
ast_unref(m_source);
|
||||
}
|
||||
|
||||
ast_unary* ast_unary_new(lex_ctx_t ctx, int op,
|
||||
ast_expression *expr)
|
||||
ast_unary* ast_unary::make(lex_ctx_t ctx, int op, ast_expression *expr)
|
||||
{
|
||||
ast_instantiate(ast_unary, ctx, ast_unary_delete);
|
||||
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_unary_codegen);
|
||||
|
||||
self->m_op = op;
|
||||
self->m_operand = expr;
|
||||
|
||||
|
||||
if (ast_istype(expr, ast_unary) && OPTS_OPTIMIZATION(OPTIM_PEEPHOLE)) {
|
||||
ast_unary *prev = (ast_unary*)((ast_unary*)expr)->m_operand;
|
||||
|
||||
|
@ -515,93 +397,76 @@ ast_unary* ast_unary_new(lex_ctx_t ctx, int op,
|
|||
prev = (ast_unary*)((ast_unary*)expr)->m_operand;
|
||||
|
||||
if (ast_istype(prev, ast_unary)) {
|
||||
ast_expression_delete((ast_expression*)self);
|
||||
mem_d(self);
|
||||
++opts_optimizationcount[OPTIM_PEEPHOLE];
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
|
||||
ast_propagate_effects(self, expr);
|
||||
return new ast_unary(ctx, op, expr);
|
||||
}
|
||||
|
||||
ast_unary::ast_unary(lex_ctx_t ctx, int op, ast_expression *expr)
|
||||
: ast_expression(ctx, TYPE_ast_unary),
|
||||
m_op(op),
|
||||
m_operand(expr)
|
||||
{
|
||||
propagate_side_effects(expr);
|
||||
if ((op >= INSTR_NOT_F && op <= INSTR_NOT_FNC) || op == VINSTR_NEG_F) {
|
||||
self->m_vtype = TYPE_FLOAT;
|
||||
m_vtype = TYPE_FLOAT;
|
||||
} else if (op == VINSTR_NEG_V) {
|
||||
self->m_vtype = TYPE_VECTOR;
|
||||
m_vtype = TYPE_VECTOR;
|
||||
} else {
|
||||
compile_error(ctx, "cannot determine type of unary operation %s", util_instr_str[op]);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void ast_unary_delete(ast_unary *self)
|
||||
ast_unary::~ast_unary()
|
||||
{
|
||||
if (self->m_operand) ast_unref(self->m_operand);
|
||||
ast_expression_delete((ast_expression*)self);
|
||||
self->~ast_unary();
|
||||
mem_d(self);
|
||||
if (m_operand)
|
||||
ast_unref(m_operand);
|
||||
}
|
||||
|
||||
ast_return* ast_return_new(lex_ctx_t ctx, ast_expression *expr)
|
||||
ast_return::ast_return(lex_ctx_t ctx, ast_expression *expr)
|
||||
: ast_expression(ctx, TYPE_ast_return),
|
||||
m_operand(expr)
|
||||
{
|
||||
ast_instantiate(ast_return, ctx, ast_return_delete);
|
||||
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_return_codegen);
|
||||
|
||||
self->m_operand = expr;
|
||||
|
||||
if (expr)
|
||||
ast_propagate_effects(self, expr);
|
||||
|
||||
return self;
|
||||
propagate_side_effects(expr);
|
||||
}
|
||||
|
||||
void ast_return_delete(ast_return *self)
|
||||
ast_return::~ast_return()
|
||||
{
|
||||
if (self->m_operand)
|
||||
ast_unref(self->m_operand);
|
||||
ast_expression_delete((ast_expression*)self);
|
||||
self->~ast_return();
|
||||
mem_d(self);
|
||||
if (m_operand)
|
||||
ast_unref(m_operand);
|
||||
}
|
||||
|
||||
ast_entfield* ast_entfield_new(lex_ctx_t ctx, ast_expression *entity, ast_expression *field)
|
||||
ast_entfield::ast_entfield(lex_ctx_t ctx, ast_expression *entity, ast_expression *field)
|
||||
: ast_entfield(ctx, entity, field, field->m_next)
|
||||
{
|
||||
if (field->m_vtype != TYPE_FIELD) {
|
||||
compile_error(ctx, "ast_entfield_new with expression not of type field");
|
||||
return nullptr;
|
||||
}
|
||||
return ast_entfield_new_force(ctx, entity, field, field->m_next);
|
||||
if (field->m_vtype != TYPE_FIELD)
|
||||
compile_error(ctx, "ast_entfield with expression not of type field");
|
||||
}
|
||||
|
||||
ast_entfield* ast_entfield_new_force(lex_ctx_t ctx, ast_expression *entity, ast_expression *field, const ast_expression *outtype)
|
||||
ast_entfield::ast_entfield(lex_ctx_t ctx, ast_expression *entity, ast_expression *field, const ast_expression *outtype)
|
||||
: ast_expression(ctx, TYPE_ast_entfield),
|
||||
m_entity(entity),
|
||||
m_field(field)
|
||||
{
|
||||
ast_instantiate(ast_entfield, ctx, ast_entfield_delete);
|
||||
propagate_side_effects(*m_entity);
|
||||
propagate_side_effects(*m_field);
|
||||
|
||||
if (!outtype) {
|
||||
mem_d(self);
|
||||
/* Error: field has no type... */
|
||||
return nullptr;
|
||||
compile_error(ctx, "ast_entfield: field has no type");
|
||||
m_vtype = TYPE_VOID;
|
||||
}
|
||||
|
||||
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_entfield_codegen);
|
||||
|
||||
self->m_entity = entity;
|
||||
self->m_field = field;
|
||||
ast_propagate_effects(self, entity);
|
||||
ast_propagate_effects(self, field);
|
||||
|
||||
ast_type_adopt(self, outtype);
|
||||
return self;
|
||||
else
|
||||
adopt_type(*outtype);
|
||||
}
|
||||
|
||||
void ast_entfield_delete(ast_entfield *self)
|
||||
ast_entfield::~ast_entfield()
|
||||
{
|
||||
ast_unref(self->m_entity);
|
||||
ast_unref(self->m_field);
|
||||
ast_expression_delete((ast_expression*)self);
|
||||
self->~ast_entfield();
|
||||
mem_d(self);
|
||||
ast_unref(m_entity);
|
||||
ast_unref(m_field);
|
||||
}
|
||||
|
||||
ast_member* ast_member_new(lex_ctx_t ctx, ast_expression *owner, unsigned int field, const char *name)
|
||||
|
@ -632,7 +497,7 @@ ast_member* ast_member_new(lex_ctx_t ctx, ast_expression *owner, unsigned int fi
|
|||
|
||||
self->m_rvalue = false;
|
||||
self->m_owner = owner;
|
||||
ast_propagate_effects(self, owner);
|
||||
self->propagate_side_effects(owner);
|
||||
|
||||
self->m_field = field;
|
||||
if (name)
|
||||
|
@ -683,8 +548,8 @@ ast_array_index* ast_array_index_new(lex_ctx_t ctx, ast_expression *array, ast_e
|
|||
|
||||
self->m_array = array;
|
||||
self->m_index = index;
|
||||
ast_propagate_effects(self, array);
|
||||
ast_propagate_effects(self, index);
|
||||
self->propagate_side_effects(array);
|
||||
self->propagate_side_effects(index);
|
||||
|
||||
ast_type_adopt(self, outtype);
|
||||
if (array->m_vtype == TYPE_FIELD && outtype->m_vtype == TYPE_ARRAY) {
|
||||
|
@ -741,11 +606,11 @@ ast_ifthen* ast_ifthen_new(lex_ctx_t ctx, ast_expression *cond, ast_expression *
|
|||
self->m_cond = cond;
|
||||
self->m_on_true = ontrue;
|
||||
self->m_on_false = onfalse;
|
||||
ast_propagate_effects(self, cond);
|
||||
self->propagate_side_effects(cond);
|
||||
if (ontrue)
|
||||
ast_propagate_effects(self, ontrue);
|
||||
self->propagate_side_effects(ontrue);
|
||||
if (onfalse)
|
||||
ast_propagate_effects(self, onfalse);
|
||||
self->propagate_side_effects(onfalse);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -776,9 +641,9 @@ ast_ternary* ast_ternary_new(lex_ctx_t ctx, ast_expression *cond, ast_expression
|
|||
self->m_cond = cond;
|
||||
self->m_on_true = ontrue;
|
||||
self->m_on_false = onfalse;
|
||||
ast_propagate_effects(self, cond);
|
||||
ast_propagate_effects(self, ontrue);
|
||||
ast_propagate_effects(self, onfalse);
|
||||
self->propagate_side_effects(cond);
|
||||
self->propagate_side_effects(ontrue);
|
||||
self->propagate_side_effects(onfalse);
|
||||
|
||||
if (ontrue->m_vtype == TYPE_NIL)
|
||||
exprtype = onfalse;
|
||||
|
@ -820,15 +685,15 @@ ast_loop* ast_loop_new(lex_ctx_t ctx,
|
|||
self->m_post_not = post_not;
|
||||
|
||||
if (initexpr)
|
||||
ast_propagate_effects(self, initexpr);
|
||||
self->propagate_side_effects(initexpr);
|
||||
if (precond)
|
||||
ast_propagate_effects(self, precond);
|
||||
self->propagate_side_effects(precond);
|
||||
if (postcond)
|
||||
ast_propagate_effects(self, postcond);
|
||||
self->propagate_side_effects(postcond);
|
||||
if (increment)
|
||||
ast_propagate_effects(self, increment);
|
||||
self->propagate_side_effects(increment);
|
||||
if (body)
|
||||
ast_propagate_effects(self, body);
|
||||
self->propagate_side_effects(body);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -875,7 +740,7 @@ ast_switch* ast_switch_new(lex_ctx_t ctx, ast_expression *op)
|
|||
|
||||
self->m_operand = op;
|
||||
|
||||
ast_propagate_effects(self, op);
|
||||
self->propagate_side_effects(op);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -1141,7 +1006,7 @@ ast_block* ast_block_new(lex_ctx_t ctx)
|
|||
|
||||
bool ast_block_add_expr(ast_block *self, ast_expression *e)
|
||||
{
|
||||
ast_propagate_effects(self, e);
|
||||
self->propagate_side_effects(e);
|
||||
self->m_exprs.push_back(e);
|
||||
if (self->m_next) {
|
||||
ast_delete(self->m_next);
|
||||
|
|
139
ast.h
139
ast.h
|
@ -101,29 +101,32 @@ typedef void ast_node_delete(ast_node*);
|
|||
|
||||
struct ast_node
|
||||
{
|
||||
//ast_node() = delete;
|
||||
//ast_node(lex_ctx_t, int nodetype);
|
||||
//virtual ~ast_node();
|
||||
ast_node() = delete;
|
||||
ast_node(lex_ctx_t, int nodetype);
|
||||
virtual ~ast_node();
|
||||
|
||||
lex_ctx_t m_context;
|
||||
/* I don't feel comfortable using keywords like 'delete' as names... */
|
||||
ast_node_delete *m_destroy;
|
||||
int m_node_type;
|
||||
/* keep_node: if a node contains this node, 'keep_node'
|
||||
* prevents its dtor from destroying this node as well.
|
||||
*/
|
||||
bool m_keep_node;
|
||||
bool m_side_effects;
|
||||
|
||||
void propagate_side_effects(ast_node *other) const;
|
||||
};
|
||||
|
||||
#define ast_delete(x) ( (x)->m_destroy((x)) )
|
||||
#define ast_unref(x) do \
|
||||
{ \
|
||||
if (! (x)->m_keep_node ) { \
|
||||
ast_delete(x); \
|
||||
delete (x); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
enum class ast_copy_type_t { value };
|
||||
static const ast_copy_type_t ast_copy_type = ast_copy_type_t::value;
|
||||
|
||||
/* Expression interface
|
||||
*
|
||||
* Any expression or block returns an ir_value, and needs
|
||||
|
@ -144,27 +147,36 @@ typedef bool ast_expression_codegen(ast_expression*,
|
|||
* variables through the environment (or functions, constants...).
|
||||
*/
|
||||
struct ast_expression : ast_node {
|
||||
ast_expression() {}
|
||||
ast_expression() = delete;
|
||||
ast_expression(lex_ctx_t ctx, int nodetype, qc_type vtype);
|
||||
ast_expression(lex_ctx_t ctx, int nodetype);
|
||||
~ast_expression();
|
||||
ast_expression(ast_copy_type_t, int nodetype, const ast_expression&);
|
||||
ast_expression(ast_copy_type_t, const ast_expression&);
|
||||
|
||||
ast_expression_codegen *m_codegen;
|
||||
qc_type m_vtype;
|
||||
ast_expression *m_next;
|
||||
static ast_expression *shallow_type(lex_ctx_t ctx, qc_type vtype);
|
||||
|
||||
bool compare_type(const ast_expression &other) const;
|
||||
void adopt_type(const ast_expression &other);
|
||||
|
||||
qc_type m_vtype = TYPE_VOID;
|
||||
ast_expression *m_next = nullptr;
|
||||
/* arrays get a member-count */
|
||||
size_t m_count;
|
||||
std::vector<ast_value*> m_type_params;
|
||||
size_t m_count = 0;
|
||||
std::vector<std::unique_ptr<ast_value>> m_type_params;
|
||||
|
||||
ast_flag_t m_flags;
|
||||
ast_flag_t m_flags = 0;
|
||||
/* void foo(string...) gets varparam set as a restriction
|
||||
* for variadic parameters
|
||||
*/
|
||||
ast_expression *m_varparam;
|
||||
ast_expression *m_varparam = nullptr;
|
||||
/* The codegen functions should store their output values
|
||||
* so we can call it multiple times without re-evaluating.
|
||||
* Store lvalue and rvalue seperately though. So that
|
||||
* ast_entfield for example can generate both if required.
|
||||
*/
|
||||
ir_value *m_outl;
|
||||
ir_value *m_outr;
|
||||
ir_value *m_outl = nullptr;
|
||||
ir_value *m_outr = nullptr;
|
||||
};
|
||||
|
||||
/* Value
|
||||
|
@ -186,16 +198,26 @@ union basic_value_t {
|
|||
|
||||
struct ast_value : ast_expression
|
||||
{
|
||||
const char *m_name;
|
||||
const char *m_desc;
|
||||
ast_value() = delete;
|
||||
ast_value(lex_ctx_t ctx, const std::string &name, qc_type qctype);
|
||||
~ast_value();
|
||||
|
||||
const char *m_argcounter;
|
||||
ast_value(ast_copy_type_t, const ast_expression&, const std::string&);
|
||||
ast_value(ast_copy_type_t, const ast_value&);
|
||||
ast_value(ast_copy_type_t, const ast_value&, const std::string&);
|
||||
|
||||
int m_cvq; /* const/var qualifier */
|
||||
bool m_isfield; /* this declares a field */
|
||||
bool m_isimm; /* an immediate, not just const */
|
||||
bool m_hasvalue;
|
||||
bool m_inexact; /* inexact coming from folded expression */
|
||||
void add_param(ast_value*);
|
||||
|
||||
std::string m_name;
|
||||
std::string m_desc;
|
||||
|
||||
const char *m_argcounter = nullptr;
|
||||
|
||||
int m_cvq = CV_NONE; /* const/var qualifier */
|
||||
bool m_isfield = false; /* this declares a field */
|
||||
bool m_isimm = false; /* an immediate, not just const */
|
||||
bool m_hasvalue = false;
|
||||
bool m_inexact = false; /* inexact coming from folded expression */
|
||||
basic_value_t m_constval;
|
||||
/* for TYPE_ARRAY we have an optional vector
|
||||
* of constants when an initializer list
|
||||
|
@ -204,41 +226,23 @@ struct ast_value : ast_expression
|
|||
std::vector<basic_value_t> m_initlist;
|
||||
|
||||
/* usecount for the parser */
|
||||
size_t m_uses;
|
||||
size_t m_uses = 0;
|
||||
|
||||
ir_value *m_ir_v;
|
||||
ir_value **m_ir_values;
|
||||
size_t m_ir_value_count;
|
||||
ir_value *m_ir_v = nullptr;
|
||||
ir_value **m_ir_values = nullptr;
|
||||
size_t m_ir_value_count = 0;
|
||||
|
||||
/* ONLY for arrays in progs version up to 6 */
|
||||
ast_value *m_setter;
|
||||
ast_value *m_getter;
|
||||
ast_value *m_setter = nullptr;
|
||||
ast_value *m_getter = nullptr;
|
||||
|
||||
|
||||
bool m_intrinsic; /* true if associated with intrinsic */
|
||||
bool m_intrinsic = false; /* true if associated with intrinsic */
|
||||
};
|
||||
|
||||
ast_value* ast_value_new(lex_ctx_t ctx, const char *name, qc_type qctype);
|
||||
ast_value* ast_value_copy(const ast_value *self);
|
||||
/* This will NOT delete an underlying ast_function */
|
||||
void ast_value_delete(ast_value*);
|
||||
|
||||
bool ast_value_set_name(ast_value*, const char *name);
|
||||
|
||||
/*
|
||||
bool ast_value_codegen(ast_value*, ast_function*, bool lvalue, ir_value**);
|
||||
bool ast_local_codegen(ast_value *self, ir_function *func, bool isparam);
|
||||
*/
|
||||
|
||||
bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield);
|
||||
|
||||
void ast_value_params_add(ast_value*, ast_value*);
|
||||
|
||||
bool ast_compare_type(ast_expression *a, ast_expression *b);
|
||||
ast_expression* ast_type_copy(lex_ctx_t ctx, const ast_expression *ex);
|
||||
#define ast_type_adopt(a, b) ast_type_adopt_impl((ast_expression*)(a), (ast_expression*)(b))
|
||||
void ast_type_adopt_impl(ast_expression *self, const ast_expression *other);
|
||||
void ast_type_to_string(ast_expression *e, char *buf, size_t bufsize);
|
||||
void ast_type_to_string(const ast_expression *e, char *buf, size_t bufsize);
|
||||
|
||||
enum ast_binary_ref {
|
||||
AST_REF_NONE = 0,
|
||||
|
@ -254,16 +258,16 @@ enum ast_binary_ref {
|
|||
*/
|
||||
struct ast_binary : ast_expression
|
||||
{
|
||||
ast_binary() = delete;
|
||||
ast_binary(lex_ctx_t ctx, int op, ast_expression *l, ast_expression *r);
|
||||
~ast_binary();
|
||||
|
||||
int m_op;
|
||||
ast_expression *m_left;
|
||||
ast_expression *m_right;
|
||||
ast_binary_ref m_refs;
|
||||
bool m_right_first;
|
||||
};
|
||||
ast_binary* ast_binary_new(lex_ctx_t ctx,
|
||||
int op,
|
||||
ast_expression *left,
|
||||
ast_expression *right);
|
||||
|
||||
/* Binstore
|
||||
*
|
||||
|
@ -272,6 +276,10 @@ ast_binary* ast_binary_new(lex_ctx_t ctx,
|
|||
*/
|
||||
struct ast_binstore : ast_expression
|
||||
{
|
||||
ast_binstore() = delete;
|
||||
ast_binstore(lex_ctx_t ctx, int storeop, int mathop, ast_expression *l, ast_expression *r);
|
||||
~ast_binstore();
|
||||
|
||||
int m_opstore;
|
||||
int m_opbin;
|
||||
ast_expression *m_dest;
|
||||
|
@ -291,12 +299,14 @@ ast_binstore* ast_binstore_new(lex_ctx_t ctx,
|
|||
*/
|
||||
struct ast_unary : ast_expression
|
||||
{
|
||||
ast_unary() = delete;
|
||||
~ast_unary();
|
||||
int m_op;
|
||||
ast_expression *m_operand;
|
||||
static ast_unary* make(lex_ctx_t ctx, int op, ast_expression *expr);
|
||||
private:
|
||||
ast_unary(lex_ctx_t ctx, int op, ast_expression *expr);
|
||||
};
|
||||
ast_unary* ast_unary_new(lex_ctx_t ctx,
|
||||
int op,
|
||||
ast_expression *expr);
|
||||
|
||||
/* Return
|
||||
*
|
||||
|
@ -306,10 +316,11 @@ ast_unary* ast_unary_new(lex_ctx_t ctx,
|
|||
*/
|
||||
struct ast_return : ast_expression
|
||||
{
|
||||
ast_return() = delete;
|
||||
ast_return(lex_ctx_t ctx, ast_expression *expr);
|
||||
~ast_return();
|
||||
ast_expression *m_operand;
|
||||
};
|
||||
ast_return* ast_return_new(lex_ctx_t ctx,
|
||||
ast_expression *expr);
|
||||
|
||||
/* Entity-field
|
||||
*
|
||||
|
@ -326,13 +337,15 @@ ast_return* ast_return_new(lex_ctx_t ctx,
|
|||
*/
|
||||
struct ast_entfield : ast_expression
|
||||
{
|
||||
/* The entity can come from an expression of course. */
|
||||
ast_entfield() = delete;
|
||||
ast_entfield(lex_ctx_t ctx, ast_expression *entity, ast_expression *field);
|
||||
ast_entfield(lex_ctx_t ctx, ast_expression *entity, ast_expression *field, const ast_expression *outtype);
|
||||
~ast_entfield();
|
||||
// The entity can come from an expression of course.
|
||||
ast_expression *m_entity;
|
||||
/* As can the field, it just must result in a value of TYPE_FIELD */
|
||||
// As can the field, it just must result in a value of TYPE_FIELD
|
||||
ast_expression *m_field;
|
||||
};
|
||||
ast_entfield* ast_entfield_new(lex_ctx_t ctx, ast_expression *entity, ast_expression *field);
|
||||
ast_entfield* ast_entfield_new_force(lex_ctx_t ctx, ast_expression *entity, ast_expression *field, const ast_expression *outtype);
|
||||
|
||||
/* Member access:
|
||||
*
|
||||
|
|
10
parser.cpp
10
parser.cpp
|
@ -4376,7 +4376,7 @@ static ast_value* parser_create_array_setter_proto(parser_t *parser, ast_value *
|
|||
fval->m_next = (ast_expression*)ast_value_new(array->m_context, "<void>", TYPE_VOID);
|
||||
|
||||
index = ast_value_new(array->m_context, "index", TYPE_FLOAT);
|
||||
value = ast_value_copy((ast_value*)array->m_next);
|
||||
value = ast_value_from_type((ast_value*)array->m_next);
|
||||
|
||||
if (!index || !value) {
|
||||
parseerror(parser, "failed to create locals for array accessor");
|
||||
|
@ -4442,7 +4442,7 @@ static bool parser_create_array_field_setter(parser_t *parser, ast_value *array,
|
|||
|
||||
entity = ast_value_new(array->m_context, "entity", TYPE_ENTITY);
|
||||
index = ast_value_new(array->m_context, "index", TYPE_FLOAT);
|
||||
value = ast_value_copy((ast_value*)array->m_next);
|
||||
value = ast_value_from_type((ast_value*)array->m_next);
|
||||
if (!entity || !index || !value) {
|
||||
parseerror(parser, "failed to create locals for array accessor");
|
||||
goto cleanup;
|
||||
|
@ -4790,7 +4790,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va
|
|||
|
||||
/* generate the basic type value */
|
||||
if (cached_typedef) {
|
||||
var = ast_value_copy(cached_typedef);
|
||||
var = ast_value_from_type(cached_typedef);
|
||||
ast_value_set_name(var, "<type(from_def)>");
|
||||
} else
|
||||
var = ast_value_new(ctx, "<type>", parser_token(parser)->constval.t);
|
||||
|
@ -4826,7 +4826,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va
|
|||
|
||||
/* store the base if requested */
|
||||
if (storebase) {
|
||||
*storebase = ast_value_copy(var);
|
||||
*storebase = ast_value_from_type(var);
|
||||
if (isfield) {
|
||||
tmp = ast_value_new(ctx, "<type:f>", TYPE_FIELD);
|
||||
tmp->m_next = (ast_expression*)*storebase;
|
||||
|
@ -5795,7 +5795,7 @@ another:
|
|||
parseerror(parser, "expected another variable");
|
||||
break;
|
||||
}
|
||||
var = ast_value_copy(basetype);
|
||||
var = ast_value_from_type(basetype);
|
||||
cleanvar = true;
|
||||
ast_value_set_name(var, parser_tokval(parser));
|
||||
if (!parser_next(parser)) {
|
||||
|
|
Loading…
Reference in a new issue