Browse Source

Added preliminary support for Struct. Fixed a bind method. Unit test added.

Marco Bambini 6 years ago
parent
commit
122fdaa5ac

+ 9 - 0
src/compiler/gravity_codegen.c

@@ -1063,6 +1063,8 @@ static void visit_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node)
                 uint32_t reg = ircode_register_pop(code);
                 uint32_t reg = ircode_register_pop(code);
                 if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid var expression.");
                 if (reg == REGISTER_ERROR) report_error(self, (gnode_t *)node, "Invalid var expression.");
 				ircode_add(code, MOVE, p->index, reg, 0, LINE_NUMBER(node));
 				ircode_add(code, MOVE, p->index, reg, 0, LINE_NUMBER(node));
+                // Checkpoint added to support STRUCT
+                ircode_add_check(code);
             } else {
             } else {
                 // no default assignment expression found so initialize to NULL
                 // no default assignment expression found so initialize to NULL
 				ircode_add(code, LOADK, p->index, CPOOL_VALUE_NULL, 0, LINE_NUMBER(node));
 				ircode_add(code, LOADK, p->index, CPOOL_VALUE_NULL, 0, LINE_NUMBER(node));
@@ -1274,6 +1276,9 @@ static void visit_binary_expr (gvisitor_t *self, gnode_binary_expr_t *node) {
 
 
         CODEGEN_COUNT_REGISTERS(n2);
         CODEGEN_COUNT_REGISTERS(n2);
         CODEGEN_ASSERT_REGISTERS(n1, n2, 0);
         CODEGEN_ASSERT_REGISTERS(n1, n2, 0);
+        
+        // Checkpoint added to support STRUCT
+        ircode_add_check(code);
         return;
         return;
     }
     }
 
 
@@ -1453,6 +1458,10 @@ static void visit_postfix_expr (gvisitor_t *self, gnode_postfix_expr_t *node) {
                     report_error(self, (gnode_t *)arg, "Invalid register computation in call expression.");
                     report_error(self, (gnode_t *)arg, "Invalid register computation in call expression.");
                     return;
                     return;
                 }
                 }
+                
+                // a checkpoint should be added after each nreg computation in order to support STRUCT
+                // I'll skip this overhead in this version because it should be a type based decision
+                // ircode_add_check(code, nreg);
                 marray_push(uint32_t, args, nreg);
                 marray_push(uint32_t, args, nreg);
             }
             }
 
 

+ 9 - 1
src/compiler/gravity_ircode.c

@@ -247,7 +247,7 @@ uint8_t opcode_numop (opcode_t op) {
         case RANGENEW: return 3;
         case RANGENEW: return 3;
         case CLOSURE: return 2;
         case CLOSURE: return 2;
         case CLOSE: return 1;
         case CLOSE: return 1;
-        case RESERVED1:
+        case CHECK: return 1;
         case RESERVED2:
         case RESERVED2:
         case RESERVED3:
         case RESERVED3:
         case RESERVED4:
         case RESERVED4:
@@ -424,6 +424,14 @@ void ircode_add_skip (ircode_t *code, uint32_t lineno) {
     marray_push(inst_t*, *code->list, inst);
     marray_push(inst_t*, *code->list, inst);
 }
 }
 
 
+void ircode_add_check (ircode_t *code) {
+    inst_t *inst = marray_last(*code->list);
+    if ((inst) && (inst->op == MOVE)) {
+        inst_t *newinst = inst_new(CHECK, inst->p1, 0, 0, NO_TAG, 0, 0, inst->lineno);
+        marray_push(inst_t*, *code->list, newinst);
+    }    
+}
+
 // MARK: - Context based functions -
 // MARK: - Context based functions -
 
 
 #if 0
 #if 0

+ 1 - 0
src/compiler/gravity_ircode.h

