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: // old code:
// await p.pwiki.parse('<slot moo/>!!! <slot moo>moo</slot>') // await p.pwiki.parse('<slot moo/>!!! <slot moo>moo</slot>')
// -> 'moo!!! ' // -> 'moo!!! '
// ...does not seem to affect named macros... // ...this affects @var(..) and @slot(..) and does not affect @macro(..)
_expand: function(page, ast, state={}){ // 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 var that = this
ast = ast == null ? ast = ast == null ?
Promise.awaitOrRun( Promise.awaitOrRun(
@ -460,12 +489,8 @@ module.BaseParser = {
ast ast
: ast.iter() : 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... // 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, return Promise.seqiter(ast,
function(value){ function(value){
// text block... // text block...
@ -478,6 +503,9 @@ module.BaseParser = {
return {...value, skip: true} } return {...value, skip: true} }
// macro call... // macro call...
return Promise.awaitOrRun( 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), that.callMacro(page, name, args, body, state),
function(res){ function(res){
res = res ?? '' res = res ?? ''
@ -508,7 +536,7 @@ module.BaseParser = {
.replace(/=/g, '&equals;') .replace(/=/g, '&equals;')
+'")') }) +'")') })
.sync() }, .sync() },
//*/ /*/
expand: async function*(page, ast, state={}){ expand: async function*(page, ast, state={}){
try{ try{
ast = ast == null ? ast = ast == null ?