]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
Merging master to handle vector members, fields, and members of vector fields
authorWolfgang (Blub) Bumiller <blub@speed.at>
Sun, 12 Aug 2012 08:08:41 +0000 (10:08 +0200)
committerWolfgang (Blub) Bumiller <blub@speed.at>
Sun, 12 Aug 2012 08:08:41 +0000 (10:08 +0200)
ast.c
exec.c
execloop.h
flags.def
gmqcc.h
ir.c
ir.h
test/ast-macros.h
test/ast-test.c

diff --git a/ast.c b/ast.c
index 5f947b0e02903709cde800090c03f877a1b31048..117f845ae0bc816b40a99f5a3ab0a9741ace5ac6 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -94,6 +94,15 @@ static ast_value* ast_value_copy(const ast_value *self)
     return cp;
 }
 
+static ast_expression* ast_shallow_type(lex_ctx ctx, int vtype)
+{
+    ast_instantiate(ast_expression, ctx, ast_expression_delete_full);
+    self->expression.codegen = NULL;
+    self->expression.next    = NULL;
+    self->expression.vtype   = vtype;
+    return self;
+}
+
 static ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex)
 {
     size_t i;
@@ -306,10 +315,22 @@ ast_member* ast_member_new(lex_ctx ctx, ast_expression *owner, unsigned int fiel
         return NULL;
     }
 
+    if (owner->expression.vtype != TYPE_FLOAT &&
+        owner->expression.vtype != TYPE_FIELD) {
+        printf("ast_member on an invalid owner of type %i\n", (int)owner->expression.vtype);
+        mem_d(self);
+        return NULL;
+    }
+
     ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_member_codegen);
 
-    self->expression.vtype = TYPE_FLOAT;
-    self->expression.next  = NULL;
+    if (owner->expression.vtype == TYPE_VECTOR) {
+        self->expression.vtype = TYPE_FLOAT;
+        self->expression.next  = NULL;
+    } else {
+        self->expression.vtype = TYPE_FIELD;
+        self->expression.next = ast_shallow_type(ctx, TYPE_FLOAT);
+    }
 
     self->owner = owner;
     self->field = field;
@@ -628,6 +649,18 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir)
         return true;
     }
 
