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>