@@ -90,6 +90,7 @@ void		ircode_add_int (ircode_t *code, int64_t n, uint32_t lineno);
 void		ircode_add_constant (ircode_t *code, uint32_t index, uint32_t lineno);
 void		ircode_add_constant (ircode_t *code, uint32_t index, uint32_t lineno);
 void		ircode_add_skip (ircode_t *code, uint32_t lineno);
 void		ircode_add_skip (ircode_t *code, uint32_t lineno);
 void        ircode_set_index (uint32_t index, ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3);
 void        ircode_set_index (uint32_t index, ircode_t *code, opcode_t op, uint32_t p1, uint32_t p2, uint32_t p3);
+void        ircode_add_check (ircode_t *code);
 
 
 // IMPORTANT NOTE
 // IMPORTANT NOTE
 //
 //

+ 4 - 1
src/compiler/gravity_optimizer.c

@@ -192,7 +192,10 @@ static void finalize_function (gravity_function_t *f, bool add_debug) {
                 OPCODE_SET_ONE8bit_ONE18bit(op, inst->op, inst->p1, inst->p2);
                 OPCODE_SET_ONE8bit_ONE18bit(op, inst->op, inst->p1, inst->p2);
                 break;
                 break;
 
 
-            case RESERVED1:
+            case CHECK:
+                OPCODE_SET_ONE8bit_ONE18bit(op, inst->op, inst->p1, inst->p2);
+                break;
+                
             case RESERVED2:
             case RESERVED2:
             case RESERVED3:
             case RESERVED3:
             case RESERVED4:
             case RESERVED4:

+ 23 - 2
src/runtime/gravity_core.c

@@ -768,7 +768,13 @@ static bool object_store (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
         uint32_t nivar = c->nivars;
         uint32_t nivar = c->nivars;
         uint32_t nindex = (uint32_t)key.n;
         uint32_t nindex = (uint32_t)key.n;
         if (nindex >= nivar) RETURN_ERROR("Out of bounds ivar index in store operation (1).");
         if (nindex >= nivar) RETURN_ERROR("Out of bounds ivar index in store operation (1).");
-
+        
+        // check for struct
+        if (VALUE_ISA_INSTANCE(value) && (gravity_instance_isstruct(VALUE_AS_INSTANCE(value)))) {
+            gravity_instance_t *instance_copy = gravity_instance_clone(vm, VALUE_AS_INSTANCE(value));
+            value = VALUE_FROM_OBJECT(instance_copy);
+        }
+        
         if (instance) instance->ivars[nindex] = value;
         if (instance) instance->ivars[nindex] = value;
         else c->ivars[nindex] = value;
         else c->ivars[nindex] = value;
         RETURN_NOVALUE();
         RETURN_NOVALUE();
@@ -803,7 +809,13 @@ static bool object_store (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
                 uint32_t nivar = c->nivars;
                 uint32_t nivar = c->nivars;
                 uint32_t nindex = closure->f->index;
                 uint32_t nindex = closure->f->index;
                 if (nindex >= nivar) RETURN_ERROR("Out of bounds ivar index in store operation (2).");
                 if (nindex >= nivar) RETURN_ERROR("Out of bounds ivar index in store operation (2).");
-
+                
+                // check for struct
+                if (VALUE_ISA_INSTANCE(value) && (gravity_instance_isstruct(VALUE_AS_INSTANCE(value)))) {
+                    gravity_instance_t *instance_copy = gravity_instance_clone(vm, VALUE_AS_INSTANCE(value));
+                    value = VALUE_FROM_OBJECT(instance_copy);
+                }
+                
                 if (instance) instance->ivars[nindex] = value;
                 if (instance) instance->ivars[nindex] = value;
                 else c->ivars[nindex] = value;
                 else c->ivars[nindex] = value;
 
 
@@ -873,6 +885,9 @@ static bool object_bind (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
         // store anonymous class (and its meta) into VM context
         // store anonymous class (and its meta) into VM context
         gravity_vm_setvalue(vm, name, VALUE_FROM_OBJECT(anon));
         gravity_vm_setvalue(vm, name, VALUE_FROM_OBJECT(anon));
     }
     }
+    
+    // set closure context (only if class or instance)
+    // VALUE_AS_CLOSURE(GET_VALUE(2))->context = object;
 
 
     // add closure to anonymous class
     // add closure to anonymous class
     gravity_class_bind(c, key->s, GET_VALUE(2));
     gravity_class_bind(c, key->s, GET_VALUE(2));
@@ -888,6 +903,12 @@ static bool object_unbind (gravity_vm *vm, gravity_value_t *args, uint16_t nargs
 
 
     // remove key/value from hash table
     // remove key/value from hash table
     gravity_class_t *c = gravity_value_getclass(GET_VALUE(0));
     gravity_class_t *c = gravity_value_getclass(GET_VALUE(0));
+    gravity_object_t *obj = (gravity_object_t *)gravity_class_lookup(c, GET_VALUE(1));
+    
+    // clear closure context
+    if (obj && OBJECT_ISA_CLOSURE(obj)) ((gravity_closure_t *)obj)->context = NULL;
+    
+    // remove key from class hash table
     gravity_hash_remove(c->htable, GET_VALUE(1));
     gravity_hash_remove(c->htable, GET_VALUE(1));
 
 
     RETURN_NOVALUE();
     RETURN_NOVALUE();

+ 18 - 4
src/runtime/gravity_vm.c

@@ -1437,8 +1437,9 @@ static bool gravity_vm_exec (gravity_vm *vm) {
                 // create closure (outside GC)
                 // create closure (outside GC)
                 gravity_closure_t *closure = gravity_closure_new(vm, f);
                 gravity_closure_t *closure = gravity_closure_new(vm, f);
 
 
-                // save current context (if any)
-                closure->context = gravity_value_isobject(STACK_GET(0)) ? VALUE_AS_OBJECT(STACK_GET(0)) : NULL;
+                // save current context (only if class or instance)
+                if ((VALUE_ISA_CLASS(STACK_GET(0))) || (VALUE_ISA_INSTANCE(STACK_GET(0))))
+                    closure->context = VALUE_AS_OBJECT(STACK_GET(0)) ;
                 
                 
                 // loop for each upvalue setup instruction
                 // loop for each upvalue setup instruction
                 for (uint16_t i=0; i<f->nupvalues; ++i) {
                 for (uint16_t i=0; i<f->nupvalues; ++i) {
@@ -1466,9 +1467,22 @@ static bool gravity_vm_exec (gravity_vm *vm) {
                 gravity_close_upvalues(fiber, &stackstart[r1]);
                 gravity_close_upvalues(fiber, &stackstart[r1]);
                 DISPATCH();
                 DISPATCH();
             }
             }
-
+            
+            // MARK: CHECK
+            CASE_CODE(CHECK): {
+                OPCODE_GET_ONE8bit(inst, const uint32_t r1);
+                DEBUG_VM("CHECK %d", r1);
+                
+                gravity_value_t value = STACK_GET(r1);
+                if (VALUE_ISA_INSTANCE(value) && (gravity_instance_isstruct(VALUE_AS_INSTANCE(value)))) {
+                    gravity_instance_t *instance = gravity_instance_clone(vm, VALUE_AS_INSTANCE(value));
+                    SETVALUE(r1, VALUE_FROM_OBJECT(instance));
+                }
+                
+                DISPATCH();
+            }
+            
             // MARK: - RESERVED
             // MARK: - RESERVED
-            CASE_CODE(RESERVED1):
             CASE_CODE(RESERVED2):
             CASE_CODE(RESERVED2):
             CASE_CODE(RESERVED3):
             CASE_CODE(RESERVED3):
             CASE_CODE(RESERVED4):
             CASE_CODE(RESERVED4):

+ 1 - 1
src/runtime/gravity_vmmacros.h

@@ -133,7 +133,7 @@
                                     &&MATCH,        &&NEG,          &&NOT,          &&LSHIFT,       \
                                     &&MATCH,        &&NEG,          &&NOT,          &&LSHIFT,       \
                                     &&RSHIFT,       &&BAND,         &&BOR,          &&BXOR,         \
                                     &&RSHIFT,       &&BAND,         &&BOR,          &&BXOR,         \
                                     &&BNOT,         &&MAPNEW,       &&LISTNEW,      &&RANGENEW,     \
                                     &&BNOT,         &&MAPNEW,       &&LISTNEW,      &&RANGENEW,     \
-                                    &&SETLIST,      &&CLOSURE,      &&CLOSE,        &&RESERVED1,    \
+                                    &&SETLIST,      &&CLOSURE,      &&CLOSE,        &&CHECK,        \
                                     &&RESERVED2,    &&RESERVED3,    &&RESERVED4,    &&RESERVED5,    \
                                     &&RESERVED2,    &&RESERVED3,    &&RESERVED4,    &&RESERVED5,    \
                                     &&RESERVED6                                                        };
                                     &&RESERVED6                                                        };
 #define INTERPRET_LOOP              DISPATCH();
 #define INTERPRET_LOOP              DISPATCH();

+ 1 - 1
src/shared/gravity_opcodes.h

@@ -129,7 +129,7 @@ typedef enum {
             CLOSE,          //  A               //  close all upvalues from R(A)
             CLOSE,          //  A               //  close all upvalues from R(A)
 
 
                                                 //  *** UNUSED (6) ***
                                                 //  *** UNUSED (6) ***
-            RESERVED1,      //                  //  reserved for future use
+            CHECK,          //  A               //  checkpoint for structs                  R(A) = R(A).clone (if A is a struct)
             RESERVED2,      //                  //  reserved for future use
             RESERVED2,      //                  //  reserved for future use
             RESERVED3,      //                  //  reserved for future use
             RESERVED3,      //                  //  reserved for future use
             RESERVED4,      //                  //  reserved for future use
             RESERVED4,      //                  //  reserved for future use

+ 4 - 0
src/shared/gravity_value.c

@@ -1754,6 +1754,10 @@ void gravity_instance_serialize (gravity_instance_t *instance, json_t *json) {
     json_end_object(json);
     json_end_object(json);
 }
 }
 
 
+bool gravity_instance_isstruct (gravity_instance_t *i) {
+    return i->objclass->is_struct;
+}
+
 // MARK: -
 // MARK: -
 static bool hash_value_compare_cb (gravity_value_t v1, gravity_value_t v2, void *data) {
 static bool hash_value_compare_cb (gravity_value_t v1, gravity_value_t v2, void *data) {
     #pragma unused (data)
     #pragma unused (data)

+ 3 - 2
src/shared/gravity_value.h

@@ -66,8 +66,8 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-#define GRAVITY_VERSION						"0.7.7"     // git tag 0.7.7
-#define GRAVITY_VERSION_NUMBER				0x000707    // git push --tags
+#define GRAVITY_VERSION						"0.7.8"     // git tag 0.7.8
+#define GRAVITY_VERSION_NUMBER				0x000708    // git push --tags
 #define GRAVITY_BUILD_DATE                  __DATE__
 #define GRAVITY_BUILD_DATE                  __DATE__
 
 
 #ifndef GRAVITY_ENABLE_DOUBLE
 #ifndef GRAVITY_ENABLE_DOUBLE
@@ -501,6 +501,7 @@ GRAVITY_API gravity_closure_t   *gravity_instance_lookup_event (gravity_instance
 GRAVITY_API void                gravity_instance_blacken (gravity_vm *vm, gravity_instance_t *i);
 GRAVITY_API void                gravity_instance_blacken (gravity_vm *vm, gravity_instance_t *i);
 GRAVITY_API uint32_t            gravity_instance_size (gravity_vm *vm, gravity_instance_t *i);
 GRAVITY_API uint32_t            gravity_instance_size (gravity_vm *vm, gravity_instance_t *i);
 GRAVITY_API void                gravity_instance_serialize (gravity_instance_t *i, json_t *json);
 GRAVITY_API void                gravity_instance_serialize (gravity_instance_t *i, json_t *json);
+GRAVITY_API bool                gravity_instance_isstruct (gravity_instance_t *i);
 
 
 // MARK: - VALUE -
 // MARK: - VALUE -
 GRAVITY_API bool                gravity_value_equals (gravity_value_t v1, gravity_value_t v2);
 GRAVITY_API bool                gravity_value_equals (gravity_value_t v1, gravity_value_t v2);

+ 8 - 2
src/utils/gravity_debug.c

@@ -32,7 +32,7 @@ const char *opcode_name (opcode_t op) {
         "MUL", "REM", "AND", "OR", "LT", "GT", "EQ", "LEQ", "GEQ", "NEQ",
         "MUL", "REM", "AND", "OR", "LT", "GT", "EQ", "LEQ", "GEQ", "NEQ",
         "EQQ", "NEQQ", "IS", "MATCH", "NEG", "NOT", "LSHIFT", "RSHIFT", "BAND",
         "EQQ", "NEQQ", "IS", "MATCH", "NEG", "NOT", "LSHIFT", "RSHIFT", "BAND",
         "BOR", "BXOR", "BNOT", "MAPNEW", "LISTNEW", "RANGENEW", "SETLIST",
         "BOR", "BXOR", "BNOT", "MAPNEW", "LISTNEW", "RANGENEW", "SETLIST",
-        "CLOSURE", "CLOSE", "RESERVED1", "RESERVED2", "RESERVED3", "RESERVED4",
+        "CLOSURE", "CLOSE", "CHECK", "RESERVED2", "RESERVED3", "RESERVED4",
         "RESERVED5", "RESERVED6"};
         "RESERVED5", "RESERVED6"};
     return optable[op];
     return optable[op];
 }
 }
@@ -228,7 +228,13 @@ const char *gravity_disassemble (gravity_vm *vm, gravity_function_t *f, const ch
                 break;
                 break;
             }
             }
                 
                 
-            case RESERVED1:
+            case CHECK: {
+                OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t r1, const uint32_t r2);
+                #pragma unused(r2)
+                DUMP_VM(buffer, bindex, "%s %d", opcode_name(op), r1);
+                break;
+            }
+                
             case RESERVED2:
             case RESERVED2:
             case RESERVED3:
             case RESERVED3:
             case RESERVED4:
             case RESERVED4:

+ 20 - 0
test/unittest/bind_func.gravity

@@ -0,0 +1,20 @@
+#unittest {
+	name: "Bind function to an existing class.";
+	error: NONE;
+	result: 100;
+};
+
+class Foo {
+    var x = 100;
+
+}
+
+func test() {
+    return self.x;
+}
+
+func main() {
+	var foo = Foo();
+    foo.bind("test", test);
+    return foo.test();
+}

+ 46 - 0
test/unittest/struct.gravity

@@ -0,0 +1,46 @@
+#unittest {
+	name: "Struct test.";
+	error: NONE;
+	result: 1070;
+};
+
+class P1 {
+    var x;
+    var y;
+    
+    func init (a, b) {
+        x = a;
+        y = b;
+    }
+    
+    func sum() {
+        return x + y;
+    }
+}
+
+struct P2 {
+    var x = 0;
+    var y = 0;
+    
+    func init (a, b) {
+        x = a;
+        y = b;
+    }
+    
+    func sum() {
+        return x + y;
+    }
+}
+
+func main() {
+    var p1 = P1(10, 20);
+    var p2 = P2(20, 30);
+    
+    var obj1 = p1;
+    obj1.x = 1000;
+    
+    var obj2 = p2;
+    obj2.x = 1000;
+    
+    return p1.sum() + p2.sum();
+}