From 3558a1994aaab9bd809929e8979d1830f7601f8a Mon Sep 17 00:00:00 2001 From: Thakee Nathees Date: Sun, 6 Jun 2021 19:48:47 +0530 Subject: [PATCH] fiber documentation written --- .../Getting-Started/learn-in-15-minutes.md | 18 +++- docs/pages/Language-API/fibers.md | 86 ++++++++++++++++++- src/core.c | 12 +-- 3 files changed, 105 insertions(+), 11 deletions(-) diff --git a/docs/pages/Getting-Started/learn-in-15-minutes.md b/docs/pages/Getting-Started/learn-in-15-minutes.md index 50bb7d7..0dedc7e 100644 --- a/docs/pages/Getting-Started/learn-in-15-minutes.md +++ b/docs/pages/Getting-Started/learn-in-15-minutes.md @@ -23,7 +23,6 @@ true; false # Booleans. [42, 'foo', null] # Lists. { 'Key':'value' } # Maps. func(x) return x*x end # Lambda/literal functions. -import lang # Module (imported scripts). # Control flow. # ------------- @@ -71,9 +70,20 @@ end # Concanative call operator '->' -str_lower(str_strip('FOO ')) # This can be written as below -'FOO ' -> str_strip -> str_lower +str_lower(str_strip('Foo ')) # This can be written as below +'Foo ' -> str_strip -> str_lower 'foo' -> print # similer as print('foo') -``` \ No newline at end of file +# Fibers & Coroutine +#------------------- + +def fn(p1, p2) + print(yield(42)) # Prints 3.14 +end + +fb = fiber_new(fn) +val = fiber_run(fb, 1, 2) +print(val) ## Prints 42 +fiber_resume(fb, 3.14) +``` diff --git a/docs/pages/Language-API/fibers.md b/docs/pages/Language-API/fibers.md index a669efe..865fd09 100644 --- a/docs/pages/Language-API/fibers.md +++ b/docs/pages/Language-API/fibers.md @@ -1,4 +1,88 @@ # %% Fibers %% -TODO +Pocketlang support coroutines via [fibers](https://en.wikipedia.org/wiki/Fiber_(computer_science)) +(light weight threads with cooperative multitask). A fiber object is a wrapper +around a function, contains the execution state (simply the stack and the +instruction pointer) for that function, which can be run and once yielded +resumed. + +```ruby +def fn(h, w) + print(h, w) +end + +fb = fiber_new(fn) # Create a fiber. +fiber_run(fb, 'hello', 'world') # Run the fiber. +``` + +## %% Yielding %% + +When a function is yielded, it's state will be stored in the fiber it's +belongs to and will return from the function, to parent fiber it's running +from (not the caller of the function). And you can pass values between +fibers when they yield. + +```ruby +def fn() + print('running') + yield() + print('resumed') +end + +fb = fiber_new(fn) +fiber_run(fb) # Prints 'running'. +print('before resumed') +fiber_resume(fb) # Prints 'resumed'. +``` + +Yield from the fiber with a value. + +```ruby +def fn() + print('running') + yield(42) # Return 42. + print('resumed') +end + +fb = fiber_new(fn) +val = fiber_run(fb) # Prints 'running'. +print(val) # Prints 42. +fiber_resume(fb) # Prints 'resumed'. +``` + +Resume the fiber with a value. + +```ruby +def fn() + print('running') + val = yield() # Resumed value. + print(val) # Prints 42. + print('resumed') +end + +fb = fiber_new(fn) +val = fiber_run(fb) # Prints 'running'. +fiber_resume(fb, 42) # Resume with 42, Prints 'resumed'. +``` + +Once a fiber is done execution, trying to resume it will cause a runtime +error. To check if the fiber is finished it's execution use the function +`fiber_is_done` and use the function `fiber_get_func` to get it's function, +which could be used to create a new fiber to "re-start" the fiber. + +```ruby +fiber_run(fb = fiber_new( +func() + for i in 0..5 do + yield(i) + end +end)) + +while not fiber_is_done(fb) + fiber_resume(fb) +end + +# Get the function from the fiber. +fn = fiber_get_func(fb) +``` diff --git a/src/core.c b/src/core.c index 2e1f8cf..e59e444 100644 --- a/src/core.c +++ b/src/core.c @@ -195,20 +195,20 @@ void pkReturnValue(PKVM* vm, PkVar value) { // Check if a numeric value bool/number and set [value]. static inline bool isNumeric(Var var, double* value) { - if (IS_BOOL(var)) { - *value = AS_BOOL(var); - return true; - } if (IS_NUM(var)) { *value = AS_NUM(var); return true; } + if (IS_BOOL(var)) { + *value = AS_BOOL(var); + return true; + } return false; } // Check if [var] is bool/number. If not set error and return false. static inline bool validateNumeric(PKVM* vm, Var var, double* value, - const char* name) { + const char* name) { if (isNumeric(var, value)) return true; vm->fiber->error = stringFormat(vm, "$ must be a numeric value.", name); return false; @@ -216,7 +216,7 @@ static inline bool validateNumeric(PKVM* vm, Var var, double* value, // Check if [var] is integer. If not set error and return false. static inline bool validateInteger(PKVM* vm, Var var, int32_t* value, - const char* name) { + const char* name) { double number; if (isNumeric(var, &number)) { double truncated = floor(number);