+    if (self->expression.vtype == TYPE_FIELD) {
+        v = ir_builder_create_field(ir, self->name, self->expression.next->expression.vtype);
+        if (!v)
+            return false;
+        if (self->isconst) {
+            printf("TODO: constant field pointers with value\n");
+            goto error;
+        }
+        self->ir_v = v;
+        return true;
+    }
+
     v = ir_builder_create_global(ir, self->name, self->expression.vtype);
     if (!v) {
         printf("ir_builder_create_global failed\n");
@@ -954,14 +987,17 @@ bool ast_entfield_codegen(ast_entfield *self, ast_function *func, bool lvalue, i
 bool ast_member_codegen(ast_member *self, ast_function *func, bool lvalue, ir_value **out)
 {
     ast_expression_codegen *cgen;
-    ir_value *vec, *field;
+    ir_value *vec;
 
     cgen = self->owner->expression.codegen;
     if (!(*cgen)((ast_expression*)(self->owner), func, true, &vec))
         return false;
 
-    if (vec->vtype != TYPE_VECTOR)
+    if (vec->vtype != TYPE_VECTOR &&
+        !(vec->vtype == TYPE_FIELD && self->owner->expression.next->expression.vtype == TYPE_VECTOR))
+    {
         return false;
+    }
 
     *out = ir_value_vector_member(vec, self->field);
 
diff --git a/exec.c b/exec.c
index c65c6e2d2edfb590754eaf515f6ec3c06308ec2d..b957a83a8722401f76a7e8f723e13f36661844f6 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -13,6 +13,7 @@ MEM_VEC_FUN_APPEND(qc_program,  char,                   strings)
 MEM_VEC_FUN_RESIZE(qc_program,  char,                   strings)
 MEM_VEC_FUNCTIONS(qc_program,   qcint,                  globals)
 MEM_VEC_FUNCTIONS(qc_program,   qcint,                  entitydata)
+MEM_VEC_FUNCTIONS(qc_program,   bool,                   entitypool)
 
 MEM_VEC_FUNCTIONS(qc_program,   qcint,         localstack)
 MEM_VEC_FUN_APPEND(qc_program,  qcint,         localstack)
@@ -34,10 +35,20 @@ static void loaderror(const char *fmt, ...)
     printf(": %s\n", strerror(err));
 }
 
+static void printvmerr(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    vprintf(fmt, ap);
+    va_end(ap);
+    putchar('\n');
+}
+
 qc_program* prog_load(const char *filename)
 {
     qc_program *prog;
     prog_header header;
+    size_t      i;
     FILE *file;
 
     file = fopen(filename, "rb");
@@ -108,6 +119,19 @@ qc_program* prog_load(const char *filename)
     if (!qc_program_strings_resize(prog, prog->strings_count + 16*1024))
         goto error;
 
+    /* spawn the world entity */
+    if (!qc_program_entitypool_add(prog, true)) {
+        loaderror("failed to allocate world entity\n");
+        goto error;
+    }
+    for (i = 0; i < prog->entityfields; ++i) {
+        if (!qc_program_entitydata_add(prog, 0)) {
+            loaderror("failed to allocate world data\n");
+            goto error;
+        }
+    }
+    prog->entities = 1;
+
     return prog;
 
 error:
@@ -119,6 +143,7 @@ error:
     if (prog->strings)    mem_d(prog->strings);
     if (prog->globals)    mem_d(prog->globals);
     if (prog->entitydata) mem_d(prog->entitydata);
+    if (prog->entitypool) mem_d(prog->entitypool);
     mem_d(prog);
     return NULL;
 }
@@ -133,6 +158,7 @@ void prog_delete(qc_program *prog)
     MEM_VECTOR_CLEAR(prog, strings);
     MEM_VECTOR_CLEAR(prog, globals);
     MEM_VECTOR_CLEAR(prog, entitydata);
+    MEM_VECTOR_CLEAR(prog, entitypool);
     MEM_VECTOR_CLEAR(prog, localstack);
     MEM_VECTOR_CLEAR(prog, stack);
     MEM_VECTOR_CLEAR(prog, profile);
@@ -177,7 +203,58 @@ prog_section_def* prog_getdef(qc_program *prog, qcint off)
 
 qcany* prog_getedict(qc_program *prog, qcint e)
 {
-    return (qcany*)(prog->entitydata + (prog->entityfields + e));
+    if (e >= prog->entitypool_count) {
+        prog->vmerror++;
+        printf("Accessing out of bounds edict %i\n", (int)e);
+        e = 0;
+    }
+    return (qcany*)(prog->entitydata + (prog->entityfields * e));
+}
+
+qcint prog_spawn_entity(qc_program *prog)
+{
+    size_t i;
+    qcint  e;
+    for (e = 0; e < (qcint)prog->entitypool_count; ++e) {
+        if (!prog->entitypool[e]) {
+            char *data = (char*)(prog->entitydata + (prog->entityfields * e));
+            memset(data, 0, prog->entityfields * sizeof(qcint));
+            return e;
+        }
+    }
+    if (!qc_program_entitypool_add(prog, true)) {
+        prog->vmerror++;
+        printf("Failed to allocate entity\n");
+        return 0;
+    }
+    prog->entities++;
+    for (i = 0; i < prog->entityfields; ++i) {
+        if (!qc_program_entitydata_add(prog, 0)) {
+            printf("Failed to allocate entity\n");
+            return 0;
+        }
+    }
+    return e;
+}
+
+void prog_free_entity(qc_program *prog, qcint e)
+{
+    if (!e) {
+        prog->vmerror++;
+        printf("Trying to free world entity\n");
+        return;
+    }
+    if (e >= prog->entitypool_count) {
+        prog->vmerror++;
+        printf("Trying to free out of bounds entity\n");
+        return;
+    }
+    if (!prog->entitypool[e]) {
+        prog->vmerror++;
+        printf("Double free on entity\n");
+        return;
+    }
+    prog->entitypool[e] = false;
 }
 
 qcint prog_tempstring(qc_program *prog, const char *_str)
@@ -439,6 +516,8 @@ bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long
     long jumpcount = 0;
     prog_section_statement *st;
 
+    prog->vmerror = 0;
+
     st = prog->code + prog_enterfunction(prog, func);
     --st;
     switch (flags)
@@ -477,6 +556,8 @@ bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long
 cleanup:
     prog->localstack_count = 0;
     prog->stack_count = 0;
+    if (prog->vmerror)
+        return false;
     return true;
 }
 
@@ -488,16 +569,66 @@ cleanup:
 bool        opts_debug    = false;
 bool        opts_memchk   = false;
 
+#define CheckArgs(num) do {                                                    \
+    if (prog->argc != (num)) {                                                 \
+        prog->vmerror++;                                                       \
+        printf("ERROR: invalid number of arguments for %s: %i, expected %i\n", \
+        __FUNCTION__, prog->argc, (num));                                      \
+        return -1;                                                             \
+    }                                                                          \
+} while (0)
+
+#define GetGlobal(idx) ((qcany*)(prog->globals + (idx)))
+#define GetArg(num) GetGlobal(OFS_PARM0 + 3*(num))
+#define Return(any) *(GetGlobal(OFS_RETURN)) = (any)
+
 static int qc_print(qc_program *prog)
 {
-    qcany *str = (qcany*)(prog->globals + OFS_PARM0);
-    printf("%s", prog_getstring(prog, str->string));
+    size_t i;
+    for (i = 0; i < prog->argc; ++i) {
+        qcany *str = (qcany*)(prog->globals + OFS_PARM0 + 3*i);
+        printf("%s", prog_getstring(prog, str->string));
+    }
+    return 0;
+}
+
+static int qc_ftos(qc_program *prog)
+{
+    char buffer[512];
+    qcany *num;
+    qcany str;
+    CheckArgs(1);
+    num = GetArg(0);
+    snprintf(buffer, sizeof(buffer), "%g", num->_float);
+    str.string = prog_tempstring(prog, buffer);
+    Return(str);
+    return 0;
+}
+
+static int qc_spawn(qc_program *prog)
+{
+    qcany ent;
+    CheckArgs(0);
+    ent.edict = prog_spawn_entity(prog);
+    Return(ent);
+    return (ent.edict ? 0 : -1);
+}
+
+static int qc_kill(qc_program *prog)
+{
+    qcany *ent;
+    CheckArgs(1);
+    ent = GetArg(0);
+    prog_free_entity(prog, ent->edict);
     return 0;
 }
 
 static prog_builtin qc_builtins[] = {
     NULL,
-    &qc_print
+    &qc_print,
+    &qc_ftos,
+    &qc_spawn,
+    &qc_kill
 };
 static size_t qc_builtins_count = sizeof(qc_builtins) / sizeof(qc_builtins[0]);
 
