Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.TokenTransformManager.js |
— | — | @@ -422,7 +422,7 @@ |
423 | 423 | this.tailAccumulator = res.async; |
424 | 424 | this.tokenCB = res.async.getParentCB ( 'sibling' ); |
425 | 425 | } |
426 | | - this.env.dp('AsyncTokenTransformManager onChunk ' + res.async); |
| 426 | + this.env.dp('AsyncTokenTransformManager onChunk res.async=' + res.async); |
427 | 427 | //this.phase2TailCB( tokens, true ); |
428 | 428 | |
429 | 429 | // The next processed chunk should call back as a sibling to last |
— | — | @@ -529,6 +529,12 @@ |
530 | 530 | */ |
531 | 531 | AsyncTokenTransformManager.prototype._returnTokens = function ( tokens, notYetDone ) { |
532 | 532 | //tokens = this._transformPhase2( this.frame, tokens, this.parentCB ); |
| 533 | + |
| 534 | + //if ( tokens.length && tokens[tokens.length - 1].type === 'END' ) { |
| 535 | + // this.env.dp( 'AsyncTokenTransformManager, stripping end ' ); |
| 536 | + // tokens.pop(); |
| 537 | + //} |
| 538 | + |
533 | 539 | this.env.dp('AsyncTokenTransformManager._returnTokens, emitting chunk: ' + |
534 | 540 | JSON.stringify( tokens ) ); |
535 | 541 | |
— | — | @@ -539,6 +545,9 @@ |
540 | 546 | // JSON.stringify( tokens, null, 2 ) + ', listeners: ' + |
541 | 547 | // JSON.stringify( this.listeners( 'chunk' ), null, 2 ) ); |
542 | 548 | // signal our done-ness to consumers. |
| 549 | + //if ( this.atTopLevel ) { |
| 550 | + // this.emit( 'chunk', [{type: 'END'}]); |
| 551 | + //} |
543 | 552 | this.emit( 'end' ); |
544 | 553 | // and reset internal state. |
545 | 554 | this._reset(); |
— | — | @@ -553,11 +562,13 @@ |
554 | 563 | */ |
555 | 564 | AsyncTokenTransformManager.prototype.onEndEvent = function () { |
556 | 565 | if ( this.tailAccumulator ) { |
557 | | - this.env.dp( 'AsyncTokenTransformManager.onEndEvent: calling siblingDone' ); |
| 566 | + this.env.dp( 'AsyncTokenTransformManager.onEndEvent: calling siblingDone', |
| 567 | + this.loopAndDepthCheck ); |
558 | 568 | this.tailAccumulator.siblingDone(); |
559 | 569 | } else { |
560 | 570 | // nothing was asynchronous, so we'll have to emit end here. |
561 | | - this.env.dp( 'AsyncTokenTransformManager.onEndEvent: synchronous done' ); |
| 571 | + this.env.dp( 'AsyncTokenTransformManager.onEndEvent: synchronous done', |
| 572 | + this.loopAndDepthCheck ); |
562 | 573 | this.emit('end'); |
563 | 574 | this._reset(); |
564 | 575 | } |
— | — | @@ -607,8 +618,8 @@ |
608 | 619 | * @param {Array} Token chunk. |
609 | 620 | */ |
610 | 621 | SyncTokenTransformManager.prototype.onChunk = function ( tokens ) { |
611 | | - //console.log('SyncTokenTransformManager.onChunk: ' + |
612 | | - // JSON.stringify( tokens, null, 2 ) ); |
| 622 | + this.env.dp('SyncTokenTransformManager.onChunk, input: ' + |
| 623 | + JSON.stringify( tokens, null, 2 ) ); |
613 | 624 | var res, |
614 | 625 | localAccum = [], |
615 | 626 | localAccumLength = 0, |
— | — | @@ -859,36 +870,12 @@ |
860 | 871 | //console.log( 'TokenAccumulator._returnTokens' ); |
861 | 872 | if ( reference === 'child' ) { |
862 | 873 | tokens = tokens.concat( this.accum ); |
863 | | - //console.log('TokenAccumulator._returnTokens child: ' + |
864 | | - // JSON.stringify( tokens, null, 2 ) + |
865 | | - // ' outstanding: ' + this.outstanding |
866 | | - // ); |
| 874 | + console.log('TokenAccumulator._returnTokens child: ' + |
| 875 | + JSON.stringify( tokens, null, 2 ) + |
| 876 | + ' outstanding: ' + this.outstanding |
| 877 | + ); |
867 | 878 | this.accum = []; |
868 | | - // XXX: Use some marker to avoid re-transforming token chunks several |
869 | | - // times? |
870 | | - //res = this.transformTokens( tokens, this.parentCB ); |
871 | | - |
872 | | - //if ( res.async ) { |
873 | | - // // new asynchronous expansion started, chain of accumulators |
874 | | - // // created |
875 | | - // if ( this.outstanding === 0 ) { |
876 | | - // // Last accum in chain should only wait for child |
877 | | - // res.async.outstanding--; |
878 | | - // cb = this.parentCB; |
879 | | - // } else { |
880 | | - // cb = this.parentCB; |
881 | | - // // set own callback to new sibling, the end of accumulator chain |
882 | | - // this.parentCB = res.async.getParentCB( 'sibling' ); |
883 | | - // } |
884 | | - //} |
885 | | - //if ( ! notYetDone ) { |
886 | | - // // Child is done, return accumulator from sibling. Siblings |
887 | | - // // process tokens themselves, so we concat those to the result of |
888 | | - // // processing tokens from the child. |
889 | | - // tokens = res.tokens.concat( this.accum ); |
890 | | - // this.accum = []; |
891 | | - //} |
892 | | - this.parentCB( tokens, this.outstanding !== 0 ); |
| 879 | + this.parentCB( tokens, this.outstanding ); |
893 | 880 | return null; |
894 | 881 | } else { |
895 | 882 | // sibling |
— | — | @@ -896,13 +883,13 @@ |
897 | 884 | tokens = this.accum.concat( tokens ); |
898 | 885 | // A sibling will transform tokens, so we don't have to do this |
899 | 886 | // again. |
900 | | - //console.log( 'TokenAccumulator._returnTokens: sibling done and parentCB ' + |
901 | | - // JSON.stringify( tokens ) ); |
| 887 | + console.log( 'TokenAccumulator._returnTokens: sibling done and parentCB ' + |
| 888 | + JSON.stringify( tokens ) ); |
902 | 889 | this.parentCB( tokens, false ); |
903 | 890 | return null; |
904 | 891 | } else if ( this.outstanding === 1 && notYetDone ) { |
905 | | - //console.log( 'TokenAccumulator._returnTokens: sibling done and parentCB but notYetDone ' + |
906 | | - // JSON.stringify( tokens ) ); |
| 892 | + console.log( 'TokenAccumulator._returnTokens: sibling done and parentCB but notYetDone ' + |
| 893 | + JSON.stringify( tokens ) ); |
907 | 894 | // Sibling is not yet done, but child is. Return own parentCB to |
908 | 895 | // allow the sibling to go direct, and call back parent with |
909 | 896 | // tokens. The internal accumulator is empty at this stage, as its |
— | — | @@ -910,8 +897,10 @@ |
911 | 898 | return this.parentCB( tokens, true); |
912 | 899 | } else { |
913 | 900 | this.accum = this.accum.concat( tokens ); |
914 | | - //console.log( 'TokenAccumulator._returnTokens: sibling done, but not overall ' + |
915 | | - // JSON.stringify( tokens ) ); |
| 901 | + console.log( 'TokenAccumulator._returnTokens: sibling done, but not overall. notYetDone=' + |
| 902 | + notYetDone + ', this.outstanding=' + this.outstanding + |
| 903 | + ', this.accum=' + |
| 904 | + JSON.stringify( this.accum, null, 2 ) ); |
916 | 905 | } |
917 | 906 | |
918 | 907 | |
— | — | @@ -966,7 +955,7 @@ |
967 | 956 | */ |
968 | 957 | LoopAndDepthCheck.prototype.check = function ( title ) { |
969 | 958 | // XXX: set limit really low for testing! |
970 | | - if ( this.depth > 40 ) { |
| 959 | + if ( this.depth > 5 ) { |
971 | 960 | // too deep |
972 | 961 | //console.log( 'Loopcheck: ' + JSON.stringify( this, null, 2 ) ); |
973 | 962 | 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: false |
| 24 | + debug: true |
25 | 25 | } ), |
26 | 26 | parser = new ParserPipeline( env ); |
27 | 27 | |
Index: trunk/extensions/VisualEditor/modules/parser/pegTokenizer.pegjs.txt |
— | — | @@ -764,19 +764,25 @@ |
765 | 765 | // HACK, not final. |
766 | 766 | obj.attribs.push(['data-defaultvalue', params[0][1]]); |
767 | 767 | obj.attribs.push(['data-json-args', JSON.stringify(params)]); |
768 | | - obj.defaultvalue = params[0][1]; |
| 768 | + obj.defaultvalue = params[0][1].length ? params[0][1] : |
| 769 | + [{type: 'TEXT', value: ''}]; |
769 | 770 | } |
770 | 771 | //console.log( 'tokenizer tplarg ' + JSON.stringify( obj )); |
771 | 772 | return obj; |
772 | 773 | } |
773 | 774 | |
774 | 775 | template_param |
775 | | - = name:template_param_name space* "=" space* c:template_param_text { |
| 776 | + = name:template_param_name space* "=" space* c:template_param_text? { |
776 | 777 | //console.log( 'named template_param matched' + pp([name, flatten( c )]) ); |
777 | | - return [name, flatten( c )]; |
| 778 | + if ( c !== '' ) { |
| 779 | + return [name, flatten( c )]; |
| 780 | + } else { |
| 781 | + return [name, []]; |
| 782 | + } |
778 | 783 | } / c:template_param_text { |
779 | | - return [[], flatten( c ) ]; |
| 784 | + return [[], flatten( c ) ]; |
780 | 785 | } |
| 786 | + / & '|' { return [[], []]; } |
781 | 787 | |
782 | 788 | |
783 | 789 | // FIXME: handle template args and templates in key! (or even parser functions?) |
Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.parser.js |
— | — | @@ -67,6 +67,7 @@ |
68 | 68 | // Create an input pipeline for the given input type. |
69 | 69 | this.inputPipeline = this.makeInputPipeline ( inputType, {}, true ); |
70 | 70 | this.inputPipeline.atTopLevel = true; |
| 71 | + this.inputPipeline.last.atTopLevel = true; |
71 | 72 | |
72 | 73 | |
73 | 74 | this.tokenPostProcessor = new TokenTransformManager.SyncTokenTransformManager ( env ); |
Index: trunk/extensions/VisualEditor/modules/parser/ext.core.TemplateHandler.js |
— | — | @@ -75,8 +75,8 @@ |
76 | 76 | var attributes = [[[{ type: 'TEXT', value: '' }] , token.target ]] |
77 | 77 | .concat( this._nameArgs( token.orderedArgs ) ); |
78 | 78 | |
79 | | - this.manager.env.dp( 'before AttributeTransformManager: ' + |
80 | | - JSON.stringify( attributes, null, 2 ) ); |
| 79 | + //this.manager.env.dp( 'before AttributeTransformManager: ' + |
| 80 | + // JSON.stringify( attributes, null, 2 ) ); |
81 | 81 | new AttributeTransformManager( |
82 | 82 | this.manager, |
83 | 83 | this._returnAttributes.bind( this, tplExpandData ) |
— | — | @@ -106,6 +106,7 @@ |
107 | 107 | var n = 1, |
108 | 108 | out = []; |
109 | 109 | for ( var i = 0, l = orderedArgs.length; i < l; i++ ) { |
| 110 | + // FIXME: Also check for whitespace-only named args! |
110 | 111 | if ( ! orderedArgs[i][0].length ) { |
111 | 112 | out.push( [[{ type: 'TEXT', value: n }], orderedArgs[i][1]]); |
112 | 113 | n++; |
— | — | @@ -257,6 +258,7 @@ |
258 | 259 | var res = tplExpandData.resultTokens; |
259 | 260 | // Remove 'end' token from end |
260 | 261 | if ( res.length && res[res.length - 1].type === 'END' ) { |
| 262 | + this.manager.env.dp( 'TemplateHandler, stripping end ' ); |
261 | 263 | res.pop(); |
262 | 264 | } |
263 | 265 | |
— | — | @@ -365,7 +367,7 @@ |
366 | 368 | } else { |
367 | 369 | console.log( 'templateArg not found: ' + argName + |
368 | 370 | ' vs. ' + JSON.stringify( this.manager.args ) ); |
369 | | - if ( token.attribs.length > 1 ) { |
| 371 | + if ( false && defaultValue.length ) { |
370 | 372 | res = defaultValue; |
371 | 373 | } else { |
372 | 374 | res = [{ type: 'TEXT', value: '{{{' + argName + '}}}' }]; |