www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

begingroup.js (9758B)


      1 /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 
      4 /*************************************************************
      5  *
      6  *  MathJax/extensions/TeX/begingroup.js
      7  *  
      8  *  Implements \begingroup and \endgroup commands that make local 
      9  *  definitions possible and are removed when the \endgroup occurs.  
     10  *
     11  *  ---------------------------------------------------------------------
     12  *  
     13  *  Copyright (c) 2011-2015 The MathJax Consortium
     14  * 
     15  *  Licensed under the Apache License, Version 2.0 (the "License");
     16  *  you may not use this file except in compliance with the License.
     17  *  You may obtain a copy of the License at
     18  * 
     19  *      http://www.apache.org/licenses/LICENSE-2.0
     20  * 
     21  *  Unless required by applicable law or agreed to in writing, software
     22  *  distributed under the License is distributed on an "AS IS" BASIS,
     23  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     24  *  See the License for the specific language governing permissions and
     25  *  limitations under the License.
     26  */
     27 
     28 MathJax.Extension["TeX/begingroup"] = {
     29   version: "2.6.0"
     30 };
     31 
     32 MathJax.Hub.Register.StartupHook("TeX Jax Ready",function () {
     33 
     34   var TEX = MathJax.InputJax.TeX,
     35       TEXDEF = TEX.Definitions;
     36 
     37   /****************************************************/
     38 
     39   //
     40   //  A namespace for localizing macros and environments
     41   //  (\begingroup and \endgroup create and destroy these)
     42   //
     43   var NSFRAME = MathJax.Object.Subclass({
     44     macros: null,         // the local macro definitions
     45     environments: null,   // the local environments
     46     Init: function (macros,environments) {
     47       this.macros = (macros || {});
     48       this.environments = (environments || {});
     49     },
     50     //
     51     //  Find a macro or environment by name
     52     //
     53     Find: function (name,type) {if (this[type][name]) {return this[type][name]}},
     54     //
     55     //  Define or remove a macro or environment
     56     //
     57     Def: function (name,value,type) {this[type][name] = value},
     58     Undef: function (name,type) {delete this[type][name]},
     59     //
     60     //  Merge two namespaces (used when the equation namespace is combined with the root one)
     61     //
     62     Merge: function (frame) {
     63       MathJax.Hub.Insert(this.macros,frame.macros);
     64       MathJax.Hub.Insert(this.environments,frame.environments);
     65     },
     66     //
     67     //  Move global macros to the stack (globally) and remove from the frame
     68     //
     69     MergeGlobals: function (stack) {
     70       var macros = this.macros;
     71       for (var cs in macros) {if (macros.hasOwnProperty(cs) && macros[cs].global) {
     72         stack.Def(cs,macros[cs],"macros",true);
     73         delete macros[cs].global; delete macros[cs];
     74       }}
     75     },
     76     //
     77     //  Clear the macro and environment lists
     78     //  (but not global macros unless "all" is true)
     79     //
     80     Clear: function (all) {
     81       this.environments = {};
     82       if (all) {this.macros = {}} else {
     83         var macros = this.macros;
     84         for (var cs in macros) {
     85           if (macros.hasOwnProperty(cs) && !macros[cs].global) {delete macros[cs]}
     86         }
     87       }
     88       return this;
     89     }
     90   });
     91 
     92   /****************************************************/
     93 
     94   //
     95   //  A Stack of namespace frames
     96   //
     97   var NSSTACK = TEX.nsStack = MathJax.Object.Subclass({
     98     stack: null,         // the namespace frames
     99     top: 0,              // the current top one (we don't pop for real until the equation completes)
    100     isEqn: false,        // true if this is the equation stack (not the global one)
    101     //
    102     //  Set up the initial stack frame
    103     //
    104     Init: function (eqn) {
    105       this.isEqn = eqn; this.stack = [];
    106       if (!eqn) {this.Push(NSFRAME(TEXDEF.macros,TEXDEF.environment))}
    107            else {this.Push(NSFRAME())}
    108     },
    109     //
    110     //  Define a macro or environment in the top frame
    111     //
    112     Def: function (name,value,type,global) {
    113       var n = this.top-1;
    114       if (global) {
    115         //
    116         //  Define global macros in the base frame and remove that cs
    117         //  from all other frames.  Mark the global ones in equations
    118         //  so they can be made global when merged with the root stack.
    119         //
    120         while (n > 0) {this.stack[n].Undef(name,type); n--}
    121         if (!(value instanceof Array)) {value = [value]}
    122         if (this.isEqn) {value.global = true}
    123       }
    124       this.stack[n].Def(name,value,type);
    125     },
    126     //
    127     //  Push a new namespace frame on the stack
    128     //
    129     Push: function (frame) {
    130       this.stack.push(frame);
    131       this.top = this.stack.length;
    132     },
    133     //
    134     //  Pop the top stack frame
    135     //  (if it is the root, just keep track of the pop so we can
    136     //   reset it if the equation is reprocessed)
    137     //
    138     Pop: function () {
    139       var top;
    140       if (this.top > 1) {
    141         top = this.stack[--this.top];
    142         if (this.isEqn) {this.stack.pop()}
    143       } else if (this.isEqn) {
    144         this.Clear();
    145       }
    146       return top;
    147     },
    148     //
    149     //  Search the stack from top to bottom for the first
    150     //    definition of the given control sequence in the given type
    151     //
    152     Find: function (name,type) {
    153       for (var i = this.top-1; i >= 0; i--) {
    154         var def = this.stack[i].Find(name,type);
    155         if (def) {return def}
    156       }
    157       return null;
    158     },
    159     //
    160     //  Combine the equation stack with the global one
    161     //  (The bottom frame of the equation goes with the top frame of the global one,
    162     //   and the remainder are pushed on the global stack, truncated to the
    163     //   position where items were poped from it.)
    164     //
    165     Merge: function (stack) {
    166       stack.stack[0].MergeGlobals(this);
    167       this.stack[this.top-1].Merge(stack.stack[0]);
    168       var data = [this.top,this.stack.length-this.top].concat(stack.stack.slice(1));
    169       this.stack.splice.apply(this.stack,data);
    170       this.top = this.stack.length;
    171     },
    172     //
    173     //  Put back the temporarily poped items
    174     //
    175     Reset: function () {this.top = this.stack.length},
    176     //
    177     //  Clear the stack and start with a blank frame
    178     //
    179     Clear: function (all) {
    180       this.stack = [this.stack[0].Clear()];
    181       this.top = this.stack.length;
    182     }
    183   },{
    184     nsFrame: NSFRAME
    185   });
    186 
    187   /****************************************************/
    188 
    189   //
    190   //  Define the new macros
    191   //
    192   TEXDEF.Add({
    193     macros: {
    194       begingroup: "BeginGroup",
    195       endgroup:   "EndGroup",
    196       global:     ["Extension","newcommand"],
    197       gdef:       ["Extension","newcommand"]
    198     }
    199   },null,true);
    200   
    201   TEX.Parse.Augment({
    202     //
    203     //  Implement \begingroup
    204     //
    205     BeginGroup: function (name) {
    206       TEX.eqnStack.Push(NSFRAME());
    207     },
    208     //
    209     //  Implements \endgroup
    210     //
    211     EndGroup: function (name) {
    212       //
    213       //  If the equation has pushed frames, pop one,
    214       //  Otherwise clear the equation stack and pop the top global one
    215       //
    216       if (TEX.eqnStack.top > 1) {
    217         TEX.eqnStack.Pop();
    218       } else if (TEX.rootStack.top === 1) {
    219         TEX.Error(["ExtraEndMissingBegin","Extra %1 or missing \\begingroup",name]);
    220       } else {
    221         TEX.eqnStack.Clear();
    222         TEX.rootStack.Pop();
    223       }
    224     },
    225 
    226     //
    227     //  Replace the original routines with ones that looks through the
    228     //  equation and root stacks for the given name
    229     //  
    230     csFindMacro: function (name) {
    231       return (TEX.eqnStack.Find(name,"macros") || TEX.rootStack.Find(name,"macros"));
    232     },
    233     envFindName: function (name) {
    234       return (TEX.eqnStack.Find(name,"environments") || TEX.rootStack.Find(name,"environments"));
    235     }
    236 
    237   });
    238 
    239   /****************************************************/
    240 
    241   TEX.rootStack = NSSTACK();         // the global namespace stack
    242   TEX.eqnStack  = NSSTACK(true);     // the equation stack
    243 
    244   //
    245   //  Reset the global stack and clear the equation stack
    246   //  (this gets us back to the initial stack state as it was
    247   //   before the equation was first processed, in case the equation
    248   //   get restarted due to an autoloaded file)
    249   //
    250   TEX.prefilterHooks.Add(function () {TEX.rootStack.Reset(); TEX.eqnStack.Clear(true)});
    251   
    252   //
    253   //  We only get here if there were no errors and the equation is fully
    254   //  processed (all restarts are complete).  So we merge the equation
    255   //  stack into the global stack, thus making the changes from this
    256   //  equation permanent.
    257   //
    258   TEX.postfilterHooks.Add(function () {TEX.rootStack.Merge(TEX.eqnStack)});
    259   
    260   /*********************************************************/
    261 
    262   MathJax.Hub.Register.StartupHook("TeX newcommand Ready",function () {
    263 
    264     //
    265     //  Add the commands that depend on the newcommand code
    266     //
    267     TEXDEF.Add({
    268       macros: {
    269         global: "Global",
    270         gdef:   ["Macro","\\global\\def"]
    271       }
    272     },null,true);
    273 
    274     TEX.Parse.Augment({
    275       //
    276       //  Modify the way macros and environments are defined
    277       //  to make them go into the equation namespace stack
    278       //
    279       setDef: function (name,value) {
    280         value.isUser = true;
    281         TEX.eqnStack.Def(name,value,"macros",this.stack.env.isGlobal);
    282         delete this.stack.env.isGlobal;
    283       },
    284       setEnv: function (name,value) {
    285         value.isUser = true;
    286         TEX.eqnStack.Def(name,value,"environments")
    287       },
    288 
    289       //
    290       //  Implement \global (for \global\let, \global\def and \global\newcommand)
    291       //
    292       Global: function (name) {
    293         var i = this.i; var cs = this.GetCSname(name); this.i = i;
    294         if (cs !== "let" && cs !== "def" && cs !== "newcommand") {
    295           TEX.Error(["GlobalNotFollowedBy",
    296                      "%1 not followed by \\let, \\def, or \\newcommand",name]);
    297         }
    298         this.stack.env.isGlobal = true;
    299       }
    300 
    301     });
    302 
    303   });
    304 
    305   MathJax.Hub.Startup.signal.Post("TeX begingroup Ready");
    306 
    307 });
    308 
    309 MathJax.Ajax.loadComplete("[MathJax]/extensions/TeX/begingroup.js");