Prechádzať zdrojové kódy

Added new closure bind method to set a custom self. Enhanced Fiber class. Unit test added.

Marco Bambini 7 rokov pred
rodič
commit
5d2de2e589

+ 61 - 0
src/runtime/gravity_core.c

@@ -431,6 +431,12 @@ inline gravity_value_t convert_value2string (gravity_vm *vm, gravity_value_t v)
                     const char *s = delegate->bridge_string(vm, instance->xdata, &len);
                     if (s) return VALUE_FROM_STRING(vm, s, len);
                 }
+            } else {
+                char buffer[512];
+                const char *identifier = (instance->objclass->identifier);
+                if (!identifier) identifier = "anonymous class";
+                snprintf(buffer, sizeof(buffer), "instance of %s (%p)", identifier, instance);
+                return VALUE_FROM_CSTRING(vm, buffer);
             }
         }
         return VALUE_FROM_ERROR(NULL);
@@ -1484,6 +1490,16 @@ static bool closure_apply (gravity_vm *vm, gravity_value_t *args, uint16_t nargs
 	RETURN_VALUE(result, rindex);
 }
 
+static bool closure_bind (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+    if (nargs != 2) RETURN_ERROR("An argument is required by the setself function.");
+    
+    gravity_closure_t *closure = VALUE_AS_CLOSURE(GET_VALUE(0));
+    gravity_value_t self_value = GET_VALUE(1);
+    closure->self_value = self_value;
+    
+    RETURN_NOVALUE();
+}
+
 // MARK: - Float Class -
 
 static bool operator_float_add (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
@@ -2405,6 +2421,12 @@ static bool fiber_run (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, ui
 	gravity_fiber_t *fiber = VALUE_AS_FIBER(GET_VALUE(0));
 	if (fiber->caller != NULL) RETURN_ERROR("Fiber has already been called.");
 
+    if (fiber->timewait > 0.0f) {
+        // check if minimum timewait is passed
+        nanotime_t elapsed = (nanotime() - fiber->lasttime) / 1000000000.0f;
+        if (elapsed < fiber->timewait) RETURN_NOVALUE();
+    }
+    
 	// remember who ran the fiber
 	fiber->caller = gravity_vm_fiber(vm);
 
@@ -2434,6 +2456,43 @@ static bool fiber_yield (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
     // get currently executed fiber
 	gravity_fiber_t *fiber = gravity_vm_fiber(vm);
 
+    // reset wait time and update last time
+    fiber->timewait = 0.0f;
+    fiber->lasttime = nanotime();
+    
+    // in no caller then this is just a NOP
+    if (fiber->caller) {
+        gravity_vm_setfiber(vm, fiber->caller);
+    
+        // unhook this fiber from the one that called it
+        fiber->caller = NULL;
+        fiber->trying = false;
+	
+        RETURN_FIBER();
+    } else {
+        RETURN_NOVALUE();
+    }
+}
+
+static bool fiber_yield_time (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+    #pragma unused(args, nargs, rindex)
+    
+    // set rindex slot to NULL in order to falsify the if closure check performed by the VM
+    gravity_vm_setslot(vm, VALUE_FROM_NULL, rindex);
+    
+    // get currently executed fiber
+    gravity_fiber_t *fiber = gravity_vm_fiber(vm);
+    
+    // if parameter is a float/int set its wait time (otherwise ignore it)
+    if (VALUE_ISA_FLOAT(GET_VALUE(1))) {
+        fiber->timewait = VALUE_AS_FLOAT(GET_VALUE(1));
+    } else if (VALUE_ISA_INT(GET_VALUE(1))) {
+        fiber->timewait = (gravity_float_t)GET_VALUE(1).n;
+    }
+    
+    // update last time
+    fiber->lasttime = nanotime();
+    
     // in no caller then this is just a NOP
     if (fiber->caller) {
         gravity_vm_setfiber(vm, fiber->caller);
@@ -2744,6 +2803,7 @@ static void gravity_core_init (void) {
 	// CLOSURE CLASS
 	gravity_class_bind(gravity_class_closure, "disassemble", NEW_CLOSURE_VALUE(closure_disassemble));
 	gravity_class_bind(gravity_class_closure, "apply", NEW_CLOSURE_VALUE(closure_apply));
+    gravity_class_bind(gravity_class_closure, "bind", NEW_CLOSURE_VALUE(closure_bind));
 
 	// LIST CLASS
     gravity_closure_t *closure = computed_property_create(NULL, NEW_FUNCTION(list_count), NULL);
@@ -2892,6 +2952,7 @@ static void gravity_core_init (void) {
 	gravity_class_bind(gravity_class_fiber, "call", NEW_CLOSURE_VALUE(fiber_exec));
 	gravity_class_bind(gravity_class_fiber, "try", NEW_CLOSURE_VALUE(fiber_try));
 	gravity_class_bind(fiber_meta, "yield", NEW_CLOSURE_VALUE(fiber_yield));
+    gravity_class_bind(fiber_meta, "yieldWaitTime", NEW_CLOSURE_VALUE(fiber_yield_time));
 	gravity_class_bind(gravity_class_fiber, "status", NEW_CLOSURE_VALUE(fiber_status));
 	gravity_class_bind(fiber_meta, "abort", NEW_CLOSURE_VALUE(fiber_abort));
 

+ 3 - 0
src/runtime/gravity_vm.c

@@ -1085,6 +1085,9 @@ static bool gravity_vm_exec (gravity_vm *vm) {
 					++r3;
 				}
 
+                // check for custom self
+                if (VALUE_ISA_VALID(closure->self_value)) SETVALUE(rwin, closure->self_value);
+				
 				DEBUG_STACK();
 
                 // save currently executing fiber (that can change!)

+ 7 - 2
src/shared/gravity_value.h

@@ -66,8 +66,8 @@
 extern "C" {
 #endif
 
-#define GRAVITY_VERSION						"0.4.8"     // git tag 0.4.8
-#define GRAVITY_VERSION_NUMBER				0x000408    // git push --tags
+#define GRAVITY_VERSION						"0.4.9"     // git tag 0.4.9
+#define GRAVITY_VERSION_NUMBER				0x000409    // git push --tags
 #define GRAVITY_BUILD_DATE					__DATE__
 
 #ifndef GRAVITY_ENABLE_DOUBLE
@@ -292,6 +292,8 @@ typedef struct {
 	gravity_function_t		*f;					// function prototype
     gravity_object_t        *context;           // context where the closure has been created
 	gravity_upvalue_t		**upvalue;			// upvalue array
+    
+    gravity_value_t         self_value;        // custom self value set by the user
 } gravity_closure_t;
 
 typedef struct {
@@ -338,6 +340,9 @@ typedef struct fiber_s {
 	bool					trying;				// set when the try flag is set by the user
 	struct fiber_s			*caller;			// optional caller fiber
 	gravity_value_t			result;				// end result of the fiber
+    
+    nanotime_t              lasttime;           // last time Fiber has been called
+    gravity_float_t         timewait;           // used in yieldTime
 } gravity_fiber_t;
 
 typedef struct gravity_class_s {

+ 21 - 0
test/unittest/closure_bind.gravity

@@ -0,0 +1,21 @@
+#unittest {
+	name: "Closure bind.";
+	result: 20;
+};
+
+class foo {
+    var a = 10;
+    
+    func f1() {
+        return a;
+    }
+}
+
+func main() {
+    var c = foo();
+    
+    var f1 = c.f1;
+    f1.bind(c);
+    
+    return f1() + c.f1();
+}