@@ -528,6 +659,7 @@ int main(int argc, char **argv)
         if (!strcmp(name, "main"))
             fnmain = (qcint)i;
     }
+    printf("Entity field space: %i\n", (int)prog->entityfields);
     if (fnmain > 0)
     {
         prog_exec(prog, &prog->functions[fnmain], VMXF_TRACE, VM_JUMPS_DEFAULT);
index 3b6d666f4877d03738dc3bb5713c715e54f1e608..b75061e50b4633637e8d068c3c8a08305b7798e3 100644 (file)
@@ -16,7 +16,7 @@
 #endif
 
 #if !defined(PRVM_ERROR)
-#   define PRVM_ERROR printf
+#   define PRVM_ERROR prog->vmerror++, printvmerr
 #endif
 
 #if !defined(PRVM_NAME)
                                ptr->_int = OPA->_int;
                                break;
                        case INSTR_STOREP_V:
-                               if (OPB->_int < 0 || OPB->_int + 3 >= prog->entitydata_count)
+                               if (OPB->_int < 0 || OPB->_int + 2 >= prog->entitydata_count)
                                {
                                        PRVM_ERROR("%s attempted to write to an out of bounds edict (%i)", PRVM_NAME, OPB->_int);
                                        goto cleanup;
                        case INSTR_ADDRESS:
                                if (OPA->edict < 0 || OPA->edict >= prog->entities)
                                {
-                                       PRVM_ERROR ("%s Progs attempted to address an out of bounds edict number", PRVM_NAME);
+                                       PRVM_ERROR ("%s Progs attempted to address an out of bounds edict number %i", PRVM_NAME, OPA->edict);
                                        goto cleanup;
                                }
                                if ((unsigned int)(OPB->_int) >= (unsigned int)(prog->entityfields))
                                        PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME);
                                        goto cleanup;
                                }
