UNPKG

quamvoluptatem

Version:
138 lines (116 loc) 3.62 kB
import Transform from "./transform"; import { Node, FunctionDeclaration, ReturnStatement, CallExpression, Identifier, Literal, BinaryExpression, LogicalExpression, SwitchCase, SwitchStatement, } from "../util/gen"; import { prepend } from "../util/insert"; import { getBlock } from "../traverse"; import { getRandomInteger } from "../util/random"; import { ObfuscateOrder } from "../order"; import { ok } from "assert"; import { OPERATOR_PRECEDENCE } from "../precedence"; export default class Calculator extends Transform { gen: any; ops: { [operator: string]: number }; statesUsed: Set<string>; calculatorFn: string; constructor(o) { super(o, ObfuscateOrder.Calculator); this.ops = Object.create(null); this.statesUsed = new Set(); this.calculatorFn = this.getPlaceholder(); this.gen = this.getGenerator(); } match(object: Node, parents: Node[]) { return object.type == "Program" || object.type == "BinaryExpression"; } transform(object: Node, parents: Node[]) { if (object.type == "Program") { return () => { var block = getBlock(object, parents); if (Object.keys(this.ops).length == 0) { return; } var opArg = this.getPlaceholder(); var leftArg = this.getPlaceholder(); var rightArg = this.getPlaceholder(); var switchCases = []; Object.keys(this.ops).forEach((operator) => { var code = this.ops[operator]; var factory = operator == "&&" || operator == "||" ? LogicalExpression : BinaryExpression; var body = [ ReturnStatement( factory(operator, Identifier(leftArg), Identifier(rightArg)) ), ]; switchCases.push(SwitchCase(Literal(code), body)); }); var func = FunctionDeclaration( this.calculatorFn, [opArg, leftArg, rightArg].map((x) => Identifier(x)), [SwitchStatement(Identifier(opArg), switchCases)] ); prepend(block, func); }; } if (object.type == "BinaryExpression") { var operator = object.operator; if (!{ "+": 1, "-": 1, "*": 1, "/": 1 }[object.operator]) { return; } var myPrecedence = OPERATOR_PRECEDENCE[operator] + Object.keys(OPERATOR_PRECEDENCE).indexOf(operator) / 100; var maxParentPrecedence = parents .map( (x) => x.type == "BinaryExpression" && OPERATOR_PRECEDENCE[x.operator] + Object.keys(OPERATOR_PRECEDENCE).indexOf(x.operator) / 100 ) .sort() .pop(); // corrupt AST if (maxParentPrecedence && maxParentPrecedence > myPrecedence) { return; } return () => { if (parents.find((x) => x.$dispatcherSkip)) { return; } if (typeof this.ops[operator] !== "number") { var newState; do { newState = getRandomInteger( -1000, 1000 + Object.keys(this.ops).length * 5 ); } while (this.statesUsed.has(newState)); ok(!isNaN(newState)); this.statesUsed.add(newState); this.ops[operator] = newState; this.log(operator, `calc(${newState}, left, right)`); } this.replace( object, CallExpression(Identifier(this.calculatorFn), [ Literal(this.ops[operator]), { ...object.left }, { ...object.right }, ]) ); }; } } }