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,55 +489,54 @@ 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...
if(typeof(value) == 'string'){ if(typeof(value) == 'string'){
return value } return value }
// macro... // macro...
var {name, args, body} = value var {name, args, body} = value
// nested macro -- skip... // nested macro -- skip...
if(typeof(page.macros[name]) != 'function'){ if(typeof(page.macros[name]) != 'function'){
return {...value, skip: true} } return {...value, skip: true} }
// macro call... // macro call...
return Promise.awaitOrRun( return Promise.awaitOrRun(
that.callMacro(page, name, args, body, state), // XXX due to the unpredictable behavior of await we
function(res){ // need to call this only AFTER the previous call
res = res ?? '' // is done...
// result... that.callMacro(page, name, args, body, state),
if(res instanceof Array function(res){
|| page.macros[name] instanceof types.Generator){ res = res ?? ''
return res // result...
} else { if(res instanceof Array
return [res] } }) }, || page.macros[name] instanceof types.Generator){
function(err){ return res
console.error(err) } else {
return page.parse( return [res] } }) },
// XXX add line number and page path... function(err){
'@include("./ParseError' console.error(err)
+':path=' return page.parse(
// XXX use pwpath.encodeElem(..) ??? // XXX add line number and page path...
+ page.path '@include("./ParseError'
+':msg=' +':path='
+ err.message // XXX use pwpath.encodeElem(..) ???
// quote html stuff... + page.path
.replace(/&/g, '&amp;') +':msg='
.replace(/</g, '&lt;') + err.message
.replace(/>/g, '&gt;') // quote html stuff...
// quote argument syntax... .replace(/&/g, '&amp;')
.replace(/["']/g, function(c){ .replace(/</g, '&lt;')
return '%'+ c.charCodeAt().toString(16) }) .replace(/>/g, '&gt;')
.replace(/:/g, '&colon;') // quote argument syntax...
.replace(/=/g, '&equals;') .replace(/["']/g, function(c){
+'")') }) return '%'+ c.charCodeAt().toString(16) })
.sync() }, .replace(/:/g, '&colon;')
//*/ .replace(/=/g, '&equals;')
+'")') })
.sync() },
/*/
expand: async function*(page, ast, state={}){ expand: async function*(page, ast, state={}){
try{ try{
ast = ast == null ? ast = ast == null ?