Annotation of loncom/html/adm/jsMath/extensions/newcommand.js, revision 1.2

1.1       albertel    1: /*
                      2:  *  extensions/newcommand.js
                      3:  *  
                      4:  *  Part of the jsMath package for mathematics on the web.
                      5:  *
                      6:  *  This file implements the \newcommand and \def macros.  It will be
                      7:  *  loaded automatically when needed, or can be loaded by
                      8:  *  
                      9:  *    jsMath.Extension.Require('newcommand');
                     10:  *
                     11:  *  ---------------------------------------------------------------------
                     12:  *
                     13:  *  Copyright 2005-2006 by Davide P. Cervone
                     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: /********************************************************************/
                     29: 
                     30: jsMath.Package(jsMath.Parser,{
                     31:   
                     32:   macros: {
                     33:     newcommand: 'NewCommand',
1.2     ! albertel   34:     newenvironment: 'NewEnvironment',
1.1       albertel   35:     def: 'MacroDef'
                     36:   },
                     37:   
                     38:   /*
1.2     ! albertel   39:    *  Implement \newcommand{\name}[n]{...}
1.1       albertel   40:    */
                     41:   NewCommand: function (name) {
1.2     ! albertel   42:     var cs = this.trimSpaces(this.GetArgument(this.cmd+name)); if (this.error) return;
1.1       albertel   43:     var n = this.trimSpaces(this.GetBrackets(this.cmd+name)); if (this.error) return;
                     44:     var def = this.GetArgument(this.cmd+name); if (this.error) return;
                     45:     if (n == '') {n = null}
                     46:     if (cs.charAt(0) == this.cmd) {cs = cs.substr(1)}
                     47:     if (!cs.match(/^(.|[a-z]+)$/)) {this.Error("Illegal control sequence name for "+this.cmd+name); return}
                     48:     if (n != null && !n.match(/^[0-9]+$/)) {this.Error("Illegal number of parameters specified in "+this.cmd+name); return}
                     49:     jsMath.Parser.prototype.macros[cs] = ['Macro',def,n];
                     50:   },
                     51:   
                     52:   /*
1.2     ! albertel   53:    *  Implement \newenvironment{name}[n]{begincmd}{endcmd}
        !            54:    */
        !            55:   NewEnvironment: function (name) {
        !            56:     var env = this.trimSpaces(this.GetArgument(this.cmd+name)); if (this.error) return;
        !            57:     var n = this.trimSpaces(this.GetBrackets(this.cmd+name)); if (this.error) return;
        !            58:     var bdef = this.GetArgument(this.cmd+name); if (this.error) return;
        !            59:     var edef = this.GetArgument(this.cmd+name); if (this.error) return;
        !            60:     if (n == '') {n = null}
        !            61:     if (n != null && !n.match(/^[0-9]+$/)) {this.Error("Illegal number of parameters specified in "+this.cmd+name); return}
        !            62:     jsMath.Parser.prototype.environments[env] = ['Environment',bdef,edef,n];
        !            63:   },
        !            64:   
        !            65:   /*
1.1       albertel   66:    *  Implement \def command
                     67:    */
                     68:   MacroDef: function (name) {
                     69:     var cs = this.GetCSname(this.cmd+name); if (this.error) return;
                     70:     var params = this.GetTemplate(this.cmd+name); if (this.error) return;
                     71:     var def = this.GetArgument(this.cmd+name); if (this.error) return;
                     72:     if (typeof(params) == 'number') {
                     73:       jsMath.Parser.prototype.macros[cs] = ['Macro',def,params];
                     74:     } else {
                     75:       jsMath.Parser.prototype.macros[cs] = ['MacroWithTemplate',def,params[0],params[1]];
                     76:     }
                     77:   },
                     78: 
                     79:   /*
                     80:    *  Get a CS name or give an error
                     81:    */
                     82:   GetCSname: function (cmd) {
                     83:     var c = this.GetNext();
                     84:     if (c != this.cmd) {this.Error(cmd+" must be followed by a control sequence"); return null}
                     85:     var cs = this.trimSpaces(this.GetArgument(cmd)); if (this.error) {return null};
                     86:     return cs.substr(1);
                     87:   },
                     88:   
                     89:   /*
                     90:    *  Get a \def parameter template
                     91:    */
                     92:   GetTemplate: function (cmd) {
                     93:     var c; var params = []; var n = 0;
                     94:     c = this.GetNext(); var i = this.i;
                     95:     while (this.i < this.string.length) {
                     96:       c = this.GetNext();
                     97:       if (c == '#') {
                     98:         if (i != this.i) {params[n] = this.string.substr(i,this.i-i)}
                     99:         c = this.string.charAt(++this.i);
                    100:         if (!c.match(/[1-9]/)) {this.Error("Illegal use of # in "+cmd); return null}
                    101:         if (1*c != ++n) {this.Error("Parameters must be numbered sequentially"); return null}
                    102:         i = this.i+1;
                    103:       } else if (c == '{') {
                    104:         if (i != this.i) {params[n] = this.string.substr(i,this.i-i)}
                    105:         if (params.length > 0) {return [n,params]} else {return n}
                    106:       }
                    107:       this.i++;
                    108:     }
                    109:     this.Error("Missing replacement string for definition of "+cmd);
                    110:     return null;
                    111:   },
                    112:   
                    113:   /*
                    114:    *  Process a macro with a parameter template
                    115:    */
                    116:   MacroWithTemplate: function (name,data) {
                    117:     var text = data[0];
                    118:     var n = data[1]; var params = data[2];
                    119:     if (n) {
                    120:       var args = []; var c = this.GetNext();
                    121:       if (params[0] && !this.MatchParam(params[0]))
                    122:         {this.Error("Use of "+this.cmd+name+" doesn't match its definition"); return}
                    123:       for (var i = 0; i < n; i++) {
                    124:         args[args.length] = this.GetParameter(this.cmd+name,params[i+1]);
                    125:         if (this.error) return;
                    126:       }
                    127:       text = this.SubstituteArgs(args,text);
                    128:     }
                    129:     this.string = this.AddArgs(text,this.string.slice(this.i));
                    130:     this.i = 0;
                    131:   },
1.2     ! albertel  132:   
        !           133:   /*
        !           134:    *  Process a user-defined environment
        !           135:    */
        !           136:   Environment: function (name,data) {
        !           137:     var bdef = data[0]; var edef = data[1]; var n = data[2];
        !           138:     if (n) {
        !           139:       var args = [];
        !           140:       for (var i = 0; i < n; i++) {
        !           141:         args[args.length] = this.GetArgument(this.cmd+"begin{"+name+"}"); if (this.error) return;
        !           142:       }
        !           143:       bdef = this.SubstituteArgs(args,bdef);
        !           144:     }
        !           145:     var text = this.GetEnd(name); if (this.error) return;
        !           146:     text = this.AddArgs(this.AddArgs(bdef,text),edef);
        !           147:     this.string = this.AddArgs(text,this.string.slice(this.i));
        !           148:     this.i = 0;
        !           149:   },
1.1       albertel  150: 
                    151:   /*
                    152:    *  Find a single parameter delimited by a trailing template
                    153:    */
                    154:   GetParameter: function (name,param) {
                    155:     if (param == null) {return this.GetArgument(name)}
                    156:     var i = this.i; var j = 0; var hasBraces = 0;
                    157:     while (this.i < this.string.length) {
                    158:       if (this.string.charAt(this.i) == '{') {
                    159:         if (this.i == i) {hasBraces = 1}
                    160:         this.GetArgument(name); j = this.i - i;
                    161:       } else if (this.MatchParam(param)) {
                    162:         if (hasBraces) {i++; j -= 2}
                    163:         return this.string.substr(i,j);
                    164:       } else {
                    165:         this.i++; j++; hasBraces = 0;
                    166:       }
                    167:     }
                    168:     this.Error("Runaway argument for "+name+"?");
                    169:     return null;
                    170:   },
                    171: 
                    172:   /*
                    173:    *  Check if a template is at the current location.
                    174:    *  (The match must be exact, with no spacing differences.  TeX is
                    175:    *   a little more forgiving about spaces after macro names)
                    176:    */
                    177:   MatchParam: function (param) {
                    178:     if (this.string.substr(this.i,param.length) != param) {return 0}
                    179:     this.i += param.length;
                    180:     return 1;
                    181:   }
                    182:   
                    183: });
1.2     ! albertel  184: 
        !           185: /*
        !           186:  *  Define a jsMath.Environment() command similar to the
        !           187:  *  jsMath.Macro() command.
        !           188:  *  
        !           189:  *  Usage:  jsMath.Environment(name,begin,end[,n])
        !           190:  *  
        !           191:  *  where "name" is the name of the environment, "begin" is the
        !           192:  *  text that replaces the \begin{name} and "end" is the text that
        !           193:  *  replaces the \end{name}.  If "n" is provided, it is the number
        !           194:  *  of parameters that the \begin{name} accepts, and these are
        !           195:  *  used to replace #1, #2, etc within the "begin" text.
        !           196:  */
        !           197: 
        !           198: jsMath.Add(jsMath,{
        !           199:   Environment: function (name) {
        !           200:     var environments = jsMath.Parser.prototype.environments;
        !           201:     environments[name] = ['Environment'];
        !           202:     for (var i = 1; i < arguments.length; i++) 
        !           203:       {environments[name][environments[name].length] = arguments[i]}
        !           204:   }
        !           205: });

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>