-                               if (OPB->_int < 0 || OPB->_int + 3 >= prog->entityfields)
+                               if (OPB->_int < 0 || OPB->_int + 3 > prog->entityfields)
                                {
                                        PRVM_ERROR("%s attempted to read an invalid field in an edict (%i)", PRVM_NAME, OPB->_int);
                                        goto cleanup;
                                }
                                else
                                        st = prog->code + PROG_ENTERFUNCTION(newf);
+                               if (prog->vmerror)
+                                   goto cleanup;
                                break;
 
                        case INSTR_DONE:
index a7387d1451bf9ef59edd16fda73096c03dd4e420..79ab71ed70445b65475522fedaca340099b3d42c 100644 (file)
--- a/flags.def
+++ b/flags.def
@@ -5,3 +5,4 @@
 GMQCC_DEFINE_FLAG(OVERLAP_LOCALS)
 GMQCC_DEFINE_FLAG(DARKPLACES_STRING_TABLE_BUG)
 GMQCC_DEFINE_FLAG(OMIT_NULL_BYTES)
+GMQCC_DEFINE_FLAG(ADJUST_VECTOR_FIELDS)
diff --git a/gmqcc.h b/gmqcc.h
index 4e1c641c2579f8e66842e38dc71e44ad4878de87..b27998b1262ce1426c0f2cdb0ab8a1e3943998e8 100644 (file)
--- a/gmqcc.h
+++ b/gmqcc.h
@@ -885,6 +885,7 @@ typedef struct qc_program_s {
     MEM_VECTOR_MAKE(char,                   strings);
     MEM_VECTOR_MAKE(qcint,                  globals);
     MEM_VECTOR_MAKE(qcint,                  entitydata);
+    MEM_VECTOR_MAKE(bool,                   entitypool);
 
     size_t tempstring_start;
     size_t tempstring_at;
diff --git a/ir.c b/ir.c
index f34cc911a3242b7100e7f1153203367ae1003392..78c97c7058e6230e397c4ec8a9da343555a0589c 100644 (file)
--- a/ir.c
+++ b/ir.c
@@ -559,6 +559,8 @@ void ir_value_code_setaddr(ir_value *self, int32_t gaddr)
 
 int32_t ir_value_code_addr(const ir_value *self)
 {
+    if (self->store == store_return)
+        return OFS_RETURN + self->code.addroffset;
     return self->code.globaladdr + self->code.addroffset;
 }
 
@@ -594,13 +596,29 @@ ir_value* ir_value_vector_member(ir_value *self, unsigned int member)
     if (self->members[member])
         return self->members[member];
 
-    m = ir_value_var(self->name, self->store, TYPE_FLOAT);
-    if (!m)
-        return NULL;
-    m->context = self->context;
+    if (self->vtype == TYPE_VECTOR)
+    {
+        m = ir_value_var(self->name, self->store, TYPE_FLOAT);
+        if (!m)
+            return NULL;
+        m->context = self->context;
 
-    self->members[member] = m;
-    m->code.addroffset = member;
+        self->members[member] = m;
+        m->code.addroffset = member;
+    }
+    else if (self->vtype == TYPE_FIELD)
+    {
+        if (self->fieldtype != TYPE_VECTOR)
+            return NULL;
+        m = ir_value_var(self->name, self->store, TYPE_FIELD);
+        if (!m)
+            return NULL;
+        m->fieldtype = TYPE_FLOAT;
+        m->context = self->context;
+
+        self->members[member] = m;
+        m->code.addroffset = member;
+    }
 
     return m;
 }
