X-Git-Url: http://lambda.jimpryor.net/git/gitweb.cgi?a=blobdiff_plain;f=jsMath%2Fextensions%2Fnewcommand.js;fp=jsMath%2Fextensions%2Fnewcommand.js;h=d2302228a5bbb1d87ed7052abd9461631f83666d;hb=f084723ab17e56d39e05a8a8da8d976e670dfd42;hp=0000000000000000000000000000000000000000;hpb=b3b3c1c988e48e53f295529431d640528bb17927;p=lambda.git diff --git a/jsMath/extensions/newcommand.js b/jsMath/extensions/newcommand.js new file mode 100644 index 00000000..d2302228 --- /dev/null +++ b/jsMath/extensions/newcommand.js @@ -0,0 +1,205 @@ +/* + * extensions/newcommand.js + * + * Part of the jsMath package for mathematics on the web. + * + * This file implements the \newcommand and \def macros. It will be + * loaded automatically when needed, or can be loaded by + * + * jsMath.Extension.Require('newcommand'); + * + * --------------------------------------------------------------------- + * + * Copyright 2005-2006 by Davide P. Cervone + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/********************************************************************/ + +jsMath.Package(jsMath.Parser,{ + + macros: { + newcommand: 'NewCommand', + newenvironment: 'NewEnvironment', + def: 'MacroDef' + }, + + /* + * Implement \newcommand{\name}[n]{...} + */ + NewCommand: function (name) { + var cs = this.trimSpaces(this.GetArgument(this.cmd+name)); if (this.error) return; + var n = this.trimSpaces(this.GetBrackets(this.cmd+name)); if (this.error) return; + var def = this.GetArgument(this.cmd+name); if (this.error) return; + if (n == '') {n = null} + if (cs.charAt(0) == this.cmd) {cs = cs.substr(1)} + if (!cs.match(/^(.|[a-z]+)$/i)) {this.Error("Illegal control sequence name for "+this.cmd+name); return} + if (n != null && !n.match(/^[0-9]+$/)) {this.Error("Illegal number of parameters specified in "+this.cmd+name); return} + jsMath.Parser.prototype.macros[cs] = ['Macro',def,n]; + }, + + /* + * Implement \newenvironment{name}[n]{begincmd}{endcmd} + */ + NewEnvironment: function (name) { + var env = this.trimSpaces(this.GetArgument(this.cmd+name)); if (this.error) return; + var n = this.trimSpaces(this.GetBrackets(this.cmd+name)); if (this.error) return; + var bdef = this.GetArgument(this.cmd+name); if (this.error) return; + var edef = this.GetArgument(this.cmd+name); if (this.error) return; + if (n == '') {n = null} + if (n != null && !n.match(/^[0-9]+$/)) {this.Error("Illegal number of parameters specified in "+this.cmd+name); return} + jsMath.Parser.prototype.environments[env] = ['Environment',bdef,edef,n]; + }, + + /* + * Implement \def command + */ + MacroDef: function (name) { + var cs = this.GetCSname(this.cmd+name); if (this.error) return; + var params = this.GetTemplate(this.cmd+name); if (this.error) return; + var def = this.GetArgument(this.cmd+name); if (this.error) return; + if (typeof(params) == 'number') { + jsMath.Parser.prototype.macros[cs] = ['Macro',def,params]; + } else { + jsMath.Parser.prototype.macros[cs] = ['MacroWithTemplate',def,params[0],params[1]]; + } + }, + + /* + * Get a CS name or give an error + */ + GetCSname: function (cmd) { + var c = this.GetNext(); + if (c != this.cmd) {this.Error(cmd+" must be followed by a control sequence"); return null} + var cs = this.trimSpaces(this.GetArgument(cmd)); if (this.error) {return null}; + return cs.substr(1); + }, + + /* + * Get a \def parameter template + */ + GetTemplate: function (cmd) { + var c; var params = []; var n = 0; + c = this.GetNext(); var i = this.i; + while (this.i < this.string.length) { + c = this.GetNext(); + if (c == '#') { + if (i != this.i) {params[n] = this.string.substr(i,this.i-i)} + c = this.string.charAt(++this.i); + if (!c.match(/[1-9]/)) {this.Error("Illegal use of # in "+cmd); return null} + if (1*c != ++n) {this.Error("Parameters must be numbered sequentially"); return null} + i = this.i+1; + } else if (c == '{') { + if (i != this.i) {params[n] = this.string.substr(i,this.i-i)} + if (params.length > 0) {return [n,params]} else {return n} + } + this.i++; + } + this.Error("Missing replacement string for definition of "+cmd); + return null; + }, + + /* + * Process a macro with a parameter template + */ + MacroWithTemplate: function (name,data) { + var text = data[0]; + var n = data[1]; var params = data[2]; + if (n) { + var args = []; var c = this.GetNext(); + if (params[0] && !this.MatchParam(params[0])) + {this.Error("Use of "+this.cmd+name+" doesn't match its definition"); return} + for (var i = 0; i < n; i++) { + args[args.length] = this.GetParameter(this.cmd+name,params[i+1]); + if (this.error) return; + } + text = this.SubstituteArgs(args,text); + } + this.string = this.AddArgs(text,this.string.slice(this.i)); + this.i = 0; + }, + + /* + * Process a user-defined environment + */ + Environment: function (name,data) { + var bdef = data[0]; var edef = data[1]; var n = data[2]; + if (n) { + var args = []; + for (var i = 0; i < n; i++) { + args[args.length] = this.GetArgument(this.cmd+"begin{"+name+"}"); if (this.error) return; + } + bdef = this.SubstituteArgs(args,bdef); + } + var text = this.GetEnd(name); if (this.error) return; + text = this.AddArgs(this.AddArgs(bdef,text),edef); + this.string = this.AddArgs(text,this.string.slice(this.i)); + this.i = 0; + }, + + /* + * Find a single parameter delimited by a trailing template + */ + GetParameter: function (name,param) { + if (param == null) {return this.GetArgument(name)} + var i = this.i; var j = 0; var hasBraces = 0; + while (this.i < this.string.length) { + if (this.string.charAt(this.i) == '{') { + if (this.i == i) {hasBraces = 1} + this.GetArgument(name); j = this.i - i; + } else if (this.MatchParam(param)) { + if (hasBraces) {i++; j -= 2} + return this.string.substr(i,j); + } else { + this.i++; j++; hasBraces = 0; + } + } + this.Error("Runaway argument for "+name+"?"); + return null; + }, + + /* + * Check if a template is at the current location. + * (The match must be exact, with no spacing differences. TeX is + * a little more forgiving about spaces after macro names) + */ + MatchParam: function (param) { + if (this.string.substr(this.i,param.length) != param) {return 0} + this.i += param.length; + return 1; + } + +}); + +/* + * Define a jsMath.Environment() command similar to the + * jsMath.Macro() command. + * + * Usage: jsMath.Environment(name,begin,end[,n]) + * + * where "name" is the name of the environment, "begin" is the + * text that replaces the \begin{name} and "end" is the text that + * replaces the \end{name}. If "n" is provided, it is the number + * of parameters that the \begin{name} accepts, and these are + * used to replace #1, #2, etc within the "begin" text. + */ + +jsMath.Add(jsMath,{ + Environment: function (name) { + var environments = jsMath.Parser.prototype.environments; + environments[name] = ['Environment']; + for (var i = 1; i < arguments.length; i++) + {environments[name][environments[name].length] = arguments[i]} + } +});