Annotation of loncom/html/adm/jsMath/extensions/newcommand.js, revision 1.1
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',
! 34: def: 'MacroDef'
! 35: },
! 36:
! 37: /*
! 38: * Implement \newcommand[n]{\name}{...}
! 39: */
! 40: NewCommand: function (name) {
! 41: var n = this.trimSpaces(this.GetBrackets(this.cmd+name)); if (this.error) return;
! 42: var cs = this.trimSpaces(this.GetArgument(this.cmd+name)); if (this.error) return;
! 43: var def = this.GetArgument(this.cmd+name); if (this.error) return;
! 44: if (n == '') {n = null}
! 45: if (cs.charAt(0) == this.cmd) {cs = cs.substr(1)}
! 46: if (!cs.match(/^(.|[a-z]+)$/)) {this.Error("Illegal control sequence name for "+this.cmd+name); return}
! 47: if (n != null && !n.match(/^[0-9]+$/)) {this.Error("Illegal number of parameters specified in "+this.cmd+name); return}
! 48: jsMath.Parser.prototype.macros[cs] = ['Macro',def,n];
! 49: },
! 50:
! 51: /*
! 52: * Implement \def command
! 53: */
! 54: MacroDef: function (name) {
! 55: var cs = this.GetCSname(this.cmd+name); if (this.error) return;
! 56: var params = this.GetTemplate(this.cmd+name); if (this.error) return;
! 57: var def = this.GetArgument(this.cmd+name); if (this.error) return;
! 58: if (typeof(params) == 'number') {
! 59: jsMath.Parser.prototype.macros[cs] = ['Macro',def,params];
! 60: } else {
! 61: jsMath.Parser.prototype.macros[cs] = ['MacroWithTemplate',def,params[0],params[1]];
! 62: }
! 63: },
! 64:
! 65: /*
! 66: * Get a CS name or give an error
! 67: */
! 68: GetCSname: function (cmd) {
! 69: var c = this.GetNext();
! 70: if (c != this.cmd) {this.Error(cmd+" must be followed by a control sequence"); return null}
! 71: var cs = this.trimSpaces(this.GetArgument(cmd)); if (this.error) {return null};
! 72: return cs.substr(1);
! 73: },
! 74:
! 75: /*
! 76: * Get a \def parameter template
! 77: */
! 78: GetTemplate: function (cmd) {
! 79: var c; var params = []; var n = 0;
! 80: c = this.GetNext(); var i = this.i;
! 81: while (this.i < this.string.length) {
! 82: c = this.GetNext();
! 83: if (c == '#') {
! 84: if (i != this.i) {params[n] = this.string.substr(i,this.i-i)}
! 85: c = this.string.charAt(++this.i);
! 86: if (!c.match(/[1-9]/)) {this.Error("Illegal use of # in "+cmd); return null}
! 87: if (1*c != ++n) {this.Error("Parameters must be numbered sequentially"); return null}
! 88: i = this.i+1;
! 89: } else if (c == '{') {
! 90: if (i != this.i) {params[n] = this.string.substr(i,this.i-i)}
! 91: if (params.length > 0) {return [n,params]} else {return n}
! 92: }
! 93: this.i++;
! 94: }
! 95: this.Error("Missing replacement string for definition of "+cmd);
! 96: return null;
! 97: },
! 98:
! 99: /*
! 100: * Process a macro with a parameter template
! 101: */
! 102: MacroWithTemplate: function (name,data) {
! 103: var text = data[0];
! 104: var n = data[1]; var params = data[2];
! 105: if (n) {
! 106: var args = []; var c = this.GetNext();
! 107: if (params[0] && !this.MatchParam(params[0]))
! 108: {this.Error("Use of "+this.cmd+name+" doesn't match its definition"); return}
! 109: for (var i = 0; i < n; i++) {
! 110: args[args.length] = this.GetParameter(this.cmd+name,params[i+1]);
! 111: if (this.error) return;
! 112: }
! 113: text = this.SubstituteArgs(args,text);
! 114: }
! 115: this.string = this.AddArgs(text,this.string.slice(this.i));
! 116: this.i = 0;
! 117: },
! 118:
! 119: /*
! 120: * Find a single parameter delimited by a trailing template
! 121: */
! 122: GetParameter: function (name,param) {
! 123: if (param == null) {return this.GetArgument(name)}
! 124: var i = this.i; var j = 0; var hasBraces = 0;
! 125: while (this.i < this.string.length) {
! 126: if (this.string.charAt(this.i) == '{') {
! 127: if (this.i == i) {hasBraces = 1}
! 128: this.GetArgument(name); j = this.i - i;
! 129: } else if (this.MatchParam(param)) {
! 130: if (hasBraces) {i++; j -= 2}
! 131: return this.string.substr(i,j);
! 132: } else {
! 133: this.i++; j++; hasBraces = 0;
! 134: }
! 135: }
! 136: this.Error("Runaway argument for "+name+"?");
! 137: return null;
! 138: },
! 139:
! 140: /*
! 141: * Check if a template is at the current location.
! 142: * (The match must be exact, with no spacing differences. TeX is
! 143: * a little more forgiving about spaces after macro names)
! 144: */
! 145: MatchParam: function (param) {
! 146: if (this.string.substr(this.i,param.length) != param) {return 0}
! 147: this.i += param.length;
! 148: return 1;
! 149: }
! 150:
! 151: });
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>