@@ -694,6 +712,15 @@ bool ir_value_set_matrix(ir_value *self, matrix v)
     return true;
 }
 
+bool ir_value_set_field(ir_value *self, ir_value *fld)
+{
+    if (self->vtype != TYPE_FIELD)
+        return false;
+    self->constval.vpointer = fld;
+    self->isconst = true;
+    return true;
+}
+
 bool ir_value_set_string(ir_value *self, const char *str)
 {
     if (self->vtype != TYPE_STRING)
@@ -945,22 +972,26 @@ bool ir_values_overlap(const ir_value *a, const ir_value *b)
 
 bool ir_block_create_store_op(ir_block *self, int op, ir_value *target, ir_value *what)
 {
-    if (target->store == store_value) {
+    ir_instr *in = ir_instr_new(self, op);
+    if (!in)
+        return false;
+
+    if (target->store == store_value &&
+        (op < INSTR_STOREP_F || op > INSTR_STOREP_FNC))
+    {
         fprintf(stderr, "cannot store to an SSA value\n");
         fprintf(stderr, "trying to store: %s <- %s\n", target->name, what->name);
+        fprintf(stderr, "instruction: %s\n", asm_instr[op].m);
+        return false;
+    }
+
+    if (!ir_instr_op(in, 0, target, true) ||
+        !ir_instr_op(in, 1, what, false)  ||
+        !ir_block_instr_add(self, in) )
+    {
         return false;
-    } else {
-        ir_instr *in = ir_instr_new(self, op);
-        if (!in)
-            return false;
-        if (!ir_instr_op(in, 0, target, true) ||
-            !ir_instr_op(in, 1, what, false)  ||
-            !ir_block_instr_add(self, in) )
-        {
-            return false;
-        }
-        return true;
     }
+    return true;
 }
 
 bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what)
@@ -980,6 +1011,11 @@ bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what)
 #endif
         op = type_store_instr[vtype];
 
+    if (OPTS_FLAG(ADJUST_VECTOR_FIELDS)) {
+        if (op == INSTR_STORE_FLD && what->fieldtype == TYPE_VECTOR)
+            op = INSTR_STORE_V;
+    }
+
     return ir_block_create_store_op(self, op, target, what);
 }
 
@@ -997,6 +1033,11 @@ bool ir_block_create_storep(ir_block *self, ir_value *target, ir_value *what)
     vtype = what->vtype;
 
     op = type_storep_instr[vtype];
+    if (OPTS_FLAG(ADJUST_VECTOR_FIELDS)) {
+        if (op == INSTR_STOREP_FLD && what->fieldtype == TYPE_VECTOR)
+            op = INSTR_STOREP_V;
+    }
+
     return ir_block_create_store_op(self, op, target, what);
 }
 
@@ -2178,10 +2219,18 @@ static bool gen_global_field(ir_value *global)
 
         /* copy the field's value */
         ir_value_code_setaddr(global, code_globals_add(code_globals_data[fld->code.globaladdr]));
+        if (global->fieldtype == TYPE_VECTOR) {
+            code_globals_add(code_globals_data[fld->code.globaladdr]+1);
+            code_globals_add(code_globals_data[fld->code.globaladdr]+2);
+        }
     }
     else
     {
         ir_value_code_setaddr(global, code_globals_add(0));
+        if (global->fieldtype == TYPE_VECTOR) {
+            code_globals_add(0);
+            code_globals_add(0);
+        }
     }
     if (global->code.globaladdr < 0)
         return false;
