mediawiki-extensions-Visual.../modules/parser/mediawiki.parser.defines.js
Gabriel Wicke 8368e17d6a Biggish token transform system refactoring
* All parser pipelines including tokenizer and DOM stuff are now constructed
  from a 'recipe' data structure in a ParserPipelineFactory.

* All sub-pipelines of these can now be cached

* Event registrations to a pipeline are directly forwarded to the last
  pipeline member to save relatively expensive event forwarding.

* Some APIs for on-demand expansion / format conversion of parameters from
  parser functions are added:

  param.to('tokens/expanded', cb)
  param.to('text/wiki', cb) (this does not work yet)

  All parameters are additionally wrapped into a Param object that provides
  method for positional parameter naming (.named() or conversion to a dict
  (.dict()).

* The async token transform manager is now separated from a frame object, with
  the frame holding arguments, an on-demand expansion method and loop checks.

* Only keys of template parameters are now expanded. Parser functions or
  template arguments trigger an expansion on-demand. This (unsurprisingly)
  makes a big performance difference with typical switch-heavy template
  systems.

* Return values from async transforms are no longer used in favor of plain
  callbacks. This saves the complication of having to maintain two code paths.
  A trick in transformTokens still avoids the construction of unneeded
  TokenAccumulators.

* The results of template expansions are no longer buffered.

* 301 parser tests are passing

Known issues:

* Cosmetic cleanup remains to do
* Some parser functions do not support async expansions yet, and need to be
  modified.

Change-Id: I1a7690baffbe8141cadf67270904a1b2e1df879a
2012-04-25 16:51:36 +02:00

171 lines
4.2 KiB
JavaScript

/**
* Constructors for different token types. Plain text is represented as simple
* strings or String objects (if attributes are needed).
*/
var toString = function() { return JSON.stringify( this ); };
function TagTk( name, attribs, dataAttribs ) {
//this.type = 'TAG';
this.name = name;
this.attribs = attribs || [];
this.dataAttribs = dataAttribs || {};
}
TagTk.prototype = {};
TagTk.prototype.toJSON = function () {
return $.extend( { type: 'TagTk' }, this );
};
TagTk.prototype.constructor = TagTk;
TagTk.prototype.toString = toString;
function EndTagTk( name, attribs, dataAttribs ) {
this.name = name;
this.attribs = attribs || [];
this.dataAttribs = dataAttribs || {};
}
EndTagTk.prototype = {};
EndTagTk.prototype.toJSON = function () {
return $.extend( { type: 'EndTagTk' }, this );
};
EndTagTk.prototype.constructor = EndTagTk;
EndTagTk.prototype.toString = toString;
function SelfclosingTagTk( name, attribs, dataAttribs ) {
//this.type = 'SELFCLOSINGTAG';
this.name = name;
this.attribs = attribs || [];
this.dataAttribs = dataAttribs || {};
}
SelfclosingTagTk.prototype = {};
SelfclosingTagTk.prototype.toJSON = function () {
return $.extend( { type: 'SelfclosingTagTk' }, this );
};
SelfclosingTagTk.prototype.constructor = SelfclosingTagTk;
SelfclosingTagTk.prototype.toString = toString;
function NlTk( ) {
//this.type = 'NEWLINE';
}
NlTk.prototype = {};
NlTk.prototype.toJSON = function () {
return $.extend( { type: 'NlTk' }, this );
};
NlTk.prototype.constructor = NlTk;
NlTk.prototype.toString = toString;
function CommentTk( value ) {
this.value = value;
}
CommentTk.prototype = {};
CommentTk.prototype.toJSON = function () {
return $.extend( { type: 'COMMENT' }, this );
};
CommentTk.prototype.constructor = CommentTk;
CommentTk.prototype.toString = toString;
function EOFTk( ) { }
EOFTk.prototype = {};
EOFTk.prototype.toJSON = function () {
return $.extend( { type: 'EOFTk' }, this );
};
EOFTk.prototype.constructor = EOFTk;
EOFTk.prototype.toString = toString;
// A key-value pair
function KV ( k, v ) {
this.k = k;
this.v = v;
}
/**
* A parameter object wrapper, essentially an array of key/value pairs with a
* few extra methods.
*
* It might make sense to wrap array results of array methods such as slice
* into a params object too, so that users are not surprised by losing the
* custom methods. Alternatively, the object could be made more abstract with
* a separate .array method that just returns the plain array.
*/
function Params ( env, params ) {
this.env = env;
this.push.apply( this, params );
}
Params.prototype = [];
Params.prototype.constructor = Params;
Params.prototype.toString = function () {
return this.slice(0).toString();
};
Params.prototype.dict = function () {
var res = {};
for ( var i = 0, l = this.length; i < l; i++ ) {
var kv = this[i],
key = this.env.tokensToString( kv.k ).trim();
res[key] = kv.v;
}
//console.warn( 'KVtoHash: ' + JSON.stringify( res ));
return res;
};
Params.prototype.named = function () {
var n = 1,
out = {};
for ( var i = 0, l = this.length; i < l; i++ ) {
// FIXME: Also check for whitespace-only named args!
var k = this[i].k;
if ( k.constructor === String ) {
k = k.trim();
}
if ( ! k.length ) {
out[n.toString()] = this[i].v;
n++;
} else if ( k.constructor === String ) {
out[k] = this[i].v;
} else {
out[this.env.tokensToString( k ).trim()] = this[i].v;
}
}
return out;
};
function ParamValue ( chunk, manager ) {
this.chunk = chunk;
this.manager = manager;
this.cache = {};
}
ParamValue.prototype.expanded = function ( format, cb ) {
if ( format === tokens ) {
if ( this.cache.tokens ) {
cb( this.cache.tokens );
} else {
var pipeline = this.manager.pipeFactory.getPipeline(
this.manager.attributeType || 'tokens/wiki', true
);
pipeline.setFrame( this.manager.frame, null );
}
} else {
throw "ParamValue.expanded: Unsupported format " + format;
}
};
if (typeof module == "object") {
module.exports = {};
global.TagTk = TagTk;
global.EndTagTk = EndTagTk;
global.SelfclosingTagTk = SelfclosingTagTk;
global.NlTk = NlTk;
global.CommentTk = CommentTk;
global.EOFTk = EOFTk;
global.KV = KV;
global.Params = Params;
}