www

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

newcommand.js (9527B)


      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/newcommand.js
      7  *  
      8  *  Implements the \newcommand, \newenvironment and \def
      9  *  macros, and is loaded automatically when needed.
     10  *
     11  *  ---------------------------------------------------------------------
     12  *  
     13  *  Copyright (c) 2009-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/newcommand"] = {
     29   version: "2.6.0"
     30 };
     31 
     32 MathJax.Hub.Register.StartupHook("TeX Jax Ready",function () {
     33   
     34   var TEX = MathJax.InputJax.TeX;
     35   var TEXDEF = TEX.Definitions;
     36   
     37   TEXDEF.Add({
     38     macros: {
     39       newcommand:       'NewCommand',
     40       renewcommand:     'NewCommand',
     41       newenvironment:   'NewEnvironment',
     42       renewenvironment: 'NewEnvironment',
     43       def:              'MacroDef',
     44       let:              'Let'
     45     }
     46   },null,true);
     47 
     48   TEX.Parse.Augment({
     49 
     50     /*
     51      *  Implement \newcommand{\name}[n][default]{...}
     52      */
     53     NewCommand: function (name) {
     54       var cs = this.trimSpaces(this.GetArgument(name)),
     55           n  = this.GetBrackets(name),
     56           opt = this.GetBrackets(name),
     57           def = this.GetArgument(name);
     58       if (cs.charAt(0) === "\\") {cs = cs.substr(1)}
     59       if (!cs.match(/^(.|[a-z]+)$/i)) {
     60         TEX.Error(["IllegalControlSequenceName",
     61                    "Illegal control sequence name for %1",name]);
     62       }
     63       if (n) {
     64         n = this.trimSpaces(n);
     65         if (!n.match(/^[0-9]+$/)) {
     66           TEX.Error(["IllegalParamNumber",
     67                      "Illegal number of parameters specified in %1",name]);
     68         }
     69       }
     70       this.setDef(cs,['Macro',def,n,opt]);
     71     },
     72     
     73     /*
     74      *  Implement \newenvironment{name}[n][default]{begincmd}{endcmd}
     75      */
     76     NewEnvironment: function (name) {
     77       var env  = this.trimSpaces(this.GetArgument(name)),
     78           n    = this.GetBrackets(name),
     79           opt  = this.GetBrackets(name),
     80           bdef = this.GetArgument(name),
     81           edef = this.GetArgument(name);
     82       if (n) {
     83         n = this.trimSpaces(n);
     84         if (!n.match(/^[0-9]+$/)) {
     85           TEX.Error(["IllegalParamNumber",
     86                      "Illegal number of parameters specified in %1",name]);
     87         }
     88       }
     89       this.setEnv(env,['BeginEnv',[null,'EndEnv'],bdef,edef,n,opt]);
     90     },
     91     
     92     /*
     93      *  Implement \def command
     94      */
     95     MacroDef: function (name) {
     96       var cs     = this.GetCSname(name),
     97           params = this.GetTemplate(name,"\\"+cs),
     98           def    = this.GetArgument(name);
     99       if (!(params instanceof Array)) {this.setDef(cs,['Macro',def,params])}
    100         else {this.setDef(cs,['MacroWithTemplate',def].concat(params))}
    101     },
    102     
    103     /*
    104      *  Implements the \let command
    105      */
    106     Let: function (name) {
    107       var cs = this.GetCSname(name), macro;
    108       var c = this.GetNext(); if (c === "=") {this.i++; c = this.GetNext()}
    109       //
    110       //  All \let commands create entries in the macros array, but we
    111       //  have to look in the various mathchar and delimiter arrays if
    112       //  the source isn't a macro already, and attach the data to a
    113       //  macro with the proper routine to process it.
    114       //
    115       //  A command of the form \let\cs=char produces a macro equivalent
    116       //  to \def\cs{char}, which is as close as MathJax can get for this.
    117       //  So \let\bgroup={ is possible, but doesn't work as it does in TeX.
    118       //
    119       if (c === "\\") {
    120         name = this.GetCSname(name);
    121         macro = this.csFindMacro(name);
    122         if (!macro) {
    123           if (TEXDEF.mathchar0mi[name])            {macro = ["csMathchar0mi",TEXDEF.mathchar0mi[name]]} else
    124           if (TEXDEF.mathchar0mo[name])            {macro = ["csMathchar0mo",TEXDEF.mathchar0mo[name]]} else
    125           if (TEXDEF.mathchar7[name])              {macro = ["csMathchar7",TEXDEF.mathchar7[name]]}     else 
    126           if (TEXDEF.delimiter["\\"+name] != null) {macro = ["csDelimiter",TEXDEF.delimiter["\\"+name]]}
    127         }
    128       } else {macro = ["Macro",c]; this.i++}
    129       this.setDef(cs,macro);
    130     },
    131     
    132     /*
    133      *  Routines to set the macro and environment definitions
    134      *  (overridden by begingroup to make localized versions)
    135      */
    136     setDef: function (name,value) {value.isUser = true; TEXDEF.macros[name] = value},
    137     setEnv: function (name,value) {value.isUser = true; TEXDEF.environment[name] = value},
    138     
    139     /*
    140      *  Get a CS name or give an error
    141      */
    142     GetCSname: function (cmd) {
    143       var c = this.GetNext();
    144       if (c !== "\\") {
    145         TEX.Error(["MissingCS",
    146                    "%1 must be followed by a control sequence", cmd])
    147       }
    148       var cs = this.trimSpaces(this.GetArgument(cmd));
    149       return cs.substr(1);
    150     },
    151     
    152     /*
    153      *  Get a \def parameter template
    154      */
    155     GetTemplate: function (cmd,cs) {
    156       var c, params = [], n = 0;
    157       c = this.GetNext(); var i = this.i;
    158       while (this.i < this.string.length) {
    159         c = this.GetNext();
    160         if (c === '#') {
    161           if (i !== this.i) {params[n] = this.string.substr(i,this.i-i)}
    162           c = this.string.charAt(++this.i);
    163           if (!c.match(/^[1-9]$/)) {
    164             TEX.Error(["CantUseHash2",
    165                        "Illegal use of # in template for %1",cs]);
    166           }
    167           if (parseInt(c) != ++n) {
    168             TEX.Error(["SequentialParam",
    169                        "Parameters for %1 must be numbered sequentially",cs]);
    170           }
    171           i = this.i+1;
    172         } else if (c === '{') {
    173           if (i !== this.i) {params[n] = this.string.substr(i,this.i-i)}
    174           if (params.length > 0) {return [n,params]} else {return n}
    175         }
    176         this.i++;
    177       }
    178       TEX.Error(["MissingReplacementString",
    179                  "Missing replacement string for definition of %1",cmd]);
    180     },
    181     
    182     /*
    183      *  Process a macro with a parameter template
    184      */
    185     MacroWithTemplate: function (name,text,n,params) {
    186       if (n) {
    187         var args = []; this.GetNext();
    188         if (params[0] && !this.MatchParam(params[0])) {
    189           TEX.Error(["MismatchUseDef",
    190                      "Use of %1 doesn't match its definition",name]);
    191         }
    192         for (var i = 0; i < n; i++) {args.push(this.GetParameter(name,params[i+1]))}
    193         text = this.SubstituteArgs(args,text);
    194       }
    195       this.string = this.AddArgs(text,this.string.slice(this.i));
    196       this.i = 0;
    197       if (++this.macroCount > TEX.config.MAXMACROS) {
    198         TEX.Error(["MaxMacroSub1",
    199                    "MathJax maximum macro substitution count exceeded; " +
    200                    "is there a recursive macro call?"]);
    201       }
    202     },
    203     
    204     /*
    205      *  Process a user-defined environment
    206      */
    207     BeginEnv: function (begin,bdef,edef,n,def) {
    208       if (n) {
    209         var args = [];
    210         if (def != null) {
    211           var optional = this.GetBrackets("\\begin{"+name+"}");
    212           args.push(optional == null ? def : optional);
    213         }
    214         for (var i = args.length; i < n; i++) {args.push(this.GetArgument("\\begin{"+name+"}"))}
    215         bdef = this.SubstituteArgs(args,bdef);
    216         edef = this.SubstituteArgs([],edef); // no args, but get errors for #n in edef
    217       }
    218       this.string = this.AddArgs(bdef,this.string.slice(this.i)); this.i = 0;
    219       return begin;
    220     },
    221     EndEnv: function (begin,bdef,edef,n) {
    222       var end = "\\end{\\end\\"+begin.name+"}"; // special version of \end for after edef
    223       this.string = this.AddArgs(edef,end+this.string.slice(this.i)); this.i = 0;
    224       return null;
    225     },
    226     
    227     /*
    228      *  Find a single parameter delimited by a trailing template
    229      */
    230     GetParameter: function (name,param) {
    231       if (param == null) {return this.GetArgument(name)}
    232       var i = this.i, j = 0, hasBraces = 0;
    233       while (this.i < this.string.length) {
    234         if (this.string.charAt(this.i) === '{') {
    235           if (this.i === i) {hasBraces = 1}
    236           this.GetArgument(name); j = this.i - i;
    237         } else if (this.MatchParam(param)) {
    238           if (hasBraces) {i++; j -= 2}
    239           return this.string.substr(i,j);
    240         } else {
    241           this.i++; j++; hasBraces = 0;
    242         }
    243       }
    244       TEX.Error(["RunawayArgument","Runaway argument for %1?",name]);
    245     },
    246     
    247     /*
    248      *  Check if a template is at the current location.
    249      *  (The match must be exact, with no spacing differences.  TeX is
    250      *   a little more forgiving than this about spaces after macro names)
    251      */
    252     MatchParam: function (param) {
    253       if (this.string.substr(this.i,param.length) !== param) {return 0}
    254       this.i += param.length;
    255       return 1;
    256     }
    257     
    258   });
    259   
    260   TEX.Environment = function (name) {
    261     TEXDEF.environment[name] = ['BeginEnv','EndEnv'].concat([].slice.call(arguments,1));
    262     TEXDEF.environment[name].isUser = true;
    263   }
    264 
    265   MathJax.Hub.Startup.signal.Post("TeX newcommand Ready");
    266 
    267 });
    268 
    269 MathJax.Ajax.loadComplete("[MathJax]/extensions/TeX/newcommand.js");