@@ -2408,8 +2457,10 @@ tailcall:
             stmt.o1.u1 = stmt.o3.u1;
             stmt.o3.u1 = 0;
         }
-        else if (stmt.opcode >= INSTR_STORE_F &&
-                 stmt.opcode <= INSTR_STORE_FNC)
+        else if ((stmt.opcode >= INSTR_STORE_F &&
+                  stmt.opcode <= INSTR_STORE_FNC) ||
+                 (stmt.opcode >= INSTR_STOREP_F &&
+                  stmt.opcode <= INSTR_STOREP_FNC))
         {
             /* 2-operand instructions with A -> B */
             stmt.o2.u1 = stmt.o3.u1;
@@ -2622,13 +2673,42 @@ static bool ir_builder_gen_field(ir_builder *self, ir_value *field)
 
     def.type   = field->vtype;
     def.offset = code_globals_elements;
-    def.name   = field->code.name = code_genstring(field->name);
+
+    /* create a global named the same as the field */
+    if (opts_standard == COMPILER_GMQCC) {
+        /* in our standard, the global gets a dot prefix */
+        size_t len = strlen(field->name);
+        char name[1024];
+
+        /* we really don't want to have to allocate this, and 1024
+         * bytes is more than enough for a variable/field name
+         */
+        if (len+2 >= sizeof(name)) {
+            printf("invalid field name size: %u\n", (unsigned int)len);
+            return false;
+        }
+
+        name[0] = '.';
+        strcpy(name+1, field->name); /* no strncpy - we used strlen above */
+        name[len+1] = 0;
+
+        def.name = code_genstring(name);
+        fld.name = def.name + 1; /* we reuse that string table entry */
+    } else {
+        /* in plain QC, there cannot be a global with the same name,
+         * and so we also name the global the same.
+         * FIXME: fteqcc should create a global as well
+         * check if it actually uses the same name. Probably does
+         */
+        def.name = code_genstring(field->name);
+        fld.name = def.name;
+    }
+
+    field->code.name = def.name;
 
     if (code_defs_add(def) < 0)
         return false;
 
-    fld.name = def.name;
-    fld.offset = code_fields_elements;
     fld.type = field->fieldtype;
 
     if (fld.type == TYPE_VOID) {
@@ -2636,13 +2716,21 @@ static bool ir_builder_gen_field(ir_builder *self, ir_value *field)
         return false;
     }
 
+    fld.offset = code_alloc_field(type_sizeof[field->fieldtype]);
+
     if (code_fields_add(fld) < 0)
         return false;
 
-    if (!code_globals_add(code_alloc_field(type_sizeof[field->fieldtype])))
+    ir_value_code_setaddr(field, code_globals_elements);
+    if (!code_globals_add(fld.offset))
         return false;
+    if (fld.type == TYPE_VECTOR) {
+        if (!code_globals_add(fld.offset+1))
+            return false;
+        if (!code_globals_add(fld.offset+2))
+            return false;
+    }
 
-    ir_value_code_setaddr(field, code_globals_add(fld.offset));
     return field->code.globaladdr >= 0;
 }
 
diff --git a/ir.h b/ir.h
index a4dddcb937ea5a151f993e599f98b9a0f5b5881b..66336d6ae5a6b64a5a8e9a2ff64c2e54c48d22ed 100644 (file)
--- a/ir.h
+++ b/ir.h
@@ -97,6 +97,7 @@ bool GMQCC_WARN ir_value_set_int(ir_value*, int i);
 #endif
 bool GMQCC_WARN ir_value_set_string(ir_value*, const char *s);
 bool GMQCC_WARN ir_value_set_vector(ir_value*, vector v);
