https://www.mediawiki.org/wiki/Special:Code/MediaWiki/113620

Revision: 113620
Author:   gwicke
Date:     2012-03-12 13:08:43 +0000 (Mon, 12 Mar 2012)
Log Message:
-----------
Refactor syntactic stops into an object and add a stack variant for option
values.

Modified Paths:
--------------
    trunk/extensions/VisualEditor/modules/parser/mediawiki.tokenizer.peg.js
    trunk/extensions/VisualEditor/modules/parser/pegTokenizer.pegjs.txt

Modified: 
trunk/extensions/VisualEditor/modules/parser/mediawiki.tokenizer.peg.js
===================================================================
--- trunk/extensions/VisualEditor/modules/parser/mediawiki.tokenizer.peg.js     
2012-03-12 13:07:50 UTC (rev 113619)
+++ trunk/extensions/VisualEditor/modules/parser/mediawiki.tokenizer.peg.js     
2012-03-12 13:08:43 UTC (rev 113620)
@@ -103,48 +103,46 @@
  * Those inner productions are then exited, so that the outer production can
  * handle the end marker.
  */
-PegTokenizer.prototype.inline_breaks = function (input, pos, syntaxFlags ) {
+PegTokenizer.prototype.inline_breaks = function (input, pos, stops ) {
+       var counters = stops.counters;
        switch( input[pos] ) {
                case '=':
-                       return ( syntaxFlags.equalAttrib && 
-                                       (syntaxFlags.equalTemplate || ! 
syntaxFlags.template ) ) ||
-                               (syntaxFlags.equalTemplate && 
-                                (syntaxFlags.equalAttrib || 
syntaxFlags.template)) ||
-                               ( syntaxFlags.h &&
+                       return stops.onStack( 'equal' ) ||
+                               ( counters.h &&
                                  input.substr( pos + 1, 200)
                                  .match(/[ \t]*[\r\n]/) !== null ) || null;
                case '|':
-                       return syntaxFlags.pipe ||
-                                       syntaxFlags.template ||
-                               ( syntaxFlags.table &&
+                       return counters.pipe ||
+                                       counters.template ||
+                               ( counters.table &&
                                  ( input[pos + 1].match(/[|}]/) !== null ||
-                                       syntaxFlags.tableCellArg
+                                       counters.tableCellArg
                                  ) 
                                ) || null;
                case "!":
-                       return syntaxFlags.table && input[pos + 1] === "!" ||
+                       return counters.table && input[pos + 1] === "!" ||
                                null;
                case "}":
-                       return syntaxFlags.template && input[pos + 1] === "}" 
|| null;
+                       return counters.template && input[pos + 1] === "}" || 
null;
                case ":":
-                       return syntaxFlags.colon &&
-                               ! syntaxFlags.extlink &&
-                               ! syntaxFlags.linkdesc || null;
+                       return counters.colon &&
+                               ! counters.extlink &&
+                               ! counters.linkdesc || null;
                case "\r":
-                       return syntaxFlags.table &&
+                       return counters.table &&
                                input.substr(pos, 4).match(/\r\n?[!|]/) !== 
null ||
                                null;
                case "\n":
-                       return syntaxFlags.table &&
+                       return counters.table &&
                                input[pos + 1] === '!' ||
                                input[pos + 1] === '|' ||
                                null;
                case "]":
-                       return syntaxFlags.extlink ||
-                               ( syntaxFlags.linkdesc && input[pos + 1] === 
']' ) ||
+                       return counters.extlink ||
+                               ( counters.linkdesc && input[pos + 1] === ']' ) 
||
                                null;
                case "<":
-                       return syntaxFlags.pre &&  input.substr( pos, 6 ) === 
'</pre>' || null;
+                       return counters.pre &&  input.substr( pos, 6 ) === 
'</pre>' || null;
                default:
                        return null;
        }

Modified: trunk/extensions/VisualEditor/modules/parser/pegTokenizer.pegjs.txt
===================================================================
--- trunk/extensions/VisualEditor/modules/parser/pegTokenizer.pegjs.txt 
2012-03-12 13:07:50 UTC (rev 113619)
+++ trunk/extensions/VisualEditor/modules/parser/pegTokenizer.pegjs.txt 
2012-03-12 13:08:43 UTC (rev 113620)
@@ -271,20 +271,58 @@
      * productions can just be unrolled for all combinations of environments
      * at the cost of a much larger grammar.
      */
-    var syntaxFlags = {};
-    var setFlag = function(flag) {
-        if (syntaxFlags[flag] !== undefined) {
-            syntaxFlags[flag]++;
+    function SyntaxStops () {
+        this.counters = {};
+        this.stacks = {};
+    }
+    SyntaxStops.prototype.inc = function(flag) {
+        if (this.counters[flag] !== undefined) {
+            this.counters[flag]++;
         } else {
-            syntaxFlags[flag] = 1;
+            this.counters[flag] = 1;
         }
         return true;
     };
-    var clearFlag = function(flag) {
-        syntaxFlags[flag]--;
+    SyntaxStops.prototype.dec = function(flag) {
+        this.counters[flag]--;
         return false;
     };
+    SyntaxStops.prototype.onCount = function ( name ) {
+        return this.counters[name];
+    };
 
+    /**
+     * A stack for nested, but not cumulative syntactic stops.
+     * Example: '=' is allowed in values of template arguments, even if those
+     * are nested in attribute names.
+     */
+    SyntaxStops.prototype.push = function ( name, value ) {
+        if( this.stacks[name] === undefined ) {
+            this.stacks[name] = [value];
+        } else {
+            this.stacks[name].push( value );
+        }
+        return true;
+    };
+    SyntaxStops.prototype.pop = function ( name ) {
+        if( this.stacks[name] !== undefined ) {
+            this.stacks[name].pop();
+        } else {
+            throw "SyntaxStops.pop: unknown stop for " + name;
+        }
+        return false;
+    };
+    SyntaxStops.prototype.onStack = function ( name ) {
+        var stack = this.stacks[name];
+        if ( stack === undefined || stack.length === 0 ) {
+            return false;
+        } else {
+            return stack[stack.length - 1];
+        }
+    };
+
+    var stops = new SyntaxStops();
+
     // Start position of top-level block
     // Could also provide positions for lower-level blocks using a stack.
     var blockStart = 0;
@@ -472,7 +510,7 @@
         // cache key does not take into account flag states!
         cacheKey = ''; 
         //console.warn('ilbf: ' + input.substr(pos, 5) );
-        return null !== __parseArgs[3].inline_breaks( input, pos, syntaxFlags )
+        return null !== __parseArgs[3].inline_breaks( input, pos, stops )
       } 
 
 inline
@@ -504,13 +542,13 @@
           // XXX: Also check to end to avoid inline parsing?
     r:(
      s:'='+ // moved in here to make s accessible to inner action
-     & { return setFlag('h'); }
+     & { return stops.inc('h'); }
      c:inlineline 
      e:'='+ 
      spc:(sp:space+ { return sp.join('') } / comment)*
      &eolf 
      {
-        clearFlag('h');
+        stops.dec('h');
         var level = Math.min(s.length, e.length);
         // convert surplus equals into text
         if(s.length > level) {
@@ -534,7 +572,7 @@
         return [new TagTk( 'h' + level )]
                 .concat(c, [new EndTagTk( 'h' + level ), spc]);
       }
-    / & { /* dp('nomatch exit h'); */ clearFlag('h'); return false } { return 
null }
+    / & { /* dp('nomatch exit h'); */ stops.dec('h'); return false } { return 
null }
     ) { return r }
 
 comment
@@ -554,22 +592,22 @@
  **************************************************************/
 
 urllink
-  = ! { return syntaxFlags['extlink'] }
+  = ! { return stops.onCount('extlink') }
     target:url {
       return [ new TagTk( 'urllink', [new KV('href', target)] ) ];
   }
 
 extlink
-  = ! { return syntaxFlags['extlink'] } // extlink cannot be nested
+  = ! { return stops.onCount('extlink') } // extlink cannot be nested
     (
         "[" 
-        & { return setFlag('extlink'); }
+        & { return stops.inc('extlink'); }
         //target:urllink
         target:extlink_preprocessor_text
         text:(( space / [\u00A0\u1680\u180E\u2000-\u200A\u202F\u205F\u3000] )* 
               t:inlineline { return t } )?
         "]" {
-            clearFlag('extlink');
+            stops.dec('extlink');
             if ( text === '' ) {
                 // XXX: Link numbering should be implemented in post-processor.
                 text = [ "[" + linkCount + "]" ];
@@ -583,7 +621,7 @@
                 ] )
             ];
         }
-      / "[" & { clearFlag('extlink'); return false; }
+      / "[" & { stops.dec('extlink'); return false; }
     )
 
 /* Defaul URL protocols in MediaWiki (see DefaultSettings). Normally these can
@@ -706,7 +744,7 @@
     s0:space* 
     eq:"="?
     s1:space*
-    value:template_param_text?
+    value:template_param_value?
 
     {
       //console.warn( 'named template_param matched' + pp([name, value ]) );
@@ -724,25 +762,35 @@
 
 // FIXME: handle template args and templates in key! (or even parser 
functions?)
 template_param_name
-  = & { return setFlag( 'equalTemplate' ) }
+  = & { return stops.push( 'equal', true ) }
     tpt:template_param_text
     {
-        clearFlag( 'equalTemplate' );
+        stops.pop( 'equal' );
         //console.warn( 'template param name matched: ' + pp( tpt ) );
         return tpt;
     }
 
-  / & { return clearFlag( 'equalTemplate' ) }
+  / & { return stops.pop( 'equal' ) }
   //= h:( !"}}" x:([^=|\n]) { return x } )* { return h.join(''); }
 
+template_param_value
+  = & { return stops.push( 'equal', false ) }
+    tpt:template_param_text
+    {
+        stops.pop( 'equal' );
+        //console.warn( 'template param value matched: ' + pp( tpt ) );
+        return tpt;
+    }
+  / & { return stops.pop( 'equal' ) }
+
 template_param_text
-  = & { return setFlag('template') }
+  = & { return stops.inc('template') }
     il:inline {
-        clearFlag('template');
+        stops.dec('template');
         //console.warn( 'tpt match: ' + pp (il));
         return il;
     }
-  / & { return clearFlag('template'); }
+  / & { return stops.dec('template'); }
 
 
 // TODO: handle link prefixes as in al[[Razi]]
@@ -790,39 +838,39 @@
   / ! { return posStack.pop( 'wikilink', pos ); }
 
 link_text
-  = & { return setFlag('linkdesc'); }
+  = & { return stops.inc('linkdesc'); }
     h:inline 
     // 'equal' syntaxFlag is set for links in template parameters. Consume the
     // '=' here.
     hs:( '=' inline)?
     { 
         //console.warn('link_text' + pp(h) + pp(hs));
-        clearFlag('linkdesc');
+        stops.dec('linkdesc');
         if( hs !== '' ) {
             return h.concat(hs);
         } else {
             return h;
         }
     }
-  / & { return clearFlag('linkdesc'); }
+  / & { return stops.dec('linkdesc'); }
 
 link_option
-  = & { setFlag('pipe'); return setFlag('linkdesc'); }
+  = & { stops.inc('pipe'); return stops.inc('linkdesc'); }
     h:inline 
     // 'equal' syntaxFlag is set for links in template parameters. Consume the
     // '=' here.
     hs:( '=' inline)?
     { 
         //console.warn('link_text' + pp(h) + pp(hs));
-        clearFlag('pipe');
-        clearFlag('linkdesc');
+        stops.dec('pipe');
+        stops.dec('linkdesc');
         if( hs !== '' ) {
             return h.concat(hs);
         } else {
             return h;
         }
     }
-  / & { clearFlag('pipe'); return clearFlag('linkdesc'); }
+  / & { stops.dec('pipe'); return stops.dec('linkdesc'); }
 
 link_end = "]]"
 
@@ -845,9 +893,9 @@
  * transformer, and only for images.
  */
 img_options = 
-  & { return setFlag( 'pipe' ); }
+  & { return stops.inc( 'pipe' ); }
   os:img_option* {
-    clearFlag( 'pipe' );
+    stops.dec( 'pipe' );
        var options = {};
     os = flatten( os );
        for ( var i = 0, l = os.length; i < l; i++ ) {
@@ -857,7 +905,7 @@
        options._options = os;
        return options;
 }
-/ & { return clearFlag( 'pipe' ); }
+/ & { return stops.dec( 'pipe' ); }
 
 img_option 
   = "|" space*
@@ -909,10 +957,10 @@
   = 'link=' space* 
     u:( 
         t:url {
-            clearFlag( 'pipe' );
+            stops.dec( 'pipe' );
             return t;
         }
-        / & { return clearFlag( 'pipe' ); }
+        / & { return stops.dec( 'pipe' ); }
       ) 
 {
       return new KV( 'link', u );
@@ -946,16 +994,16 @@
     "<pre" 
     attribs:generic_attribute* 
     ">"
-    & { return setFlag('pre'); }
+    & { return stops.inc('pre'); }
     l:inlineline
     ls:(sol pre_indent_line)*
     "</pre>"
   {   
-    clearFlag('pre');
+    stops.dec('pre');
     return [ new TagTk( 'pre', attribs ) ]
         .concat( l, flatten( ls ), [ new EndTagTk( 'pre' ) ] );
   }
-  / & { return clearFlag('pre'); }
+  / & { return stops.dec('pre'); }
 
 pre_indent_line = space l:inlineline { 
     return [ '\n' ].concat(l); 
@@ -1140,15 +1188,15 @@
 //  }
 
 generic_attribute_name
-  = & { return setFlag( 'equalAttrib' ) }
+  = & { return stops.push( 'equal', true ) }
   ! '/>'
   name:attribute_preprocessor_text_line
     {
-        clearFlag( 'equalAttrib' );
+        stops.pop( 'equal' );
         //console.warn( 'generic attribute name: ' + pp( name ) );
         return name;
     }
-  / & { return clearFlag( 'equalAttrib' ) }
+  / & { return stops.pop( 'equal' ) }
 
 // A generic attribute, possibly spanning multiple lines.
 generic_attribute_newline_value
@@ -1226,12 +1274,12 @@
 dtdd 
   = bullets:(!(";" !list_char) list_char)*
     ";"
-    & {return setFlag('colon');}
+    & {return stops.inc('colon');}
     c:inlineline
     ":"
     // Fortunately dtdds cannot be nested, so we can simply set the flag
     // back to 0 to disable it.
-    & {syntaxFlags['colon'] = 0; return true;}
+    & { stops.counters['colon'] = 0; return true;}
     d:inlineline
     &eolf {
         // Convert trailing space into &nbsp;
@@ -1251,7 +1299,7 @@
         return [ li ].concat( c, [ li2 ], d );
     }
   // Fall-back case to clear the colon flag
-  / & { return true; } { syntaxFlags['colon'] = 0; return null; }
+  / & { return true; } { stops.counters['colon'] = 0; return null; }
 
 
 list_char = [*#:;]
@@ -1272,14 +1320,14 @@
  *********************************************************************/
 
 table_lines
-  = & { return setFlag('table'); }
+  = & { return stops.inc('table'); }
     tl:table_line 
     tls:( s:sol tl2:table_line { return s.concat(tl2); } )* {
-        clearFlag('table');
+        stops.dec('table');
         //console.warn('table_lines: ' + pp(tl.concat(tls)));
         return tl.concat( tls );
     }
-  / & { return clearFlag('table'); }
+  / & { return stops.dec('table'); }
 
 // This production assumes start-of-line position!
 table_line
@@ -1380,12 +1428,12 @@
   }
 
 table_cell_args
-  = & { return setFlag('tableCellArg'); }
+  = & { return stops.inc('tableCellArg'); }
     as:generic_attribute* space* "|" !"|" { 
-        clearFlag('tableCellArg');
+        stops.dec('tableCellArg');
         return as;
     }
-    / & { return clearFlag('tableCellArg'); }
+    / & { return stops.dec('tableCellArg'); }
 
 
 
@@ -1417,13 +1465,13 @@
 table_start 
   = "{" pipe
     res:(
-        & { setFlag('table'); return true; }
+        & { stops.inc('table'); return true; }
         ta:generic_attribute* 
         { 
             //dp("table_start " + pp(ta) + ", pos:" + pos);
             return ta;
         }
-        / & { clearFlag('table'); return false; } { return null; }
+        / & { stops.dec('table'); return false; } { return null; }
     ) { return res }
 
 table_caption 
@@ -1502,7 +1550,7 @@
 
 table_end 
   = nt:newlineToken? ( pipe "}" / eof ) { 
-         clearFlag('table'); 
+         stops.dec('table'); 
          if(nt) 
                  return nt;
          else


_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs

Reply via email to