| //------------------------------------------------------------------------------------------------------- |
| // Copyright (C) Microsoft. All rights reserved. |
| // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. |
| //------------------------------------------------------------------------------------------------------- |
| |
| var GenerateNegativeZeroScheme = { |
| Neg: 0, |
| Mul: 1 |
| }; |
| |
| var IntOperation = { |
| None: 0, |
| Incr: 1, |
| Decr: 2, |
| Not: 3, |
| And: 4, |
| Or: 5, |
| Xor: 6, |
| Shl: 7, |
| Shr: 8, |
| ShrU: 9 |
| }; |
| |
| var MakeNegativeZeroMatterLocation = { |
| None: 0, |
| BeforeIntOperation: 1, |
| AfterIntOperation: 2 |
| }; |
| |
| var MakeNegativeZeroMatterScheme = { |
| Div: 0, |
| Throw: 1, |
| Ret: 2, |
| PassToFunction: 3, |
| SetPropertyInLocalObject: 4, |
| SetPropertyInNonlocalObjectInScope: 5, |
| SetNonlocalVariableInScope: 6, |
| SetArrayElement: 7 |
| }; |
| |
| function makeNegativeZeroMatter(scheme, srcVar) { |
| var s = ""; |
| if(scheme === MakeNegativeZeroMatterScheme.Div) |
| s += "throw new Error(1 / c < 0 ? '-0' : '0');"; |
| else if(scheme === MakeNegativeZeroMatterScheme.Throw) |
| s += "throw c;"; |
| else if(scheme === MakeNegativeZeroMatterScheme.Ret) |
| s += "return c;"; |
| else if(scheme === MakeNegativeZeroMatterScheme.PassToFunction) |
| s += "echo(c);"; |
| else if(scheme === MakeNegativeZeroMatterScheme.SetPropertyInLocalObject) |
| s += "localObj.p = c;"; |
| else if(scheme === MakeNegativeZeroMatterScheme.SetPropertyInNonlocalObjectInScope) |
| s += "outerObj.p = c;"; |
| else if(scheme === MakeNegativeZeroMatterScheme.SetNonlocalVariableInScope) |
| s += "outerVar = c;"; |
| else if(scheme === MakeNegativeZeroMatterScheme.SetArrayElement) |
| s += "localArr[0] = c;"; |
| else |
| throw new Error("Unknown MakeNegativeZeroMatterScheme"); |
| return s; |
| } |
| |
| function generateAndRunTest( |
| generateNegativeZeroScheme, |
| intOperation, |
| makeNegativeZeroMatterLocation, |
| makeNegativeZeroMatterScheme) { |
| |
| var f = "(function outer(a, b){"; |
| f += "var outerObj = {p: 0};" |
| f += "var outerVar = 0;"; |
| f += "return (function test(a, b){"; |
| f += "a >>= 14;"; |
| f += "b &= 0x3fff;"; |
| f += "var localObj = {p: 0};"; |
| f += "var localArr = [0];"; |
| |
| if(generateNegativeZeroScheme == GenerateNegativeZeroScheme.Neg) |
| f += "var c = -b;"; |
| else if(generateNegativeZeroScheme == GenerateNegativeZeroScheme.Mul) |
| f += "var c = a * b;"; |
| else |
| throw new Error("Unknown GenerateNegativeZeroScheme"); |
| |
| if(makeNegativeZeroMatterLocation === MakeNegativeZeroMatterLocation.BeforeIntOperation) |
| f += makeNegativeZeroMatter(makeNegativeZeroMatterScheme); |
| |
| if(intOperation === IntOperation.None) |
| f += "var d = c;"; |
| else if(intOperation === IntOperation.Incr) |
| f += "var d = ++c;"; |
| else if(intOperation === IntOperation.Decr) |
| f += "var d = --c;"; |
| else if(intOperation === IntOperation.Not) |
| f += "var d = ~c;"; |
| else if(intOperation === IntOperation.And) |
| f += "var d = c & 0xfffffff;"; |
| else if(intOperation === IntOperation.Or) |
| f += "var d = c | 0xfffffff;"; |
| else if(intOperation === IntOperation.Xor) |
| f += "var d = c ^ 0xfffffff;"; |
| else if(intOperation === IntOperation.Shl) |
| f += "var d = c << 1;"; |
| else if(intOperation === IntOperation.Shr) |
| f += "var d = c >> 1;"; |
| else if(intOperation === IntOperation.ShrU) |
| f += "var d = c >>> 1;"; |
| else |
| throw new Error("Unknown IntOperation"); |
| |
| if(makeNegativeZeroMatterLocation === MakeNegativeZeroMatterLocation.AfterIntOperation) |
| f += makeNegativeZeroMatter(makeNegativeZeroMatterScheme); |
| |
| f += "return [d & 0xfffffff, localObj.p, localArr[0], outerObj.p, outerVar];"; |
| f += "}).apply(this, arguments);"; |
| f += "});"; |
| f = eval(f); |
| echo(f.toString()); |
| |
| try { |
| echo("Returned: ", f(-2 << 14, 0)); |
| } catch(ex) { |
| echo("Thrown: ", ex); |
| } |
| } |
| |
| for(var generateNegativeZeroSchemeIndex in GenerateNegativeZeroScheme) { |
| var generateNegativeZeroScheme = GenerateNegativeZeroScheme[generateNegativeZeroSchemeIndex]; |
| for(var intOperationIndex in IntOperation) { |
| var intOperation = IntOperation[intOperationIndex]; |
| for(var makeNegativeZeroMatterLocationIndex in MakeNegativeZeroMatterLocation) { |
| var makeNegativeZeroMatterLocation = MakeNegativeZeroMatterLocation[makeNegativeZeroMatterLocationIndex]; |
| if(makeNegativeZeroMatterLocation === MakeNegativeZeroMatterLocation.None) { |
| var makeNegativeZeroMatterScheme = MakeNegativeZeroMatterScheme[makeNegativeZeroMatterSchemeIndex]; |
| echo("generateAndRunTest(" + intOperationIndex + ", " + makeNegativeZeroMatterLocationIndex + ");"); |
| generateAndRunTest(generateNegativeZeroScheme, intOperation, makeNegativeZeroMatterLocation); |
| echo(); |
| } else { |
| for(var makeNegativeZeroMatterSchemeIndex in MakeNegativeZeroMatterScheme) { |
| var makeNegativeZeroMatterScheme = MakeNegativeZeroMatterScheme[makeNegativeZeroMatterSchemeIndex]; |
| echo( |
| "generateAndRunTest(" + |
| intOperationIndex + ", " + |
| makeNegativeZeroMatterLocationIndex + ", " + |
| makeNegativeZeroMatterSchemeIndex + ");"); |
| generateAndRunTest( |
| generateNegativeZeroScheme, |
| intOperation, |
| makeNegativeZeroMatterLocation, |
| makeNegativeZeroMatterScheme); |
| echo(); |
| } |
| } |
| } |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| function myToString(o, quoteStrings) { |
| switch(o) { |
| case null: |
| case undefined: |
| return "" + o; |
| } |
| |
| switch(typeof o) { |
| case "boolean": |
| return "" + o; |
| |
| case "number": |
| { |
| if(o === 0 && 1 / o < 0) |
| return "-0"; |
| var s = "" + o; |
| var i = s.indexOf("e"); |
| var end = i === -1 ? s.length : e; |
| i = s.indexOf("."); |
| var start = i === -1 ? 0 : i + 1; |
| if(start !== 0) { |
| if((end - start) % 3 !== 0) |
| end += 3 - (end - start) % 3; |
| for(i = end - 3; i > start; i -= 3) |
| s = s.substring(0, i) + "," + s.substring(i); |
| end = start - 1; |
| start = 0; |
| } |
| for(i = end - 3; i > start; i -= 3) |
| s = s.substring(0, i) + "," + s.substring(i); |
| return s; |
| } |
| |
| case "string": |
| { |
| var hex = "0123456789abcdef"; |
| var s = ""; |
| for(var i = 0; i < o.length; ++i) { |
| var c = o.charCodeAt(i); |
| switch(c) { |
| case 0x0: |
| s += "\\0"; |
| continue; |
| case 0x8: |
| s += "\\b"; |
| continue; |
| case 0xb: |
| s += "\\v"; |
| continue; |
| case 0xc: |
| s += "\\f"; |
| continue; |
| } |
| if(quoteStrings) { |
| switch(c) { |
| case 0x9: |
| s += "\\t"; |
| continue; |
| case 0xa: |
| s += "\\n"; |
| continue; |
| case 0xd: |
| s += "\\r"; |
| continue; |
| case 0x22: |
| s += "\\\""; |
| continue; |
| case 0x5c: |
| s += "\\\\"; |
| continue; |
| } |
| } |
| if(c >= 0x20 && c < 0x7f) |
| s += o.charAt(i); |
| else if(c <= 0xff) |
| s += "\\x" + hex.charAt((c >> 4) & 0xf) + hex.charAt(c & 0xf); |
| else |
| s += "\\u" + hex.charAt((c >> 12) & 0xf) + hex.charAt((c >> 8) & 0xf) + hex.charAt((c >> 4) & 0xf) + hex.charAt(c & 0xf); |
| } |
| if(quoteStrings) |
| s = "\"" + s + "\""; |
| return s; |
| } |
| |
| case "object": |
| case "function": |
| break; |
| |
| default: |
| return "<unknown type '" + typeof o + "'>"; |
| } |
| |
| if(o instanceof Array) { |
| var s = "["; |
| for(var i = 0; i < o.length; ++i) { |
| if(i) |
| s += ", "; |
| s += myToString(o[i], true); |
| } |
| return s + "]"; |
| } |
| if(o instanceof Error) |
| return o.name + ": " + o.message; |
| if(o instanceof RegExp) |
| return o.toString() + (o.lastIndex === 0 ? "" : " (lastIndex: " + o.lastIndex + ")"); |
| if(o instanceof Object && !(o instanceof Function)) { |
| var s = ""; |
| for(var p in o) |
| s += myToString(p) + ": " + myToString(o[p], true) + ", "; |
| if(s.length !== 0) |
| s = s.substring(0, s.length - ", ".length); |
| return "{" + s + "}"; |
| } |
| return "" + o; |
| } |
| |
| function echo() { |
| var doEcho; |
| if(this.WScript) |
| doEcho = function (s) { this.WScript.Echo(s); }; |
| else if(this.document) |
| doEcho = |
| function (s) { |
| s = s |
| .replace(/&/g, "&&") |
| .replace(/</g, "<") |
| .replace(/>/g, ">"); |
| this.document.write(s + "<br/>"); |
| }; |
| else |
| doEcho = function (s) { this.print(s); }; |
| echo = |
| function () { |
| var s = ""; |
| for(var i = 0; i < arguments.length; ++i) |
| s += myToString(arguments[i]); |
| doEcho(s); |
| }; |
| echo.apply(this, arguments); |
| } |
| |
| function safeCall(f) { |
| var args = []; |
| for(var a = 1; a < arguments.length; ++a) |
| args.push(arguments[a]); |
| try { |
| return f.apply(this, args); |
| } catch(ex) { |
| echo(ex); |
| } |
| } |