source: Dev/trunk/src/client/dojox/calc/_ExecutorIframe.html

Last change on this file was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 19.6 KB
Line 
1<html><head>
2<script type="text/javascript">
3Array.prototype._toString = Array.prototype.toString;
4Array.prototype.toString = function(){ return "[" + this._toString() + "]"; };
5
6Number.prototype._toString = Number.prototype.toString;
7Number.prototype.toString = function(radix){ if(!radix || radix==10){ return ""+this._toString() } if(radix==2){ return "0b"+this._toString(radix); } if(radix==8){ return "0o"+this._toString(radix); } if(radix==16){ return "0x"+this._toString(radix); } return this._toString(radix) + "#" + radix._toString(); };
8
9(function(){ // env is private
10        parseFloat = function(str){
11        var obj = null;
12        function getRadixObject(whole, numberStr, base){
13                obj = {number:numberStr, radix:base};
14                return "";
15        }
16        function getBaseString(whole, base, numberStr){
17                var baseNum = (base == '0b') ? 2 : (base == '0o') ? 8 : 16;
18                return numberStr+"#"+baseNum;
19        }
20
21
22        var str = str.replace(/(0b|0o|0x)(([0-9a-zA-Z]+\.[0-9a-zA-Z]*|\.[0-9a-zA-Z]+|[0-9a-zA-Z]+))/, getBaseString);
23
24        var radix;
25
26        var poundRegExp = /([0-9a-zA-Z]+\.[0-9a-zA-Z]*|\.[0-9a-zA-Z]+|[0-9a-zA-Z]+)\#([0-9a-zA-Z]+)/g;
27        if(poundRegExp.test(str)){
28                // define obj in getRadixObject
29                str.replace(poundRegExp, getRadixObject);
30                radix = obj.radix;
31                str = obj.number;
32        }
33        if(!radix){
34                radix = 10;
35        }
36        var decimal = str.indexOf('.');
37        if(decimal>=0){
38                var left = str.substring(0,decimal);
39                if(left == ""){
40                        left = "0";
41                }
42                var right = str.substring(decimal+1, str.length);
43                if(right == ""){
44                        right = "0";
45                }
46                var num = parseInt(left, radix);
47
48                var dec = parseInt(right, radix);
49                var length = dec._toString().length;
50                dec /= Math.pow(radix, right.length);
51                return num+dec;
52        }
53        return parseInt(str, radix);
54};
55
56        var env = {
57                window: undefined, "delete": undefined, "new": undefined, // invalidate access to the globals for security so that window.blah is invalid as is delete window
58
59                prompt: function(label, defaultValue){
60                        // summary:
61                        //              prompt the user for input without making IE8 mad.
62                        // label:
63                        //              the String name of the variable you are asking the user to input
64                        // defaultValue: primitive
65                        //              the prompt will show this value initially
66
67                        label = label || '';
68                        defaultValue = defaultValue || '';
69                        try{
70                                return this.outerPrompt(label, defaultValue);
71                        }catch(e){
72                                return window.prompt(label, defaultValue);
73                        }
74                },
75                val: function(local, name, obj){
76                        // summary:
77                        //              allow the user to use locals, globals, or give input for undefined values
78                        // local: a primitive object
79                        //              what value might've been passed to val as a local parameter.
80                        // name: String
81                        //              String name of the object.  It is passed to see if there is an available global or to set the global.
82                        var objValue = obj[name];
83                        local = (objValue == undefined) ? (local == undefined ? window[name] : local) : objValue ;
84
85                        if(typeof local == 'undefined'){
86                                if(obj.graphing){
87                                        return undefined;
88                                }
89                                local=this.prompt('Enter the value for ' + name, undefined, name);
90
91                                return local == null ? undefined : (isNaN(Number(local)) ? local : Number(local));
92                        }
93                        return local;
94                },
95                _makeKeywordsLiteral: function (text){
96                        // summary:
97                        //              surround reserved words with hex characters
98
99                        // ==, then >=. the <=, then !=, then = and surround them with \x0n first
100                        text = text.replace(/(!=(?!=)|==|>=|<=|=)/g, "\x02$1\x02");
101                        return text.replace(/\b(abstract|boolean|break|byte|case|catch|char|class|const|continue|debugger|default|do|double|else|enum|export|extends|false|final|finally|float|for|function|goto|if|implements|import|in| instanceof|int|interface|long|native|null|package|private|protected|public|return|short|static|super| switch|synchronized|this|throw|throws|transient|true|try|typeof|var|void|volatile|while|with)\b/g, "\x02$1\x02");
102                },
103                switchToGermanNumbers: function(text){
104                        // summary:
105                        //              change the format of some javascript allowed numbers to an alternate form 3.5 goes to 3,5
106                        var num = 0;
107                        var numbers = [];
108                        function substituteCommas(whole, junk, text){
109                                numbers['_'+num+'_'] = text.replace(/\,/g, ';');
110                                return junk+'_'+(num++)+'_';
111                        }
112                        function substituteNumbers(wholematch, stuff, junk, text, stuff2){
113                                return stuff+numbers[text]+stuff2;
114                        }
115                        if(typeof text != "string"){
116                                text = text.toString();
117                        }
118                        if(text.indexOf('\x02')<0){
119                                text = this._makeKeywordsLiteral(text);
120                                //text = text.replace(/(!=(?!=)|==|>=|<=|=)/g, "\x02$1\x02");
121                        }
122
123                        // same as semiColonRegExp
124                        var commaRegExp = /([^\x02\s]*)(\([^\(\)]+\)|\[[^\[\]]+\])/;
125                        while(commaRegExp.test(text)){
126                                text = text.replace(commaRegExp , substituteCommas);
127                        }
128
129                        while(/((\W)*)(\_[0-9]+\_)((\W)*)/.test(text)){
130                                text = text.replace(/((\W)*)(\_[0-9]+\_)((\W)*)/g, substituteNumbers);
131                        }
132
133                        text = text.replace(/([0-9]*)\.([0-9]+)/g, "$1"+','+"$2");
134
135                        // get rid of keyword characters (duplicate code from parse())
136                        return text.replace(/\x02((.|\s)*?)\x02/g, "$1");
137                },
138                normalizeTextLanguage: function(text){
139                        // summary:
140                        //              change text to use javascript list separators and decimal points instead of commas
141                        // text: String
142                        //              string like "pow(3,1; 4);"
143                        //              for that input, this method should return "pow(3.1, 4);"
144
145                        var num = 0;
146                        var numbers = [];
147                        function substituteSemicolons(whole, junk, text){
148                                numbers['_'+num+'_'] = text.replace(/\;/g, ',');
149                                return junk+'_'+(num++)+'_';
150                        }
151                        function substituteNumbers(wholematch, stuff, junk, text, stuff2){
152                                return stuff+numbers[text]+stuff2;
153                        }
154                        if(text.indexOf('\x02')<0){
155                                text = this._makeKeywordsLiteral(text);
156                        }
157                        // change all comma-type decimals into periods
158                        text = text.replace(/([0-9]*)\,([0-9]+)/g, "$1"+'.'+"$2");
159                        //alert(text);
160                        var semiColonRegExp = /([^\x02\s]*)(\([^\(\)]+\)|\[[^\[\]]+\])/; // /([^\x02\s]+)(\([^\(\)]+\)|\[[^\[\]]+\])/; // /[^\x02\s]+\([^\(\)]+\)|[^\x02\s]+\[[^\[\]]+\]/; // /[^\x02]\s*\([^\(]+\)/;
161                        while(semiColonRegExp.test(text)){
162                                text = text.replace(semiColonRegExp, substituteSemicolons);
163                        }
164                        while(/((\W)*)(\_[0-9]+\_)((\W)*)/.test(text)){
165                                text = text.replace(/((\W)*)(\_[0-9]+\_)((\W)*)/g, substituteNumbers);
166                        }
167                        // get rid of keyword characters (duplicate code from parse())
168                        return text.replace(/\x02((.|\s)*?)\x02/g, "$1");
169                },
170                preparse: function(text){
171                        // summary:
172                        //              change the numbers to javascript allowed numbers if it is from a different locale
173                        if(!this.isJavaScriptLanguage){
174                                text = this.normalizeTextLanguage(text);
175                        }
176                        return text;
177                },
178                // parseFloat(Number(4.5).toString(3)) should return 4.5
179
180                postparse: function(text){
181                        // summary:
182                        //              make the javascript numbers match the locale
183                        if(!this.isJavaScriptLanguage){
184                                text = this.switchToGermanNumbers(text);
185                        }
186                        return text;
187                },
188                toDecimalRegExp: function(whole, base, number){
189                        // summary:
190                        //              get the decimal number from a float
191                        function getBase(base){
192                                switch(base){
193                                        case '0b':
194                                                return 2;
195                                        case '0o':
196                                                return 8;
197                                        case '0x':
198                                                return 16;
199                                        default:
200                                                return 10;
201                                }
202                        }
203                        //return parseInt(base, getBase(base));
204                        return parseFloat(base+number);
205                },
206                parse: function(text){
207                        // summary:
208                        //              This parses augmented mathematical syntax and converts it to executable JavaScript.
209                        // text: String
210                        //              should be a String which represents an expression, a function, a number, etc
211
212                        // this array holds the substitutions that represent an expression's parentheses and functions in a simplified way.
213                        var     numbers = [],
214                                // characters
215                                functionContentsChar = '\x03',
216                        // these are the regular expression needed to find and replace operators
217                                factorialRE = /((\w|\.)+)\s*\!/,
218                                unaryRightsideRE = /(^|[\+\-\/\*\!\^\u221A]+\s*)([\+\-]+)\s*((\w|\.)+)(?!.*[\+\-])/,
219                                unaryRE = /(^|[^a-zA-Z0-9_\.\s]+\s*)([\+\-]+|\u221A)\s*((\w|\.)+)/,              // /(^|[^a-zA-Z0-9_\.]\s*)([\+\-]+|\u221A)\s*((\w|\.)+)/,
220                                caretRE = /((\w|\.)+)\s*([\^])\s*((\w|\.)+)/, // /((\w|\.)+)\s*([\^])\s*(-?\s*(\w|\.)+)/,
221                                radicalRE = /((\w|\.)+)\s*(\u221A)\s*([+-]?\s*(\w|\.)+)/, // /((\w|\.)+)\s*(\u221A)\s*([+-]?\s*(\w|\.)+)(?!.*\u221A)/,
222                                binaryHighRE = /((\w|\.)+)\s*([*/])\s*((\w|\.)+)/,
223                                binaryLowRE = /((\w|\.)+)\s*([\+\-])+\s*((\w|\.)+)/;
224
225                        // get rid of all new and delete statements
226                        text = exterminateNewAndDelete(text);
227                        // make all keywords and operators literal (like '!=' or 'return') by surrounding them with unprintable characters
228                        text = this._makeKeywordsLiteral(text);
229
230
231                        function getBaseTen(whole, numberStr, base){
232                                return ""+parseFloat(numberStr+"#"+parseInt(base));
233                        }
234                        text = text.replace(/(0b)([0-1]+\.[0-1]*|\.[0-1]+|[0-1]+)/g, this.toDecimalRegExp);
235                        text = text.replace(/(0o)([0-7]+\.[0-7]*|\.[0-7]+|[0-7]+)/g, this.toDecimalRegExp);
236                        text = text.replace(/(0x)([0-9a-zA-Z]+\.[0-9a-zA-Z]*|\.[0-9a-zA-Z]+|[0-9a-zA-Z]+)/g, this.toDecimalRegExp);
237
238                        text = text.replace(/([0-9a-zA-Z]+\.[0-9a-zA-Z]*|\.[0-9a-zA-Z]+|[0-9a-zA-Z]+)\#([0-9a-zA-Z]+)/g, getBaseTen);
239
240                        // parse the input to form JavaScript
241                        return MathParser(text);
242
243                        function MathParser(text){
244                                // Pi is better represented by \u03C0, but isn't computable
245                                text = text.replace(/\u03C0/g,"Math.PI");
246                                text = text.replace(/\u03F5/g,"Math.E");
247
248                                // Microsoft word will give you these '\u2013' for a subtraction sign sometimes, so I'll fix that here
249                                text = text.replace(/\u2013/g, "-");
250                                // add unreadable characters in front of functions so it is easier to manipulate
251                                text = text.replace(/(((\w|\.)+\s*)\()/g,putFuncChar);
252
253                                // change 10e-10 or 10e10 or 10e+10 to an constant right away
254                                text = scientificNotationSimplifier(text);
255                                // recursively track down and replace all simplified parts of the expression until everything is simple; then move the simple text into the correct JavaScript format
256                                text = parseRecursive(text);
257                                // now resubstitute the real text back into the string now that it is arranged correctly
258                                while (hasArrayIndexBasedOnUnderscore(text)){
259                                        text  = text.replace(/\_(\d+)\_/g, function(whole, one){return numbers[parseInt(one)]});
260                                }
261                                // get rid of the function character from the functions now
262                                text = text.replace(/\x01/g,"");
263                                // get rid of keyword characters too
264                                text = text.replace(/\x02((.|\s)*?)\x02/g, "$1");
265                                return text;
266                        }
267                        function exterminateNewAndDelete(text){
268                                return text.replace(/\b(delete|new|this\.*)\b/, "");
269                        }
270                        // A simple grouping has no parentheses inside the initial pair.
271                        function isSimpleGrouping(text){
272                                return (/^\([^()]*\)|\W\([^()]*\)/).test(text);
273                        }
274                        function ReplaceSimpleGrouping(text){
275                                return text.replace((/(^|\W)(\([^()]*\))/), replaceWithNum);
276                        }
277                        function replaceWithNum(wholeMatch, partMatch1, partMatch2){
278                                numbers.push(partMatch2);
279                                return partMatch1+"_"+(numbers.length-1)+"_";
280                        }
281                        function replaceFuncWithNum(wholeMatch){
282                                numbers.push(wholeMatch);
283                                return "_"+(numbers.length-1)+"_";
284                        }
285                        // A simple function has no parentheses within its parentheses, and has the special character \x01 leading up to the name and (...)
286                        function isSimpleFunction(text){
287                                return (/\x01((\w|\.)+\s*)\([^()]*\)/).test(text);
288                        }
289                        function ReplaceSimpleFunction(text){
290                                return text.replace(/\x01((\w|\.)+\s*)\([^()]*\)/, replaceFuncWithNum);
291                        }
292                        function FactorialParser(text){
293                                // loop this untill all ! are gone (in main)
294                                return text.replace(factorialRE, "\x01"+"factorial($1)");
295                        }
296                        function putFuncChar(wholematch){
297                                return '\x01'+wholematch;
298                        }
299                        function putInPiece(wholematch){
300                                return numbers[currentNum];
301                        }
302
303                        function caretParser(text){
304                                return text.replace(caretRE, replaceBinaryOp);
305                        }
306                        // the unary radical is inside the unaryOperatorParse(text) function
307                        function radicalOperatorParse(text){
308                                return text.replace(radicalRE, replaceBinaryOp);
309                        }
310                        function replaceBinaryOp(wholeMatch, operand1, nothing1, operator, operand2){
311
312                                switch(operator.charAt(0)){
313                                        case '^':
314                                                return "\x01"+"pow("+operand1+","+operand2+")";
315                                        case '\u221A':
316                                                return "\x01"+"pow("+operand2+", 1/"+operand1+")";
317                                        case '*':
318                                        case '/':
319                                                return replaceFuncWithNum(wholeMatch);
320                                        case '+':
321                                        case '-':
322                                        case 'e':
323                                                return replaceFuncWithNum(simplifyPlusAnsMinus(wholeMatch));
324                                }
325                        }
326                        // e is treated as a binary operator
327                        function scientificNotationSimplifier(text){
328                                //return text.replace(/((\w|\.)+)\s*([\e])\s*([+-]*\s*(\w|\.)+)/g, replaceBinaryOp);
329                                return text.replace(/(([0-9]+\.?[0-9]*))(e)([+-]*([0-9]+))/g, replaceBinaryOp);
330                        }
331                        // this handles * and /
332                        function binaryHighPriorityOperatorParse(text){
333                                return text.replace(binaryHighRE, replaceBinaryOp);
334                        }
335                        // this handles + and - with two operands
336                        function binaryLowPriorityOperatorParse(text){
337                                return text.replace(binaryLowRE, replaceBinaryOp);
338                        }
339                        // this replaces the one operand +'s, -'s, and radicals
340                        function replaceUnaryOp(wholeMatch, garbage, operator0, operand0){
341                                // see what operator it is
342                                switch(operator0.charAt(0)){
343                                        case '\u221A':
344                                                return garbage+"\x01"+"sqrt("+operand0+")";
345                                        case '+':
346                                        case '-':
347                                                return garbage+replaceFuncWithNum(simplifyPlusAnsMinus(wholeMatch.substr(garbage.length)));
348                                }
349                        }
350                        // this handles one operand operators -, +, radical
351                        function unaryOperatorParse(text){
352                                return text.replace(unaryRE, replaceUnaryOp);
353                        }
354                        // this handles one operand operators on the right side of everything
355                        function unaryOperatorRightsideParse(text){
356                                return text.replace(unaryRightsideRE, replaceUnaryOp);
357                        }
358                        function parseRecursive(text){
359                                // keep going until there is nothing left that can be simplified
360                                while (isSimpleGrouping(text)||isSimpleFunction(text)||factorialRE.test(text)||caretRE.test(text)||radicalRE.test(text)||unaryRE.test(text)||binaryHighRE.test(text)||binaryLowRE.test(text)){
361
362                                        var sTextOrginal = text;
363
364                                        if(isSimpleFunction(text)){
365                                                var debugText = text;
366
367                                                text = ReplaceSimpleFunction(text);
368                                                var     s = numbers[numbers.length-1],
369                                                        pL = s.indexOf("("),
370                                                        funcName = s.substring(s.indexOf("\x01")+1, pL),//take out the function character
371                                                        content = s.substring(pL+1, s.length-1);
372
373                                                numbers[numbers.length-1] = funcName+"("+parseRecursive(functionContentsChar+content)+")";
374                                                continue;
375                                        }
376                                        if(isSimpleGrouping(text)){
377                                                text = ReplaceSimpleGrouping(text);
378                                                var     s = numbers[numbers.length-1],
379                                                        content = s.substring(1, s.length-1);
380                                                numbers[numbers.length-1] = "("+parseRecursive(content)+")";
381                                                continue;
382                                        }
383
384                                        // factorials must come first for 5^2! cases, it equals 25
385                                        text = FactorialParser(text);
386                                        if(text!=sTextOrginal){
387                                                continue;
388                                        }
389
390                                        text = caretParser(text);
391                                        if(text!=sTextOrginal){
392                                                continue;
393                                        }
394
395                                        text = radicalOperatorParse(text);
396                                        if(text!=sTextOrginal){
397                                                continue;
398                                        }
399                                        text = unaryOperatorRightsideParse(text);
400                                        if(text!=sTextOrginal){
401                                                // put parentheses around the unary operators so 0--2 will pass
402                                                numbers[numbers.length-1] = "("+numbers[numbers.length-1]+")";
403                                                continue;
404                                        }
405                                        text = unaryOperatorParse(text);
406                                        if(text!=sTextOrginal){
407                                                // put parentheses around the unary operators so 0--2 will pass
408                                                numbers[numbers.length-1] = "("+numbers[numbers.length-1]+")";
409                                                continue;
410                                        }
411
412                                        text = binaryHighPriorityOperatorParse(text);
413                                        if(text!=sTextOrginal){
414                                                continue;
415                                        }
416                                        text = binaryLowPriorityOperatorParse(text);
417                                        if(text!=sTextOrginal){
418                                                continue;
419                                        }
420                                        // it should never ever make it to this point.  If it does, I'll want to know about it.
421                                        throw("Parse Error");
422                                }
423                                // make assignments within function calls be arranged to be (x=y, undefined)
424                                if(text.charAt(0) == functionContentsChar){
425                                        text = text.substring(1, text.length);
426                                        if(text.indexOf('=') >= 0){
427                                                text = ReplaceFunctionContentAssignments(text);
428                                        }
429                                }
430
431                                return text;
432                        }
433                        function ReplaceFunctionContentAssignments(text){
434                                return text.replace(/((\w|\.)+)\x02=\x02((\w|\.)+)/g, "("+"$1"+'\x02=\x02'+"$3"+", {_name:'"+"$1"+"', _value:"+"$3"+"})");
435                        }
436                        function hasArrayIndexBasedOnUnderscore(text){
437                                return /\_\d+\_/.test(text);
438                        }
439                       
440                        function simplifyPlusAnsMinus(text){
441                                function hasUnsimplifiedPlusMinus(text){
442                                        return /\-\s*\-/.test(text)||/\+\s*\+/.test(text)||/\+\s*\-/.test(text)||/\-\s*\+/.test(text);
443                                }
444                                while(hasUnsimplifiedPlusMinus(text)){
445                                        text = text.replace(/((\-\s*\-)|(\+\s*\+))/g, "+");
446                                        text = text.replace(/((\+\s*\-)|(\-\s*\+))/g, "-");
447                                }
448                                return text;
449                        }
450
451                },
452                eval: function(text){
453                        // summary:
454                        //              create an anonymous function to run the code the parser generates from the user input.
455                        // text: String
456                        //              is the user input that needs to be parsed
457
458                        // this try catch is necessary to ensure that any incorrect input will receive NaN (it won't cause a self destruct from a user typo)
459                        try{
460                                var value = this.Function(undefined, '', 'return ' + text).call(this); // make sure it is called within the correct scope.
461                                //value = ((value instanceof Array || typeof value == "array") ? ("["+value+"]") : value.toString())
462                                return this.postparse(value);
463                        }catch(e){
464                                return NaN;
465                        }
466                },
467                normalizedFunction: function(name, args, body){
468                        // summary:
469                        //              create an anonymous function to run the code the parser generates from the user input.
470                        // name: String
471                        //              this argument is simply a String that represents the name of the function being evaluated. It can be undefined, but in that case the function is a one time use.
472                        // args: String
473                        //              the function arguments
474                        // body: String
475                        //              the function body
476                        var     argMultiVals = '',
477                        // make an array of parameters with what's given (if nothing is given, make an empty array)
478                                params = args ? (args||'').split(/\W+/) : [];
479
480                        argMultiVals += 'var _localObjectContainer = {};\n'+
481                                                'for(var _objCnt = 0; _objCnt < arguments.length; _objCnt++){\n'+
482                                                'if(typeof arguments[_objCnt] == "object" && "_name" in arguments[_objCnt] && "_value" in arguments[_objCnt]){\n'+
483                                                        '_localObjectContainer.graphing = arguments[_objCnt]._graphing;\n'+
484                                                        '_localObjectContainer[arguments[_objCnt]._name]=arguments[_objCnt]._value;\n'+
485                                                        'arguments[_objCnt]=undefined;\n}\n}\n';
486
487                        // make the parameters fit into the val function so it can use either globals, locals, or if all are null, prompt the user for input
488                        for(var i=0; i < params.length; i++){
489                                var param = params[i];
490                                argMultiVals += param + '=val(' + param + ',"' + param + '", _localObjectContainer);\n';
491                                argMultiVals += 'if(typeof '+param+' == "undefined"){\n'+
492                                                'return null;}\n';
493                        }
494                        var _f_ = window.Function.apply(this,
495                                [
496                                        args,
497                                        'with(Math){with(this.dojox.math){with(this){\n' +
498                                                argMultiVals +
499                                                this.parse(body) +
500                                        '\n}}}'
501                                ]
502                        );
503                        if(name){
504                                return this[name] = _f_;
505                        }
506                        return _f_;
507                },
508                Function: function(name, args, body){
509                        // summary:
510                        //              create an anonymous function to run the code the parser generates from the user input.  It also normalizes the language format.
511                        // name: String
512                        //              this argument is simply a String that represents the name of the function being evaluated. It can be undefined, but in that case the function is a one time use.
513                        // args: String
514                        //              the function arguments
515                        // body: String
516                        //              the function body
517
518                        body = this.preparse(body);
519                        return this.normalizedFunction(name, args, body);
520
521                }
522        };
523        for(var i in window){
524                if(!(i in env) && i != "alert" && i != "confirm"){ env[i] = undefined; } // invalidate access to the window object's attributes for security so that document.blah is invalid
525        }
526        frameElement.onload(env);
527})();
528</script>
529</head><body>
530<script type="text/javascript">
531        document.documentElement.removeChild(document.documentElement.firstChild); // remove HEAD to remove debugger access for extra security
532</script>
533</body></html>
Note: See TracBrowser for help on using the repository browser.