investigating the sync issue...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2023-02-05 23:02:30 +03:00
parent 0b133aeeb8
commit 4991dd1bd0

View File

@ -446,8 +446,37 @@ module.BaseParser = {
// old code:
// await p.pwiki.parse('<slot moo/>!!! <slot moo>moo</slot>')
// -> 'moo!!! '
// ...does not seem to affect named macros...
_expand: function(page, ast, state={}){
// ...this affects @var(..) and @slot(..) and does not affect @macro(..)
// The problem is that .callMacro(..) is for some execution paths is
// called sync and in some paths after the current execution frame is
// done, i.e. async...
// ...turns out that the problem is in the inconsistent await behavior,
// in var macro, as an example, there are two paths: the assign and
// the get, the assign calls .parse(..) and awaits for the result
// while the get path is "sync", this results in the first exec path
// getting pushed to the next execution frame while the second is run
// in sync with the caller, here is a simplified demo:
// console.log(1)
// // note that we are NOTE await'ing for the function here...
// (async function f(){
// console.log(2)})()
// console.log(3)
// -> prints 1, 2, 3
// and:
// console.log(1)
// (async function f(){
// // note the await -- this is the only difference...
// console.log(await 2)})()
// console.log(3)
// -> prints 1, 3, 2
// this could both be a bug or a feature depending on how you look
// at it, but it makes promise sequencing very unpredictable...
// ...another problem here is that in the var macro, simply adding
// an await of something does not fix the issue, we need to await
// for something significant -- await this.parse('') works, while
// await vars[name] does not -- to the contrary of the above example...
// XXX EXPERIMENTAL...
expand: function(page, ast, state={}){
var that = this
ast = ast == null ?
Promise.awaitOrRun(
@ -460,12 +489,8 @@ module.BaseParser = {
ast
: ast.iter()
// XXX this must execute sequentially for things that depend on
// NOTE this must execute sequentially for things that depend on
// lexical scope not to get lost in the mess...
// ...or it's a question of if we can maintain "slices" of
// state per macro call that is both containing all the state
// from previous macros, and is not affected by the changes
// done by next macros (unless needed)...
return Promise.seqiter(ast,
function(value){
// text block...
@ -478,6 +503,9 @@ module.BaseParser = {
return {...value, skip: true} }
// macro call...
return Promise.awaitOrRun(
// XXX due to the unpredictable behavior of await we
// need to call this only AFTER the previous call
// is done...
that.callMacro(page, name, args, body, state),
function(res){
res = res ?? ''
@ -508,7 +536,7 @@ module.BaseParser = {
.replace(/=/g, '&equals;')
+'")') })
.sync() },
//*/
/*/
expand: async function*(page, ast, state={}){
try{
ast = ast == null ?