js-confuser 1.5.8 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/node.js.yml +2 -2
- package/CHANGELOG.md +69 -0
- package/README.md +143 -7
- package/dist/index.js +33 -4
- package/dist/obfuscator.js +30 -31
- package/dist/options.js +4 -5
- package/dist/order.js +4 -6
- package/dist/probability.js +2 -4
- package/dist/templates/bufferToString.js +13 -0
- package/dist/templates/crash.js +2 -2
- package/dist/templates/es5.js +18 -0
- package/dist/transforms/antiTooling.js +1 -1
- package/dist/transforms/calculator.js +77 -21
- package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +980 -367
- package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +8 -3
- package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +25 -26
- package/dist/transforms/deadCode.js +33 -25
- package/dist/transforms/dispatcher.js +7 -6
- package/dist/transforms/es5/antiClass.js +6 -2
- package/dist/transforms/es5/antiDestructuring.js +3 -1
- package/dist/transforms/es5/es5.js +31 -34
- package/dist/transforms/eval.js +11 -0
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +8 -5
- package/dist/transforms/extraction/objectExtraction.js +6 -1
- package/dist/transforms/finalizer.js +82 -0
- package/dist/transforms/flatten.js +82 -55
- package/dist/transforms/hexadecimalNumbers.js +34 -9
- package/dist/transforms/identifier/globalAnalysis.js +88 -0
- package/dist/transforms/identifier/globalConcealing.js +10 -83
- package/dist/transforms/identifier/movedDeclarations.js +2 -8
- package/dist/transforms/identifier/renameVariables.js +39 -27
- package/dist/transforms/identifier/variableAnalysis.js +58 -62
- package/dist/transforms/minify.js +80 -61
- package/dist/transforms/opaquePredicates.js +1 -1
- package/dist/transforms/preparation/preparation.js +2 -2
- package/dist/transforms/preparation.js +231 -0
- package/dist/transforms/renameLabels.js +1 -1
- package/dist/transforms/rgf.js +4 -5
- package/dist/transforms/stack.js +87 -26
- package/dist/transforms/string/encoding.js +150 -179
- package/dist/transforms/string/stringCompression.js +14 -15
- package/dist/transforms/string/stringConcealing.js +25 -8
- package/dist/transforms/string/stringEncoding.js +13 -24
- package/dist/transforms/transform.js +11 -18
- package/dist/traverse.js +24 -18
- package/dist/util/compare.js +2 -2
- package/dist/util/gen.js +15 -0
- package/dist/util/insert.js +31 -7
- package/dist/util/random.js +15 -0
- package/package.json +5 -5
- package/src/index.ts +57 -19
- package/src/obfuscator.ts +26 -29
- package/src/options.ts +17 -21
- package/src/order.ts +4 -8
- package/src/probability.ts +2 -3
- package/src/templates/bufferToString.ts +68 -0
- package/src/templates/crash.ts +5 -9
- package/src/templates/es5.ts +131 -0
- package/src/transforms/antiTooling.ts +1 -1
- package/src/transforms/calculator.ts +122 -59
- package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +1583 -571
- package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +18 -3
- package/src/transforms/deadCode.ts +383 -26
- package/src/transforms/dispatcher.ts +8 -6
- package/src/transforms/es5/antiClass.ts +10 -1
- package/src/transforms/es5/antiDestructuring.ts +3 -1
- package/src/transforms/es5/es5.ts +32 -77
- package/src/transforms/eval.ts +18 -0
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +9 -6
- package/src/transforms/extraction/objectExtraction.ts +12 -5
- package/src/transforms/finalizer.ts +75 -0
- package/src/transforms/flatten.ts +194 -151
- package/src/transforms/identifier/globalAnalysis.ts +85 -0
- package/src/transforms/identifier/globalConcealing.ts +14 -103
- package/src/transforms/identifier/movedDeclarations.ts +4 -11
- package/src/transforms/identifier/renameVariables.ts +37 -30
- package/src/transforms/identifier/variableAnalysis.ts +66 -73
- package/src/transforms/minify.ts +116 -77
- package/src/transforms/opaquePredicates.ts +2 -2
- package/src/transforms/preparation.ts +238 -0
- package/src/transforms/renameLabels.ts +2 -2
- package/src/transforms/rgf.ts +6 -7
- package/src/transforms/stack.ts +97 -37
- package/src/transforms/string/encoding.ts +115 -212
- package/src/transforms/string/stringCompression.ts +27 -18
- package/src/transforms/string/stringConcealing.ts +41 -11
- package/src/transforms/string/stringEncoding.ts +18 -18
- package/src/transforms/transform.ts +15 -21
- package/src/traverse.ts +24 -12
- package/src/types.ts +11 -2
- package/src/util/compare.ts +2 -2
- package/src/util/gen.ts +21 -1
- package/src/util/insert.ts +49 -9
- package/src/util/random.ts +13 -0
- package/test/code/Cash.test.ts +1 -1
- package/test/code/Dynamic.test.ts +12 -10
- package/test/code/ES6.src.js +136 -0
- package/test/code/ES6.test.ts +28 -2
- package/test/code/NewFeatures.test.ts +19 -0
- package/test/index.test.ts +15 -2
- package/test/probability.test.ts +44 -0
- package/test/templates/template.test.ts +1 -1
- package/test/transforms/antiTooling.test.ts +52 -0
- package/test/transforms/calculator.test.ts +40 -0
- package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +713 -149
- package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +173 -0
- package/test/transforms/deadCode.test.ts +66 -15
- package/test/transforms/dispatcher.test.ts +44 -1
- package/test/transforms/es5/antiClass.test.ts +33 -0
- package/test/transforms/es5/antiDestructuring.test.ts +16 -0
- package/test/transforms/eval.test.ts +53 -0
- package/test/transforms/extraction/objectExtraction.test.ts +21 -0
- package/test/transforms/flatten.test.ts +195 -3
- package/test/transforms/identifier/movedDeclarations.test.ts +27 -0
- package/test/transforms/identifier/renameVariables.test.ts +108 -0
- package/test/transforms/lock/antiDebug.test.ts +2 -2
- package/test/transforms/minify.test.ts +151 -0
- package/test/transforms/preparation.test.ts +157 -0
- package/test/transforms/rgf.test.ts +56 -29
- package/test/transforms/stack.test.ts +91 -21
- package/test/transforms/string/stringCompression.test.ts +39 -0
- package/test/transforms/string/stringConcealing.test.ts +115 -0
- package/test/transforms/string/stringEncoding.test.ts +53 -2
- package/test/transforms/transform.test.ts +66 -0
- package/test/traverse.test.ts +139 -0
- package/test/util/compare.test.ts +23 -1
- package/src/transforms/controlFlowFlattening/choiceFlowObfuscation.ts +0 -87
- package/src/transforms/controlFlowFlattening/controlFlowObfuscation.ts +0 -203
- package/src/transforms/controlFlowFlattening/switchCaseObfuscation.ts +0 -130
- package/src/transforms/hexadecimalNumbers.ts +0 -31
- package/src/transforms/hideInitializingCode.ts +0 -432
- package/src/transforms/label.ts +0 -64
- package/src/transforms/preparation/nameConflicts.ts +0 -102
- package/src/transforms/preparation/preparation.ts +0 -176
- package/test/transforms/controlFlowFlattening/controlFlowObfuscation.test.ts +0 -101
- package/test/transforms/controlFlowFlattening/switchCaseObfuscation.test.ts +0 -120
- package/test/transforms/hideInitializingCode.test.ts +0 -336
- package/test/transforms/preparation/nameConflicts.test.ts +0 -52
- package/test/transforms/preparation/preparation.test.ts +0 -62
package/src/templates/crash.ts
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
import Template from "./template";
|
|
2
2
|
|
|
3
3
|
export const CrashTemplate1 = Template(`
|
|
4
|
-
try {
|
|
5
|
-
if(typeof process !== "undefined") {
|
|
6
|
-
Math.random() > 0.5 && process && process.exit();
|
|
7
|
-
}
|
|
8
|
-
} catch ( e ) {
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
12
4
|
var {var} = "a";
|
|
13
5
|
while(1){
|
|
14
6
|
{var} = {var} += "a"; //add as much as the browser can handle
|
|
@@ -17,12 +9,16 @@ while(1){
|
|
|
17
9
|
|
|
18
10
|
export const CrashTemplate2 = Template(`
|
|
19
11
|
while(true) {
|
|
20
|
-
|
|
12
|
+
var {var} = 99;
|
|
13
|
+
for({var} = 99; {var} == {var}; {var} *= {var}) {
|
|
21
14
|
!{var} && console.log({var});
|
|
22
15
|
if ({var} <= 10){
|
|
23
16
|
break;
|
|
24
17
|
}
|
|
25
18
|
};
|
|
19
|
+
if({var} === 100) {
|
|
20
|
+
{var}--
|
|
21
|
+
}
|
|
26
22
|
};`);
|
|
27
23
|
|
|
28
24
|
export const CrashTemplate3 = Template(`
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import Template from "./template";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Provides ES5 polyfills for Array methods
|
|
5
|
+
*
|
|
6
|
+
* Source: https://vanillajstoolkit.com/polyfills/
|
|
7
|
+
*/
|
|
8
|
+
export const ES5Template = Template(`
|
|
9
|
+
if (!Array.prototype.forEach) {
|
|
10
|
+
Array.prototype.forEach = function forEach (callback, thisArg) {
|
|
11
|
+
if (typeof callback !== 'function') {
|
|
12
|
+
throw new TypeError(callback + ' is not a function');
|
|
13
|
+
}
|
|
14
|
+
var array = this;
|
|
15
|
+
thisArg = thisArg || this;
|
|
16
|
+
for (var i = 0, l = array.length; i !== l; ++i) {
|
|
17
|
+
callback.call(thisArg, array[i], i, array);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
if (!Array.prototype.filter)
|
|
22
|
+
Array.prototype.filter = function(func, thisArg) {
|
|
23
|
+
'use strict';
|
|
24
|
+
if ( ! ((typeof func === 'Function' || typeof func === 'function') && this) )
|
|
25
|
+
throw new TypeError();
|
|
26
|
+
|
|
27
|
+
var len = this.length >>> 0,
|
|
28
|
+
res = new Array(len), // preallocate array
|
|
29
|
+
t = this, c = 0, i = -1;
|
|
30
|
+
if (thisArg === undefined)
|
|
31
|
+
while (++i !== len)
|
|
32
|
+
// checks to see if the key was set
|
|
33
|
+
if (i in this)
|
|
34
|
+
if (func(t[i], i, t))
|
|
35
|
+
res[c++] = t[i];
|
|
36
|
+
else
|
|
37
|
+
while (++i !== len)
|
|
38
|
+
// checks to see if the key was set
|
|
39
|
+
if (i in this)
|
|
40
|
+
if (func.call(thisArg, t[i], i, t))
|
|
41
|
+
res[c++] = t[i];
|
|
42
|
+
|
|
43
|
+
res.length = c; // shrink down array to proper size
|
|
44
|
+
return res;
|
|
45
|
+
};
|
|
46
|
+
if (!Array.prototype.map) {
|
|
47
|
+
Array.prototype.map = function(callback, thisArg) {
|
|
48
|
+
var T, A, k;
|
|
49
|
+
|
|
50
|
+
if (this == null) {
|
|
51
|
+
throw new TypeError('this is null or not defined');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 1. Let O be the result of calling ToObject passing the |this|
|
|
55
|
+
// value as the argument.
|
|
56
|
+
var O = Object(this);
|
|
57
|
+
|
|
58
|
+
// 2. Let lenValue be the result of calling the Get internal
|
|
59
|
+
// method of O with the argument "length".
|
|
60
|
+
// 3. Let len be ToUint32(lenValue).
|
|
61
|
+
var len = O.length >>> 0;
|
|
62
|
+
|
|
63
|
+
// 4. If IsCallable(callback) is false, throw a TypeError exception.
|
|
64
|
+
// See: http://es5.github.com/#x9.11
|
|
65
|
+
if (typeof callback !== 'function') {
|
|
66
|
+
throw new TypeError(callback + ' is not a function');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
|
|
70
|
+
if (arguments.length > 1) {
|
|
71
|
+
T = arguments[1];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 6. Let A be a new array created as if by the expression new Array(len)
|
|
75
|
+
// where Array is the standard built-in constructor with that name and
|
|
76
|
+
// len is the value of len.
|
|
77
|
+
A = new Array(len);
|
|
78
|
+
|
|
79
|
+
// 7. Let k be 0
|
|
80
|
+
k = 0;
|
|
81
|
+
|
|
82
|
+
// 8. Repeat, while k < len
|
|
83
|
+
while (k < len) {
|
|
84
|
+
|
|
85
|
+
var kValue, mappedValue;
|
|
86
|
+
|
|
87
|
+
// a. Let Pk be ToString(k).
|
|
88
|
+
// This is implicit for LHS operands of the in operator
|
|
89
|
+
// b. Let kPresent be the result of calling the HasProperty internal
|
|
90
|
+
// method of O with argument Pk.
|
|
91
|
+
// This step can be combined with c
|
|
92
|
+
// c. If kPresent is true, then
|
|
93
|
+
if (k in O) {
|
|
94
|
+
|
|
95
|
+
// i. Let kValue be the result of calling the Get internal
|
|
96
|
+
// method of O with argument Pk.
|
|
97
|
+
kValue = O[k];
|
|
98
|
+
|
|
99
|
+
// ii. Let mappedValue be the result of calling the Call internal
|
|
100
|
+
// method of callback with T as the this value and argument
|
|
101
|
+
// list containing kValue, k, and O.
|
|
102
|
+
mappedValue = callback.call(T, kValue, k, O);
|
|
103
|
+
|
|
104
|
+
// iii. Call the DefineOwnProperty internal method of A with arguments
|
|
105
|
+
// Pk, Property Descriptor
|
|
106
|
+
// { Value: mappedValue,
|
|
107
|
+
// Writable: true,
|
|
108
|
+
// Enumerable: true,
|
|
109
|
+
// Configurable: true },
|
|
110
|
+
// and false.
|
|
111
|
+
|
|
112
|
+
// In browsers that support Object.defineProperty, use the following:
|
|
113
|
+
// Object.defineProperty(A, k, {
|
|
114
|
+
// value: mappedValue,
|
|
115
|
+
// writable: true,
|
|
116
|
+
// enumerable: true,
|
|
117
|
+
// configurable: true
|
|
118
|
+
// });
|
|
119
|
+
|
|
120
|
+
// For best browser support, use the following:
|
|
121
|
+
A[k] = mappedValue;
|
|
122
|
+
}
|
|
123
|
+
// d. Increase k by 1.
|
|
124
|
+
k++;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 9. return A
|
|
128
|
+
return A;
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
`);
|
|
@@ -7,25 +7,26 @@ import {
|
|
|
7
7
|
Identifier,
|
|
8
8
|
Literal,
|
|
9
9
|
BinaryExpression,
|
|
10
|
-
LogicalExpression,
|
|
11
10
|
SwitchCase,
|
|
12
11
|
SwitchStatement,
|
|
13
|
-
SequenceExpression,
|
|
14
12
|
AssignmentExpression,
|
|
15
13
|
VariableDeclaration,
|
|
16
14
|
VariableDeclarator,
|
|
17
|
-
|
|
15
|
+
UnaryExpression,
|
|
18
16
|
} from "../util/gen";
|
|
19
17
|
import { prepend } from "../util/insert";
|
|
20
|
-
import { getBlock } from "../traverse";
|
|
21
18
|
import { choice, getRandomInteger } from "../util/random";
|
|
22
19
|
import { ObfuscateOrder } from "../order";
|
|
23
20
|
import { ok } from "assert";
|
|
24
21
|
import { OPERATOR_PRECEDENCE } from "../precedence";
|
|
25
22
|
import Template from "../templates/template";
|
|
23
|
+
import { ComputeProbabilityMap } from "../probability";
|
|
24
|
+
|
|
25
|
+
const allowedBinaryOperators = new Set(["+", "-", "*", "/"]);
|
|
26
|
+
const allowedUnaryOperators = new Set(["!", "void", "typeof", "-", "~", "+"]);
|
|
26
27
|
|
|
27
28
|
export default class Calculator extends Transform {
|
|
28
|
-
gen:
|
|
29
|
+
gen: ReturnType<Transform["getGenerator"]>;
|
|
29
30
|
ops: { [operator: string]: number };
|
|
30
31
|
statesUsed: Set<string>;
|
|
31
32
|
calculatorFn: string;
|
|
@@ -37,7 +38,7 @@ export default class Calculator extends Transform {
|
|
|
37
38
|
|
|
38
39
|
this.ops = Object.create(null);
|
|
39
40
|
this.statesUsed = new Set();
|
|
40
|
-
this.calculatorFn = this.getPlaceholder();
|
|
41
|
+
this.calculatorFn = this.getPlaceholder() + "_calc";
|
|
41
42
|
this.calculatorOpVar = this.getPlaceholder();
|
|
42
43
|
this.calculatorSetOpFn = this.getPlaceholder();
|
|
43
44
|
|
|
@@ -55,19 +56,29 @@ export default class Calculator extends Transform {
|
|
|
55
56
|
var rightArg = this.getPlaceholder();
|
|
56
57
|
var switchCases = [];
|
|
57
58
|
|
|
58
|
-
Object.keys(this.ops).forEach((
|
|
59
|
-
var
|
|
60
|
-
|
|
61
|
-
var
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
59
|
+
Object.keys(this.ops).forEach((opKey) => {
|
|
60
|
+
var [type, operator] = opKey.split("_");
|
|
61
|
+
|
|
62
|
+
var code = this.ops[opKey];
|
|
63
|
+
var body = [];
|
|
64
|
+
|
|
65
|
+
if (type === "Binary") {
|
|
66
|
+
body = [
|
|
67
|
+
ReturnStatement(
|
|
68
|
+
BinaryExpression(
|
|
69
|
+
operator,
|
|
70
|
+
Identifier(leftArg),
|
|
71
|
+
Identifier(rightArg)
|
|
72
|
+
)
|
|
73
|
+
),
|
|
74
|
+
];
|
|
75
|
+
} else if (type === "Unary") {
|
|
76
|
+
body = [
|
|
77
|
+
ReturnStatement(UnaryExpression(operator, Identifier(leftArg))),
|
|
78
|
+
];
|
|
79
|
+
} else {
|
|
80
|
+
throw new Error("Unknown type: " + type);
|
|
81
|
+
}
|
|
71
82
|
|
|
72
83
|
switchCases.push(SwitchCase(Literal(code), body));
|
|
73
84
|
});
|
|
@@ -95,70 +106,122 @@ export default class Calculator extends Transform {
|
|
|
95
106
|
}
|
|
96
107
|
|
|
97
108
|
match(object: Node, parents: Node[]) {
|
|
98
|
-
return
|
|
109
|
+
return (
|
|
110
|
+
object.type === "BinaryExpression" || object.type === "UnaryExpression"
|
|
111
|
+
);
|
|
99
112
|
}
|
|
100
113
|
|
|
101
114
|
transform(object: Node, parents: Node[]) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (!allowedOperators.has(operator)) {
|
|
115
|
+
// Allow percentage
|
|
116
|
+
if (!ComputeProbabilityMap(this.options.calculator)) {
|
|
105
117
|
return;
|
|
106
118
|
}
|
|
107
119
|
|
|
108
|
-
var
|
|
109
|
-
OPERATOR_PRECEDENCE[operator] +
|
|
110
|
-
Object.keys(OPERATOR_PRECEDENCE).indexOf(operator) / 100;
|
|
111
|
-
var precedences = parents.map(
|
|
112
|
-
(x) =>
|
|
113
|
-
x.type == "BinaryExpression" &&
|
|
114
|
-
OPERATOR_PRECEDENCE[x.operator] +
|
|
115
|
-
Object.keys(OPERATOR_PRECEDENCE).indexOf(x.operator) / 100
|
|
116
|
-
);
|
|
120
|
+
var operator = object.operator;
|
|
117
121
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
122
|
+
var type;
|
|
123
|
+
|
|
124
|
+
if (object.type === "BinaryExpression") {
|
|
125
|
+
type = "Binary";
|
|
126
|
+
|
|
127
|
+
if (!allowedBinaryOperators.has(operator)) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Additional checks to ensure complex expressions still work
|
|
132
|
+
var myPrecedence =
|
|
133
|
+
OPERATOR_PRECEDENCE[operator] +
|
|
134
|
+
Object.keys(OPERATOR_PRECEDENCE).indexOf(operator) / 100;
|
|
135
|
+
var precedences = parents.map(
|
|
136
|
+
(x) =>
|
|
137
|
+
x.type == "BinaryExpression" &&
|
|
138
|
+
OPERATOR_PRECEDENCE[x.operator] +
|
|
139
|
+
Object.keys(OPERATOR_PRECEDENCE).indexOf(x.operator) / 100
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
// corrupt AST
|
|
143
|
+
if (precedences.find((x) => x >= myPrecedence)) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (
|
|
147
|
+
parents.find((x) => x.$dispatcherSkip || x.type == "BinaryExpression")
|
|
148
|
+
) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
121
151
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
152
|
+
|
|
153
|
+
if (object.type === "UnaryExpression") {
|
|
154
|
+
type = "Unary";
|
|
155
|
+
|
|
156
|
+
if (!allowedUnaryOperators.has(operator)) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Typeof expression fix
|
|
161
|
+
if (operator === "typeof" && object.argument.type === "Identifier") {
|
|
162
|
+
// `typeof name` is special because it can reference the variable `name` without
|
|
163
|
+
// throwing any errors. If changed, an error could be thrown, breaking the users code
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
126
166
|
}
|
|
127
167
|
|
|
128
168
|
return () => {
|
|
129
|
-
|
|
169
|
+
const opKey = type + "_" + operator;
|
|
170
|
+
|
|
171
|
+
if (typeof this.ops[opKey] !== "number") {
|
|
130
172
|
var newState;
|
|
131
173
|
do {
|
|
132
174
|
newState = getRandomInteger(
|
|
133
|
-
-
|
|
134
|
-
|
|
175
|
+
-50,
|
|
176
|
+
50 + Object.keys(this.ops).length * 5
|
|
135
177
|
);
|
|
136
178
|
} while (this.statesUsed.has(newState));
|
|
137
179
|
|
|
138
180
|
ok(!isNaN(newState));
|
|
139
181
|
|
|
140
182
|
this.statesUsed.add(newState);
|
|
141
|
-
this.ops[
|
|
142
|
-
|
|
183
|
+
this.ops[opKey] = newState;
|
|
184
|
+
|
|
185
|
+
if (type === "Binary") {
|
|
186
|
+
this.log(
|
|
187
|
+
`left ${operator} right ->`,
|
|
188
|
+
`${this.calculatorFn}((${newState}, left, right)`
|
|
189
|
+
);
|
|
190
|
+
} else if (type === "Unary") {
|
|
191
|
+
this.log(
|
|
192
|
+
`${operator}(argument) ->`,
|
|
193
|
+
`${this.calculatorFn}(${newState}, argument)`
|
|
194
|
+
);
|
|
195
|
+
}
|
|
143
196
|
}
|
|
144
197
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
198
|
+
// The operator expression sets the operator to be used
|
|
199
|
+
var operatorExpression = choice([
|
|
200
|
+
AssignmentExpression(
|
|
201
|
+
"=",
|
|
202
|
+
Identifier(this.calculatorOpVar),
|
|
203
|
+
Literal(this.ops[opKey])
|
|
204
|
+
),
|
|
205
|
+
CallExpression(Identifier(this.calculatorSetOpFn), [
|
|
206
|
+
Literal(this.ops[opKey]),
|
|
207
|
+
]),
|
|
208
|
+
]);
|
|
209
|
+
|
|
210
|
+
var newExpression;
|
|
211
|
+
if (type === "Binary") {
|
|
212
|
+
newExpression = CallExpression(Identifier(this.calculatorFn), [
|
|
148
213
|
object.left,
|
|
149
214
|
object.right,
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
])
|
|
161
|
-
);
|
|
215
|
+
operatorExpression,
|
|
216
|
+
]);
|
|
217
|
+
} else {
|
|
218
|
+
newExpression = CallExpression(Identifier(this.calculatorFn), [
|
|
219
|
+
object.argument,
|
|
220
|
+
operatorExpression,
|
|
221
|
+
]);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
this.replace(object, newExpression);
|
|
162
225
|
};
|
|
163
226
|
}
|
|
164
227
|
}
|