mirror of
https://github.com/flynx/pWiki.git
synced 2026-10-03 04:41:39 +00:00
Compare commits
3 Commits
327693a768
...
64c7a63930
| Author | SHA1 | Date | |
|---|---|---|---|
| 64c7a63930 | |||
| 811b0a433d | |||
| 74b6c19753 |
@ -18,10 +18,15 @@ var pwpath = require('./path')
|
|||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// Parser...
|
// Parser/Runner...
|
||||||
|
|
||||||
// XXX TODO:
|
// XXX TODO:
|
||||||
// callbacks on elements resolving...
|
// - callbacks on elements resolving...
|
||||||
|
// - option/way to wrap macro output -- callback??
|
||||||
|
// - naming:
|
||||||
|
// parser -> macro
|
||||||
|
//
|
||||||
|
//
|
||||||
// XXX ASAP move the macros here...
|
// XXX ASAP move the macros here...
|
||||||
// XXX BUG?: <macro src=/moo/> is not parsed correctly...
|
// XXX BUG?: <macro src=/moo/> is not parsed correctly...
|
||||||
// XXX need to correctly handle nested and escaped quotes...
|
// XXX need to correctly handle nested and escaped quotes...
|
||||||
@ -30,8 +35,8 @@ var pwpath = require('./path')
|
|||||||
|
|
||||||
// XXX RENAME...
|
// XXX RENAME...
|
||||||
// ...this handles the syntax and execution...
|
// ...this handles the syntax and execution...
|
||||||
var BaseParser =
|
var BaseMacros =
|
||||||
module.BaseParser = {
|
module.BaseMacros = {
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
// Passive parsing...
|
// Passive parsing...
|
||||||
@ -280,7 +285,8 @@ module.BaseParser = {
|
|||||||
return f in (that.filters ?? {})})
|
return f in (that.filters ?? {})})
|
||||||
var handle = function(str){
|
var handle = function(str){
|
||||||
// skip non-basic data...
|
// skip non-basic data...
|
||||||
if(typeof(str) == 'object'
|
if(str == null
|
||||||
|
|| typeof(str) == 'object'
|
||||||
|| typeof(str) == 'function'){
|
|| typeof(str) == 'function'){
|
||||||
return str }
|
return str }
|
||||||
return filters
|
return filters
|
||||||
@ -749,6 +755,7 @@ module.BaseParser = {
|
|||||||
// <ast> ::= [ <item>, ... ]
|
// <ast> ::= [ <item>, ... ]
|
||||||
// <item> ::=
|
// <item> ::=
|
||||||
// <basic-value>
|
// <basic-value>
|
||||||
|
// | Promise(<value>)
|
||||||
// | <elem>
|
// | <elem>
|
||||||
//
|
//
|
||||||
// <elem> is returned if its value is not resolved yet.
|
// <elem> is returned if its value is not resolved yet.
|
||||||
@ -768,7 +775,7 @@ module.BaseParser = {
|
|||||||
var unresolved = []
|
var unresolved = []
|
||||||
|
|
||||||
// merge resolved elements into the last item of elems...
|
// merge resolved elements into the last item of elems...
|
||||||
var elems = []
|
var elems = []
|
||||||
for(var elem of ast){
|
for(var elem of ast){
|
||||||
// nesting...
|
// nesting...
|
||||||
while(elem && elem.value){
|
while(elem && elem.value){
|
||||||
@ -776,18 +783,15 @@ module.BaseParser = {
|
|||||||
if(typeof(elem.value) == 'function'){
|
if(typeof(elem.value) == 'function'){
|
||||||
let e = elem
|
let e = elem
|
||||||
let func = e.value
|
let func = e.value
|
||||||
Promise.awaitOrRun(
|
elem = Promise.awaitOrRun(
|
||||||
// if not everything is resolved, delay the stage II
|
// if not everything is resolved, delay the stage II
|
||||||
// callbacks till .wait is done...
|
// callbacks till .wait is done...
|
||||||
// NOTE: this depends on that JS is single thread
|
// NOTE: this depends on that JS is single thread
|
||||||
// and we can't have state.wait resolve in
|
// and we can't have state.wait resolve in
|
||||||
// the middle of this loop.
|
// the middle of this loop.
|
||||||
// NOTE: waiting promises resolving is also done in
|
|
||||||
// FIFO orderm thus maintaining order of execution
|
|
||||||
state.wait,
|
state.wait,
|
||||||
function(){
|
function(){
|
||||||
return elem = e.value =
|
return func(state) })
|
||||||
func(state) })
|
|
||||||
break }
|
break }
|
||||||
elem = elem.value }
|
elem = elem.value }
|
||||||
if(elem == null){
|
if(elem == null){
|
||||||
@ -846,13 +850,8 @@ module.BaseParser = {
|
|||||||
// - apply global filters
|
// - apply global filters
|
||||||
// - apply stage III post handlers
|
// - apply stage III post handlers
|
||||||
//
|
//
|
||||||
//
|
// XXX do we report recursion errors here???
|
||||||
// XXX BUG: this seems to always return a promise...
|
|
||||||
// XXX RECURSION might be a good idea to limit recursion/nesting depth
|
|
||||||
// of inner resolve(..)...
|
|
||||||
// XXX RENAME...
|
|
||||||
finalize: function(page, ast, state={}, nested_handlers={}, wait='wait'){
|
finalize: function(page, ast, state={}, nested_handlers={}, wait='wait'){
|
||||||
//finalize: function(page, ast, state={}, nested_handlers={}, wait='waitNested'){
|
|
||||||
var that = this
|
var that = this
|
||||||
|
|
||||||
var stage3 = function(ast){
|
var stage3 = function(ast){
|
||||||
@ -862,12 +861,13 @@ module.BaseParser = {
|
|||||||
e.call(that, state)
|
e.call(that, state)
|
||||||
: e })
|
: e })
|
||||||
.flat() }
|
.flat() }
|
||||||
|
// NOTE: we are not guarding against recursion here as there is no
|
||||||
|
// point of manually doing what JS does anyway, unless there
|
||||||
|
// is an explicit reason to do so (e.g. report error).
|
||||||
var resolve = function(ast){
|
var resolve = function(ast){
|
||||||
return Promise.awaitOrRun(
|
return Promise.awaitOrRun(
|
||||||
// XXX LOCAL_STATE
|
|
||||||
state.hasOwnProperty('wait') ?
|
state.hasOwnProperty('wait') ?
|
||||||
state.wait
|
state.wait
|
||||||
// XXX
|
|
||||||
: null,
|
: null,
|
||||||
function(){
|
function(){
|
||||||
//delete state.unresolved
|
//delete state.unresolved
|
||||||
@ -886,20 +886,19 @@ module.BaseParser = {
|
|||||||
ast = this.resolve(page, ast, state, nested_handlers)
|
ast = this.resolve(page, ast, state, nested_handlers)
|
||||||
|
|
||||||
return Promise.awaitOrRun(
|
return Promise.awaitOrRun(
|
||||||
// XXX LOCAL_STATE
|
// in case ast contains value promises, expand them...
|
||||||
// XXX do we actually need to wait here???
|
Promise
|
||||||
// ...each macro should already be waiting...
|
.iter(ast)
|
||||||
//...[state[wait]].flat(),
|
.sync(),
|
||||||
|
// wait...
|
||||||
(wait && state.hasOwnProperty(wait)) ?
|
(wait && state.hasOwnProperty(wait)) ?
|
||||||
state[wait]
|
state[wait]
|
||||||
: null,
|
: null,
|
||||||
function(){
|
function(ast){
|
||||||
// NOTE: in an async world where any promised macro can
|
// NOTE: in an async world where any promised macro can
|
||||||
// call .exec(..) / .execNested(..) we can't trust
|
// call .exec(..) / .execNested(..) we can't trust
|
||||||
// the lack of .unresolved in state...
|
// the lack of .unresolved in state...
|
||||||
return Promise.awaitOrRun(
|
return Promise.awaitOrRun(
|
||||||
// XXX LOCAL_STATE if we are nested we should not wait
|
|
||||||
// for anything after the caller...
|
|
||||||
that.isResolved(ast) ?
|
that.isResolved(ast) ?
|
||||||
ast
|
ast
|
||||||
: resolve(ast),
|
: resolve(ast),
|
||||||
@ -972,9 +971,9 @@ function(macro){
|
|||||||
// XXX RENAME...
|
// XXX RENAME...
|
||||||
// ...this is more of an expander/executer...
|
// ...this is more of an expander/executer...
|
||||||
// ...might be a good idea to also do a check without executing...
|
// ...might be a good idea to also do a check without executing...
|
||||||
var parser =
|
var macros =
|
||||||
module.parser = {
|
module.macros = {
|
||||||
__proto__: BaseParser,
|
__proto__: BaseMacros,
|
||||||
|
|
||||||
// String to be substetuted for a recursive include...
|
// String to be substetuted for a recursive include...
|
||||||
//
|
//
|
||||||
@ -1026,13 +1025,6 @@ module.parser = {
|
|||||||
//
|
//
|
||||||
// XXX should we include the global filters (current) or exclude
|
// XXX should we include the global filters (current) or exclude
|
||||||
// them by default???
|
// them by default???
|
||||||
// XXX BUG: async body breaks nested filters...
|
|
||||||
// '<filter upper/>aaa <filter -upper> moo @source(/async/page) </filter> bbb'
|
|
||||||
// -> 'AAA MOO PAGE BBB'
|
|
||||||
// XXX and this deadlocks with LOCAL_STATE
|
|
||||||
// while:
|
|
||||||
// '<filter upper/>aaa <filter -upper> moo @source(/page) </filter> bbb'
|
|
||||||
// -> 'AAA moo Page BBB'
|
|
||||||
filter: Macro(
|
filter: Macro(
|
||||||
[['clear']],
|
[['clear']],
|
||||||
function(page, args, body, state){
|
function(page, args, body, state){
|
||||||
@ -6,12 +6,12 @@ var path = require('path')
|
|||||||
var test = require('ig-test')
|
var test = require('ig-test')
|
||||||
var serialize = require('ig-serialize')
|
var serialize = require('ig-serialize')
|
||||||
|
|
||||||
var parser = require('../parser').parser
|
var macros = require('../macros').macros
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
;(parser.filters ??= {}).upper =
|
;(macros.filters ??= {}).upper =
|
||||||
function(str){
|
function(str){
|
||||||
return str.toUpperCase() }
|
return str.toUpperCase() }
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ module.exports.PAGES = {
|
|||||||
var P =
|
var P =
|
||||||
module.exports.P = {
|
module.exports.P = {
|
||||||
__pages__: PAGES,
|
__pages__: PAGES,
|
||||||
__parser__: parser,
|
__parser__: macros,
|
||||||
|
|
||||||
path: '/',
|
path: '/',
|
||||||
|
|
||||||
@ -435,6 +435,26 @@ test.Setups({
|
|||||||
code: [
|
code: [
|
||||||
'<filter upper/>@include(/async/page)',
|
'<filter upper/>@include(/async/page)',
|
||||||
'PAGE' ]} },
|
'PAGE' ]} },
|
||||||
|
filter_exclude: function(assert){
|
||||||
|
return {
|
||||||
|
page: P,
|
||||||
|
code: [
|
||||||
|
'<filter upper/>filtered <filter -upper>unfiltered</filter>',
|
||||||
|
'FILTERED unfiltered' ]} },
|
||||||
|
filter_exclude_sync: function(assert){
|
||||||
|
var state = this.filter_exclude(assert)
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
code: [
|
||||||
|
state.code[0] +' @include(/page)',
|
||||||
|
state.code[1] +' PAGE' ]} },
|
||||||
|
filter_exclude_async: function(assert){
|
||||||
|
var state = this.filter_exclude(assert)
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
code: [
|
||||||
|
state.code[0] +' @include(/async/page)',
|
||||||
|
state.code[1] +' PAGE' ]} },
|
||||||
filter_mixed_isolated_sync: function(assert){
|
filter_mixed_isolated_sync: function(assert){
|
||||||
return {
|
return {
|
||||||
page: P,
|
page: P,
|
||||||
@ -518,7 +538,7 @@ test.Tests({
|
|||||||
var p = serialize.partialDeepCopy(page)
|
var p = serialize.partialDeepCopy(page)
|
||||||
var s = serialize.partialDeepCopy(st)
|
var s = serialize.partialDeepCopy(st)
|
||||||
assert(
|
assert(
|
||||||
(res = await parser.exec(
|
(res = await macros.exec(
|
||||||
p,
|
p,
|
||||||
input,
|
input,
|
||||||
s))
|
s))
|
||||||
Loading…
x
Reference in New Issue
Block a user