+bool GMQCC_WARN ir_value_set_field(ir_value*, ir_value *fld);
 /*bool   ir_value_set_pointer_v(ir_value*, ir_value* p); */
 /*bool   ir_value_set_pointer_i(ir_value*, int i);       */
 bool GMQCC_WARN ir_value_set_quaternion(ir_value*, quaternion v);
index ebb3a5bd6b7b09807622a90c8ef9523f0b09e4bb..580cd7a69a38d69835ed1fa2d2b383f0a7eccd90 100644 (file)
@@ -21,6 +21,17 @@ name = ast_value_new(ctx, #varname, type)
 #define MKGLOBAL(name) \
 assert(globals_add(name) >= 0)
 
+#define FIELD(type, name) \
+name = ast_value_new(ctx, #name, TYPE_FIELD);                  \
+do {                                                           \
+    ast_value *field_##name = ast_value_new(ctx, #name, type); \
+    name->expression.next = (ast_expression*)field_##name;     \
+    MKFIELD(name);                                             \
+} while (0)
+
+#define MKFIELD(name) \
+assert(fields_add(name) >= 0)
+
 #define MKCONSTFLOAT(name, value)  \
 do {                               \
     name->isconst = true;          \
@@ -35,6 +46,15 @@ do {                                             \
     MKGLOBAL(name);                              \
 } while(0)
 
+#define MKCONSTVECTOR(name, valx, valy, valz) \
+do {                                          \
+    name->isconst = true;                     \
+    name->constval.vvec.x = (valx);           \
+    name->constval.vvec.y = (valy);           \
+    name->constval.vvec.z = (valz);           \
+    MKGLOBAL(name);                           \
+} while(0)
+
 #define STATE(a)                                 \
 do {                                             \
     ast_expression *exp = (ast_expression*)(a);  \
@@ -47,6 +67,12 @@ do {                                             \
 #define BIN(op, a, b) \
 (ast_expression*)ast_binary_new(ctx, INSTR_##op, (ast_expression*)(a), (ast_expression*)(b))
 
+#define ENTFIELD(a, b) \
+(ast_expression*)ast_entfield_new(ctx, (ast_expression*)(a), (ast_expression*)(b))
+
+#define VECMEM(vec, mem) \
+(ast_expression*)ast_member_new(ctx, (ast_expression*)(vec), (mem))
+
 #define CALL(what)                                             \
 do {                                                           \
     ast_call *call = ast_call_new(ctx, (ast_expression*)what); \
@@ -58,6 +84,13 @@ do {                                                           \
     STATE(call);                                 \
 } while(0)
 
+#define ENDCALLWITH(as, where)                      \
+    {                                               \
+        ast_expression *as = (ast_expression*)call; \
+        where;                                      \
+    }                                               \
+} while(0)
+
 #define WHILE(cond)                                    \
 do {                                                   \
     ast_expression *wh_cond = (ast_expression*)(cond); \
index 3862144d8395a30d7d9f7d771bc1cdb67d2591b2..74800dd8ce7e0d0e753793d0d959109f0f50f895 100644 (file)
@@ -10,6 +10,7 @@
 #define assert(x) do { if ( !(x) ) { printf("Assertion failed: %s\n", #x); abort(); } } while(0)
 
 VECTOR_MAKE(ast_value*, globals);
+VECTOR_MAKE(ast_value*, fields);
 VECTOR_MAKE(ast_function*, functions);
 
 uint32_t    opts_flags[1 + (COUNT_FLAGS / 32)];
@@ -36,13 +37,30 @@ int main()
     DEFVAR(f0);
     DEFVAR(f1);
     DEFVAR(f5);
+    DEFVAR(cv3x4x5);
+    DEFVAR(cv1x1x1);
     DEFVAR(sHello);
+    DEFVAR(sNL);
     DEFVAR(print);
+    DEFVAR(ftos);
+    DEFVAR(spawn);
+
+    DEFVAR(mema);
+    DEFVAR(memb);
+    DEFVAR(memv);
+    DEFVAR(pawn);
 
     /* opts_debug = true; */
 
 BUILTIN(print, TYPE_VOID, -1);
 PARAM(TYPE_STRING, text);
+ENDBUILTIN();
+
+BUILTIN(ftos, TYPE_STRING, -2);
+PARAM(TYPE_FLOAT, value);
+ENDBUILTIN();
+
+BUILTIN(spawn, TYPE_ENTITY, -3);
 ENDBUILTIN();
 
     TESTINIT();
@@ -50,21 +68,36 @@ VAR(TYPE_FLOAT, f0);
 VAR(TYPE_FLOAT, f1);
 VAR(TYPE_FLOAT, f5);
 VAR(TYPE_STRING, sHello);
+VAR(TYPE_STRING, sNL);
+VAR(TYPE_VECTOR, cv3x4x5);
+VAR(TYPE_VECTOR, cv1x1x1);
+
+FIELD(TYPE_FLOAT, mema);
+FIELD(TYPE_FLOAT, memb);
+FIELD(TYPE_VECTOR, memv);
+
 MKCONSTFLOAT(f0, 0.0);
 MKCONSTFLOAT(f1, 1.0);
 MKCONSTFLOAT(f5, 5.0);
 MKCONSTSTRING(sHello, "Hello, World\n");
+MKCONSTSTRING(sNL, "\n");
+MKCONSTVECTOR(cv3x4x5, 3, 4, 5);
+MKCONSTVECTOR(cv1x1x1, 1, 1, 1);
 
 FUNCTION(foo, TYPE_VOID);
 ENDFUNCTION(foo);
 
+#define PRINTNL() do { CALL(print) CALLPARAM(sNL) ENDCALL(); } while(0)
+
 FUNCTION(main, TYPE_VOID);
 
     VAR(TYPE_FLOAT, vi);
     VAR(TYPE_FLOAT, vx);
+    VAR(TYPE_ENTITY, pawn);
 
     MKLOCAL(vi);
     MKLOCAL(vx);
+    MKLOCAL(pawn);
 
     STATE(ASSIGN(STORE_F, vi, f0));
     WHILE(BIN(LT, vi, f5));
@@ -76,11 +109,48 @@ FUNCTION(main, TYPE_VOID);
     CALLPARAM(sHello)
     ENDCALL();
 
+    CALL(spawn)
+    ENDCALLWITH(newent, STATE(ASSIGN(STORE_ENT, pawn, newent)));
+
+    STATE(ASSIGN(STOREP_F, ENTFIELD(pawn, mema), f5));
+    STATE(ASSIGN(STOREP_F, ENTFIELD(pawn, memb), f1));
+    STATE(ASSIGN(STOREP_V, ENTFIELD(pawn, memv), cv3x4x5));
+    CALL(ftos)
+    CALLPARAM(ENTFIELD(pawn, mema))
+    ENDCALLWITH(output,
+        CALL(print)
+        CALLPARAM(output)
+        CALLPARAM(sNL)
+        ENDCALL();
+    );
+    CALL(ftos)
+    CALLPARAM(ENTFIELD(pawn, memb))
+    ENDCALLWITH(output,
+        CALL(print)
+        CALLPARAM(output)
+        CALLPARAM(sNL)
+        ENDCALL();
+    );
+    CALL(ftos)
+    CALLPARAM(ENTFIELD(pawn, VECMEM(memv, 2)))
+    ENDCALLWITH(output,
+        CALL(print)
+        CALLPARAM(output)
+        CALLPARAM(sNL)
+        ENDCALL();
+    );
+
 ENDFUNCTION(main);
 
     ir = ir_builder_new("ast_test");
     assert(ir);
 
+    /* gen fields */
+    for (i = 0; i < fields_elements; ++i) {
+        if (!ast_global_codegen(fields_data[i], ir)) {
+            assert(!"failed to generate field");
+        }
+    }
     /* gen globals */
     for (i = 0; i < globals_elements; ++i) {
         if (!ast_global_codegen(globals_data[i], ir)) {