r109233 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r109232‎ | r109233 | r109234 >
Date:22:29, 17 January 2012
Author:gwicke
Status:deferred
Tags:
Comment:
Fix template argument expansion. 200 parser tests now passing.
Modified paths:
  • /trunk/extensions/VisualEditor/modules/parser/ext.core.TemplateHandler.js (modified) (history)
  • /trunk/extensions/VisualEditor/modules/parser/mediawiki.TokenTransformManager.js (modified) (history)
  • /trunk/extensions/VisualEditor/modules/parser/mediawiki.parser.environment.js (modified) (history)
  • /trunk/extensions/VisualEditor/modules/parser/mediawiki.parser.js (modified) (history)
  • /trunk/extensions/VisualEditor/modules/parser/pegTokenizer.pegjs.txt (modified) (history)

Diff [purge]

Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.TokenTransformManager.js
@@ -331,6 +331,7 @@
332332 * first stage of the pipeline, and 'last' pointing to the last stage.
333333 */
334334 AsyncTokenTransformManager.prototype.newChildPipeline = function ( inputType, args, title ) {
 335+ //console.log( 'newChildPipeline: ' + JSON.stringify( args ) );
335336 var pipe = this.childFactories.input( inputType, args );
336337
337338 // now set up a few things on the child AsyncTokenTransformManager.
@@ -375,6 +376,7 @@
376377 this.accum = new TokenAccumulator(null);
377378 this.firstaccum = this.accum;
378379 this.prevToken = undefined;
 380+ //console.log( 'AsyncTokenTransformManager args ' + JSON.stringify( args ) );
379381 if ( ! args ) {
380382 this.args = {}; // no arguments at the top level
381383 } else {
Index: trunk/extensions/VisualEditor/modules/parser/pegTokenizer.pegjs.txt
@@ -538,7 +538,7 @@
539539 inline_element
540540 = //& { dp('inline_element enter' + input.substr(pos, 10)); return true; }
541541 & '<' ( comment / xmlish_tag )
542 - / & '{' ( template / tplarg )
 542+ / & '{' ( tplarg / template )
543543 / & '[' ( wikilink / extlink )
544544 / & "'" quote
545545
@@ -728,23 +728,28 @@
729729
730730 template_param
731731 = name:template_param_name space* "=" space* c:template_param_text {
732 - return [{ type: 'TEXT', value: name }, { type: 'TEXT', value: c }];
 732+ return [[{ type: 'TEXT', value: name }], flatten( c )];
733733 } / c:template_param_text {
734 - return [[], { type: 'TEXT', value: c }];
 734+ return [[], flatten( c ) ];
735735 }
736736
737737 tplarg
738 - = "{{{" name:link_target params:("|" p:template_param { return p })* "}}}" {
 738+ = "{{{" name:template_param_text params:("|" p:template_param { return p })* "}}}" {
 739+ name = flatten( name );
739740 var obj = {
740741 type: 'SELFCLOSINGTAG',
741742 name: 'templatearg',
742 - attribs: [['argname', name]]
 743+ attribs: [],
 744+ argname: name,
 745+ defaultvalue: []
743746 };
744747 if (params && params.length) {
745748 // HACK, not final.
746749 obj.attribs.push(['data-defaultvalue', params[0][1]]);
747750 obj.attribs.push(['data-json-args', JSON.stringify(params)]);
 751+ obj.defaultvalue = params[0][1];
748752 }
 753+ //console.log( 'tokenizer templatearg ' + JSON.stringify( obj ));
749754 return obj;
750755 }
751756
Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.parser.js
@@ -130,8 +130,11 @@
131131 ParserPipeline.prototype.makeInputPipeline = function ( inputType, args ) {
132132 switch ( inputType ) {
133133 case 'text/wiki':
 134+ //console.log( 'makeInputPipeline ' + JSON.stringify( args ) );
134135 if ( this.pipelineCache['text/wiki'].input.length ) {
135 - return this.pipelineCache['text/wiki'].input.pop();
 136+ var pipe = this.pipelineCache['text/wiki'].input.pop();
 137+ pipe.last.args = args;
 138+ return pipe;
136139 } else {
137140 var wikiTokenizer = new PegTokenizer();
138141
Index: trunk/extensions/VisualEditor/modules/parser/ext.core.TemplateHandler.js
@@ -31,6 +31,8 @@
3232 // Register for template and templatearg tag tokens
3333 manager.addTransform( this.onTemplate.bind(this),
3434 this.rank, 'tag', 'template' );
 35+
 36+ // Template argument expansion
3537 manager.addTransform( this.onTemplateArg.bind(this),
3638 this.rank, 'tag', 'templatearg' );
3739
@@ -73,7 +75,7 @@
7476 kv;
7577
7678 var attributes = [[[{ type: 'TEXT', value: '' }] , token.target ]]
77 - .concat( token.orderedArgs );
 79+ .concat( this._nameArgs( token.orderedArgs ) );
7880
7981 //console.log( 'before AttributeTransformManager: ' + JSON.stringify( attributes, null, 2 ) );
8082 new AttributeTransformManager(
@@ -92,6 +94,21 @@
9395 }
9496 };
9597
 98+TemplateHandler.prototype._nameArgs = function ( orderedArgs ) {
 99+ var n = 1,
 100+ out = [];
 101+ for ( var i = 0, l = orderedArgs.length; i < l; i++ ) {
 102+ if ( ! orderedArgs[i][0].length ) {
 103+ out.push( [[{ type: 'TEXT', value: n }], orderedArgs[i][1]]);
 104+ n++;
 105+ } else {
 106+ out.push( orderedArgs[i] );
 107+ }
 108+ }
 109+ //console.log( '_nameArgs: ' + JSON.stringify( out ) );
 110+ return out;
 111+};
 112+
96113 TemplateHandler.prototype._returnAttributes = function ( templateTokenTransformData, attributes ) {
97114 //console.log( 'TemplateHandler._returnAttributes: ' + JSON.stringify(attributes) );
98115 // Remove the target from the attributes
@@ -101,7 +118,7 @@
102119 if ( templateTokenTransformData.isAsync ) {
103120 this._expandTemplate ( templateTokenTransformData );
104121 }
105 -}
 122+};
106123
107124 /**
108125 * Fetch, tokenize and token-transform a template after all arguments and the
@@ -144,9 +161,12 @@
145162 // 'text/wiki' input).
146163 // Returned pipe (for now):
147164 // { first: tokenizer, last: AsyncTokenTransformManager }
 165+ //console.log( 'expanded args: ' +
 166+ // JSON.stringify( this.manager.env.KVtoHash( templateTokenTransformData.expandedArgs ) ) );
 167+
148168 this.inputPipeline = this.manager.newChildPipeline(
149169 this.manager.inputType || 'text/wiki',
150 - templateTokenTransformData.expandedArgs,
 170+ this.manager.env.KVtoHash( templateTokenTransformData.expandedArgs ),
151171 templateTokenTransformData.target
152172 );
153173
@@ -299,20 +319,55 @@
300320 * Expand template arguments with tokens from the containing frame.
301321 */
302322 TemplateHandler.prototype.onTemplateArg = function ( token, cb, frame ) {
303 - var argName = token.attribs[0][1]; // XXX: do this properly!
 323+
 324+ var attributes = [[token.argname, token.defaultvalue]];
 325+
 326+ token.resultTokens = false;
 327+
 328+ new AttributeTransformManager(
 329+ this.manager,
 330+ this._returnArgAttributes.bind( this, token, cb, frame )
 331+ ).process( attributes );
 332+
 333+ if ( token.resultTokens !== false ) {
 334+ // synchronous return
 335+ //console.log( 'synchronous attribute expand: ' + JSON.stringify( token.resultTokens ) );
 336+
 337+ return { tokens: token.resultTokens };
 338+ } else {
 339+ //console.log( 'asynchronous attribute expand: ' + JSON.stringify( token, null, 2 ) );
 340+ // asynchronous return
 341+ token.resultTokens = [];
 342+ return { async: true };
 343+ }
 344+};
 345+
 346+TemplateHandler.prototype._returnArgAttributes = function ( token, cb, frame, attributes ) {
 347+ //console.log( '_returnArgAttributes: ' + JSON.stringify( attributes ));
 348+ var argName = this.manager.env.tokensToString( attributes[0][0] ),
 349+ defaultValue = attributes[0][1],
 350+ res;
304351 if ( argName in frame.args ) {
305352 // return tokens for argument
306 - return { tokens: frame.args[argName] };
 353+ //console.log( 'templateArg found: ' + argName +
 354+ // ' vs. ' + JSON.stringify( frame.args ) );
 355+ res = frame.args[argName];
307356 } else {
 357+ //console.log( 'templateArg not found: ' + argName +
 358+ // ' vs. ' + JSON.stringify( frame.args ) );
308359 if ( token.attribs.length > 1 ) {
309 - return token.attribs[1][1]; // default value, XXX: use key
 360+ res = defaultValue;
310361 } else {
311 - return { token: { type: 'TEXT', value: '{{{' + argName + '}}}' } };
 362+ res = [{ type: 'TEXT', value: '{{{' + argName + '}}}' }];
312363 }
313364 }
 365+ if ( token.resultTokens !== false ) {
 366+ cb( res );
 367+ } else {
 368+ token.resultTokens = res;
 369+ }
314370 };
315371
316 -
317372 if (typeof module == "object") {
318373 module.exports.TemplateHandler = TemplateHandler;
319374 }
Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.parser.environment.js
@@ -26,6 +26,18 @@
2727 return null;
2828 };
2929
 30+MWParserEnvironment.prototype.KVtoHash = function ( kvs ) {
 31+ var res = {};
 32+ for ( var i = 0, l = kvs.length; i < l; i++ ) {
 33+ var kv = kvs[i],
 34+ key = this.tokensToString( kv[0] );
 35+ if( res[key] === undefined ) {
 36+ res[key] = kv[1];
 37+ }
 38+ }
 39+ //console.log( 'KVtoHash: ' + JSON.stringify( res ));
 40+ return res;
 41+}
3042
3143 // Does this need separate UI/content inputs?
3244 MWParserEnvironment.prototype.formatNum = function( num ) {

Status & tagging log