Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.TokenTransformManager.js |
— | — | @@ -444,7 +444,7 @@ |
445 | 445 | phaseEndRank = 2, // XXX: parametrize! |
446 | 446 | // Prepare a new accumulator, to be used by async children (if any) |
447 | 447 | localAccum = [], |
448 | | - accum = new TokenAccumulator( parentCB ), |
| 448 | + accum = new TokenAccumulator( this, parentCB ), |
449 | 449 | cb = accum.getParentCB( 'child' ), |
450 | 450 | activeAccum = null, |
451 | 451 | tokensLength = tokens.length, |
— | — | @@ -506,7 +506,7 @@ |
507 | 507 | // The child now switched to activeAccum, we have to create a new |
508 | 508 | // accumulator for the next potential child. |
509 | 509 | activeAccum = accum; |
510 | | - accum = new TokenAccumulator( activeAccum.getParentCB( 'sibling' ) ); |
| 510 | + accum = new TokenAccumulator( this, activeAccum.getParentCB( 'sibling' ) ); |
511 | 511 | cb = accum.getParentCB( 'child' ); |
512 | 512 | } |
513 | 513 | } |
— | — | @@ -831,7 +831,8 @@ |
832 | 832 | * @param {Object} next TokenAccumulator to link to |
833 | 833 | * @param {Array} (optional) tokens, init accumulator with tokens or [] |
834 | 834 | */ |
835 | | -function TokenAccumulator ( parentCB ) { |
| 835 | +function TokenAccumulator ( manager, parentCB ) { |
| 836 | + this.manager = manager; |
836 | 837 | this.parentCB = parentCB; |
837 | 838 | this.accum = []; |
838 | 839 | // Wait for child and sibling by default |
— | — | @@ -870,7 +871,7 @@ |
871 | 872 | //console.log( 'TokenAccumulator._returnTokens' ); |
872 | 873 | if ( reference === 'child' ) { |
873 | 874 | tokens = tokens.concat( this.accum ); |
874 | | - console.log('TokenAccumulator._returnTokens child: ' + |
| 875 | + this.manager.env.dp('TokenAccumulator._returnTokens child: ' + |
875 | 876 | JSON.stringify( tokens, null, 2 ) + |
876 | 877 | ' outstanding: ' + this.outstanding |
877 | 878 | ); |
— | — | @@ -883,12 +884,12 @@ |
884 | 885 | tokens = this.accum.concat( tokens ); |
885 | 886 | // A sibling will transform tokens, so we don't have to do this |
886 | 887 | // again. |
887 | | - console.log( 'TokenAccumulator._returnTokens: sibling done and parentCB ' + |
| 888 | + this.manager.env.dp( 'TokenAccumulator._returnTokens: sibling done and parentCB ' + |
888 | 889 | JSON.stringify( tokens ) ); |
889 | 890 | this.parentCB( tokens, false ); |
890 | 891 | return null; |
891 | 892 | } else if ( this.outstanding === 1 && notYetDone ) { |
892 | | - console.log( 'TokenAccumulator._returnTokens: sibling done and parentCB but notYetDone ' + |
| 893 | + this.manager.env.dp( 'TokenAccumulator._returnTokens: sibling done and parentCB but notYetDone ' + |
893 | 894 | JSON.stringify( tokens ) ); |
894 | 895 | // Sibling is not yet done, but child is. Return own parentCB to |
895 | 896 | // allow the sibling to go direct, and call back parent with |
— | — | @@ -897,7 +898,7 @@ |
898 | 899 | return this.parentCB( tokens, true); |
899 | 900 | } else { |
900 | 901 | this.accum = this.accum.concat( tokens ); |
901 | | - console.log( 'TokenAccumulator._returnTokens: sibling done, but not overall. notYetDone=' + |
| 902 | + this.manager.env.dp( 'TokenAccumulator._returnTokens: sibling done, but not overall. notYetDone=' + |
902 | 903 | notYetDone + ', this.outstanding=' + this.outstanding + |
903 | 904 | ', this.accum=' + |
904 | 905 | JSON.stringify( this.accum, null, 2 ) ); |
— | — | @@ -955,7 +956,7 @@ |
956 | 957 | */ |
957 | 958 | LoopAndDepthCheck.prototype.check = function ( title ) { |
958 | 959 | // XXX: set limit really low for testing! |
959 | | - if ( this.depth > 5 ) { |
| 960 | + if ( this.depth > 40 ) { |
960 | 961 | // too deep |
961 | 962 | //console.log( 'Loopcheck: ' + JSON.stringify( this, null, 2 ) ); |
962 | 963 | return 'Expansion depth limit exceeded at '; |
Index: trunk/extensions/VisualEditor/modules/parser/parse.js |
— | — | @@ -20,7 +20,7 @@ |
21 | 21 | wgScriptExtension: ".php", |
22 | 22 | fetchTemplates: true, |
23 | 23 | // enable/disable debug output using this switch |
24 | | - debug: true |
| 24 | + debug: false |
25 | 25 | } ), |
26 | 26 | parser = new ParserPipeline( env ); |
27 | 27 | |
Index: trunk/extensions/VisualEditor/modules/parser/ext.core.ParserFunctions.js |
— | — | @@ -0,0 +1,145 @@ |
| 2 | +/** |
| 3 | + * Some parser functions |
| 4 | + */ |
| 5 | + |
| 6 | +function ParserFunctions ( manager ) { |
| 7 | + this.manager = manager; |
| 8 | +} |
| 9 | + |
| 10 | +ParserFunctions.prototype.fun = {}; |
| 11 | + |
| 12 | +ParserFunctions.prototype['pf_#if'] = function ( target, argList, argDict ) { |
| 13 | + if ( target.trim() !== '' ) { |
| 14 | + this.manager.env.dp('#if, first branch', argDict[1] ); |
| 15 | + return argDict[1] || []; |
| 16 | + } else { |
| 17 | + this.manager.env.dp('#if, second branch', argDict[2] ); |
| 18 | + return argDict[2] || []; |
| 19 | + } |
| 20 | +}; |
| 21 | + |
| 22 | +ParserFunctions.prototype['pf_#switch'] = function ( target, argList, argDict ) { |
| 23 | + this.manager.env.dp( 'switch enter: ' + target.trim() + |
| 24 | + ' looking in ', argDict ); |
| 25 | + if ( target.trim() in argDict ) { |
| 26 | + this.manager.env.dp( 'switch found: ' + target.trim() + |
| 27 | + ' res=', argDict[target.trim()] ); |
| 28 | + return argDict[target.trim()]; |
| 29 | + } else if ( '#default' in argDict ) { |
| 30 | + return argDict['#default']; |
| 31 | + } else { |
| 32 | + var lastKV = argList[argList.length - 1]; |
| 33 | + if ( lastKV && ! lastKV[0].length ) { |
| 34 | + return lastKV[1]; |
| 35 | + } else { |
| 36 | + return []; |
| 37 | + } |
| 38 | + } |
| 39 | +}; |
| 40 | + |
| 41 | +// #ifeq |
| 42 | +ParserFunctions.prototype['pf_#ifeq'] = function ( target, argList, argDict ) { |
| 43 | + if ( ! argList.length ) { |
| 44 | + return []; |
| 45 | + } else { |
| 46 | + if ( target.trim() === this.manager.env.tokensToString( argList[0][1] ).trim() ) { |
| 47 | + return ( argList[1] && argList[1][1]) || []; |
| 48 | + } else { |
| 49 | + return ( argList[1] && argList[1][1]) || []; |
| 50 | + } |
| 51 | + } |
| 52 | +}; |
| 53 | + |
| 54 | +ParserFunctions.prototype['pf_lc'] = function ( target, argList, argDict ) { |
| 55 | + return [{type: 'TEXT', value: target.toLowerCase()}]; |
| 56 | +}; |
| 57 | +ParserFunctions.prototype['pf_uc'] = function ( target, argList, argDict ) { |
| 58 | + return [{type: 'TEXT', value: target.toUpperCase()}]; |
| 59 | +}; |
| 60 | +ParserFunctions.prototype['pf_ucfirst'] = function ( target, argList, argDict ) { |
| 61 | + if ( target ) { |
| 62 | + return [{ |
| 63 | + type: 'TEXT', |
| 64 | + value: target[0].toUpperCase() + target.substr(1) |
| 65 | + }]; |
| 66 | + } else { |
| 67 | + return []; |
| 68 | + } |
| 69 | +}; |
| 70 | +ParserFunctions.prototype['pf_lcfirst'] = function ( target, argList, argDict ) { |
| 71 | + if ( target ) { |
| 72 | + return [{ |
| 73 | + type: 'TEXT', |
| 74 | + value: target[0].toLowerCase() + target.substr(1) |
| 75 | + }]; |
| 76 | + } else { |
| 77 | + return []; |
| 78 | + } |
| 79 | +}; |
| 80 | + |
| 81 | +ParserFunctions.prototype['pf_#tag'] = function ( target, argList, argDict ) { |
| 82 | + return [{type: 'TAG', name: target, attribs: argList}]; |
| 83 | +}; |
| 84 | + |
| 85 | +// FIXME |
| 86 | +ParserFunctions.prototype['pf_#ifexpr'] = function ( target, argList, argDict ) { |
| 87 | + return []; |
| 88 | +}; |
| 89 | +ParserFunctions.prototype['pf_#iferror'] = function ( target, argList, argDict ) { |
| 90 | + return []; |
| 91 | +}; |
| 92 | +ParserFunctions.prototype['pf_#expr'] = function ( target, argList, argDict ) { |
| 93 | + return []; |
| 94 | +}; |
| 95 | +ParserFunctions.prototype['pf_#ifexist'] = function ( target, argList, argDict ) { |
| 96 | + return []; |
| 97 | +}; |
| 98 | + |
| 99 | +// pure fake.. |
| 100 | +ParserFunctions.prototype['pf_formatnum'] = function ( target, argList, argDict ) { |
| 101 | + return [{type: 'TEXT', value: target}]; |
| 102 | +}; |
| 103 | +ParserFunctions.prototype['pf_currentpage'] = function ( target, argList, argDict ) { |
| 104 | + return [{type: 'TEXT', value: target}]; |
| 105 | +}; |
| 106 | +ParserFunctions.prototype['pf_pagename'] = function ( target, argList, argDict ) { |
| 107 | + return [{type: 'TEXT', value: target}]; |
| 108 | +}; |
| 109 | +ParserFunctions.prototype['pf_pagename'] = function ( target, argList, argDict ) { |
| 110 | + return [{type: 'TEXT', value: target}]; |
| 111 | +}; |
| 112 | +ParserFunctions.prototype['pf_fullpagename'] = function ( target, argList, argDict ) { |
| 113 | + return [{type: 'TEXT', value: target}]; |
| 114 | +}; |
| 115 | +ParserFunctions.prototype['pf_fullpagenamee'] = function ( target, argList, argDict ) { |
| 116 | + return [{type: 'TEXT', value: target}]; |
| 117 | +}; |
| 118 | +ParserFunctions.prototype['pf_fullurl'] = function ( target, argList, argDict ) { |
| 119 | + return [{type: 'TEXT', value: target}]; |
| 120 | +}; |
| 121 | +ParserFunctions.prototype['pf_urlencode'] = function ( target, argList, argDict ) { |
| 122 | + return [{type: 'TEXT', value: target}]; |
| 123 | +}; |
| 124 | +ParserFunctions.prototype['pf_namespace'] = function ( target, argList, argDict ) { |
| 125 | + return [{type: 'TEXT', value: 'Main'}]; |
| 126 | +}; |
| 127 | + |
| 128 | +// FIXME! This is just fake. |
| 129 | +ParserFunctions.prototype['pf_#time'] = function ( target, argList, argDict ) { |
| 130 | + return [{type: 'TEXT', value: new Date().toString()}]; |
| 131 | +}; |
| 132 | + |
| 133 | +// #time |
| 134 | +// #ifexp |
| 135 | +// PAGENAME |
| 136 | +// #expr |
| 137 | +// NAMESPACE |
| 138 | +// #iferror |
| 139 | +// |
| 140 | + |
| 141 | +//ParserFunctions.prototype['pf_FORMATNUM'] = function ( target, argList, argDict ) { |
| 142 | +//}; |
| 143 | + |
| 144 | +if (typeof module == "object") { |
| 145 | + module.exports.ParserFunctions = ParserFunctions; |
| 146 | +} |
Property changes on: trunk/extensions/VisualEditor/modules/parser/ext.core.ParserFunctions.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 147 | + native |
Index: trunk/extensions/VisualEditor/modules/parser/pegTokenizer.pegjs.txt |
— | — | @@ -782,7 +782,7 @@ |
783 | 783 | } / c:template_param_text { |
784 | 784 | return [[], flatten( c ) ]; |
785 | 785 | } |
786 | | - / & '|' { return [[], []]; } |
| 786 | + / & [|}] { return [[], []]; } |
787 | 787 | |
788 | 788 | |
789 | 789 | // FIXME: handle template args and templates in key! (or even parser functions?) |
Index: trunk/extensions/VisualEditor/modules/parser/ext.core.TemplateHandler.js |
— | — | @@ -14,6 +14,7 @@ |
15 | 15 | request = require('request'), |
16 | 16 | events = require('events'), |
17 | 17 | qs = require('querystring'), |
| 18 | + ParserFunctions = require('./ext.core.ParserFunctions.js').ParserFunctions, |
18 | 19 | AttributeTransformManager = require('./mediawiki.TokenTransformManager.js') |
19 | 20 | .AttributeTransformManager; |
20 | 21 | |
— | — | @@ -21,6 +22,7 @@ |
22 | 23 | function TemplateHandler ( manager ) { |
23 | 24 | this.reset(); |
24 | 25 | this.register( manager ); |
| 26 | + this.parserFunctions = new ParserFunctions( manager ); |
25 | 27 | } |
26 | 28 | |
27 | 29 | TemplateHandler.prototype.reset = function ( token ) { |
— | — | @@ -160,6 +162,30 @@ |
161 | 163 | var target = this.manager.env.normalizeTitle( |
162 | 164 | this.manager.env.tokensToString( tplExpandData.target ) |
163 | 165 | ); |
| 166 | + var args = this.manager.env.KVtoHash( tplExpandData.expandedArgs ); |
| 167 | + |
| 168 | + this.manager.env.dp( 'argHash: ', args ); |
| 169 | + |
| 170 | + var prefix = target.split(':', 1)[0].toLowerCase(); |
| 171 | + if ( prefix && 'pf_' + prefix in this.parserFunctions ) { |
| 172 | + var funcArg = target.substr( prefix.length + 1 ); |
| 173 | + this.manager.env.dp( 'entering prefix', funcArg, args ); |
| 174 | + var res = this.parserFunctions[ 'pf_' + prefix ]( funcArg, |
| 175 | + tplExpandData.expandDone, args ); |
| 176 | + |
| 177 | + // XXX: support async parser functions! |
| 178 | + if ( tplExpandData.overallAsync ) { |
| 179 | + this.manager.env.dp( 'TemplateHandler._expandTemplate: calling back ' + |
| 180 | + 'after parser func ' + prefix + ' with res:' + JSON.stringify( res ) ); |
| 181 | + return tplExpandData.cb( res, false ); |
| 182 | + } else { |
| 183 | + this.manager.env.dp( 'TemplateHandler._expandTemplate: sync return ' + |
| 184 | + 'after parser func ' + prefix + ' with res:' + JSON.stringify( res ) ); |
| 185 | + return { tokens: res }; |
| 186 | + //data.reset(); |
| 187 | + } |
| 188 | + } |
| 189 | + |
164 | 190 | var checkRes = this.manager.loopAndDepthCheck.check( target ); |
165 | 191 | if( checkRes ) { |
166 | 192 | // Loop detected, abort! |
— | — | @@ -191,10 +217,9 @@ |
192 | 218 | // 'text/wiki' input and asynchronous stage-2 transforms). |
193 | 219 | var inputPipeline = this.manager.newChildPipeline( |
194 | 220 | this.manager.inputType || 'text/wiki', |
195 | | - this.manager.env.KVtoHash( tplExpandData.expandedArgs ), |
| 221 | + args, |
196 | 222 | tplExpandData.target |
197 | 223 | ); |
198 | | - this.manager.env.dp( 'argHash:', this.manager.env.KVtoHash( tplExpandData.expandedArgs ) ); |
199 | 224 | |
200 | 225 | // Hook up the inputPipeline output events to our handlers |
201 | 226 | inputPipeline.addListener( 'chunk', this._onChunk.bind ( this, tplExpandData ) ); |
— | — | @@ -301,7 +326,7 @@ |
302 | 327 | // Unwind the stack |
303 | 328 | process.nextTick( |
304 | 329 | function () { |
305 | | - callback( self.manager.env.pageCache[title], title ) |
| 330 | + callback( self.manager.env.pageCache[title], title ); |
306 | 331 | } |
307 | 332 | ); |
308 | 333 | } else if ( ! this.manager.env.fetchTemplates ) { |
— | — | @@ -314,7 +339,7 @@ |
315 | 340 | this.manager.env.dp( 'trying to fetch ' + title ); |
316 | 341 | |
317 | 342 | // Start a new request if none is outstanding |
318 | | - this.manager.env.dp( 'requestQueue: ', this.manager.env.requestQueue) |
| 343 | + this.manager.env.dp( 'requestQueue: ', this.manager.env.requestQueue); |
319 | 344 | if ( this.manager.env.requestQueue[title] === undefined ) { |
320 | 345 | this.manager.env.requestQueue[title] = new TemplateRequest( this.manager, title ); |
321 | 346 | } |
— | — | @@ -365,9 +390,9 @@ |
366 | 391 | // ' vs. ' + JSON.stringify( this.manager.args ) ); |
367 | 392 | res = this.manager.args[argName]; |
368 | 393 | } else { |
369 | | - console.log( 'templateArg not found: ' + argName + |
| 394 | + this.manager.env.dp( 'templateArg not found: ' + argName + |
370 | 395 | ' vs. ' + JSON.stringify( this.manager.args ) ); |
371 | | - if ( false && defaultValue.length ) { |
| 396 | + if ( defaultValue.length ) { |
372 | 397 | res = defaultValue; |
373 | 398 | } else { |
374 | 399 | res = [{ type: 'TEXT', value: '{{{' + argName + '}}}' }]; |
— | — | @@ -414,10 +439,12 @@ |
415 | 440 | manager.env.dp(error); |
416 | 441 | self.emit('src', 'Page/template fetch failure for title ' + title, title); |
417 | 442 | } else if(response.statusCode == 200) { |
418 | | - var src = ''; |
| 443 | + var src = '', |
| 444 | + data, |
| 445 | + normalizedTitle; |
419 | 446 | try { |
420 | 447 | //console.log( 'body: ' + body ); |
421 | | - var data = JSON.parse( body ); |
| 448 | + data = JSON.parse( body ); |
422 | 449 | } catch(e) { |
423 | 450 | console.log( "Error: while parsing result. Error was: " ); |
424 | 451 | console.log( e ); |
— | — | @@ -426,13 +453,13 @@ |
427 | 454 | console.log( "------------------------------------------" ); |
428 | 455 | } |
429 | 456 | try { |
430 | | - $.each(data.query.pages, function(i, page) { |
| 457 | + $.each( data.query.pages, function(i, page) { |
431 | 458 | if (page.revisions && page.revisions.length) { |
432 | 459 | src = page.revisions[0]['*']; |
433 | | - title = page.title; |
| 460 | + normalizeTitle = page.title; |
434 | 461 | } |
435 | 462 | }); |
436 | | - } catch ( e ) { |
| 463 | + } catch ( e2 ) { |
437 | 464 | console.log( 'Did not find page revisions in the returned body:' + body ); |
438 | 465 | src = ''; |
439 | 466 | } |
— | — | @@ -445,13 +472,15 @@ |
446 | 473 | // XXX: handle other status codes |
447 | 474 | |
448 | 475 | // Remove self from request queue |
| 476 | + manager.env.dp( 'trying to remove ' + title + ' from requestQueue' ); |
449 | 477 | delete manager.env.requestQueue[title]; |
| 478 | + manager.env.dp( 'after deletion:', manager.env.requestQueue ); |
450 | 479 | }); |
451 | 480 | } |
452 | 481 | |
453 | 482 | /* |
454 | | - * XXX: The jQuery version does not quite work with node, but we keep |
455 | | - * it around for now. |
| 483 | + * XXX: The jQuery version does not quite work with node, but we keep |
| 484 | + * it around for now. |
456 | 485 | $.ajax({ |
457 | 486 | url: url, |
458 | 487 | data: { |
Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.parser.environment.js |
— | — | @@ -116,7 +116,7 @@ |
117 | 117 | var token = tokens[i]; |
118 | 118 | if ( ! token ) { |
119 | 119 | console.trace(); |
120 | | - console.log( 'MWParserEnvironment.tokensToString, invalid token: ' + |
| 120 | + this.dp( 'MWParserEnvironment.tokensToString, invalid token: ' + |
121 | 121 | JSON.stringify( token ) ); |
122 | 122 | continue; |
123 | 123 | } |
— | — | @@ -126,7 +126,7 @@ |
127 | 127 | // strip comments and newlines |
128 | 128 | } else { |
129 | 129 | var tstring = JSON.stringify( token ); |
130 | | - console.log ( 'MWParserEnvironment.tokensToString, non-text token: ' + |
| 130 | + this.dp ( 'MWParserEnvironment.tokensToString, non-text token: ' + |
131 | 131 | tstring + JSON.stringify( tokens, null, 2 ) ); |
132 | 132 | out.push( tstring ); |
133 | 133 | } |