From e69e8622a9ff67d9aa90e6ca655c1dde0847b74f Mon Sep 17 00:00:00 2001 From: Jonas Jenwald <jonas.jenwald@gmail.com> Date: Fri, 26 Feb 2021 13:15:07 +0100 Subject: [PATCH] Convert code in `src/core/function.js` to use "normal" classes All of this code predates the existence of native JS classes, however we can now clean this up a bit. This patch thus let us remove some variable "shadowing" from the code. --- src/core/function.js | 682 ++++++++++++++++++++++--------------------- 1 file changed, 353 insertions(+), 329 deletions(-) diff --git a/src/core/function.js b/src/core/function.js index 4dcee828e..a1f05114d 100644 --- a/src/core/function.js +++ b/src/core/function.js @@ -635,26 +635,28 @@ var PostScriptStack = (function PostScriptStackClosure() { var MAX_STACK_SIZE = 100; // eslint-disable-next-line no-shadow - function PostScriptStack(initialStack) { - this.stack = !initialStack - ? [] - : Array.prototype.slice.call(initialStack, 0); - } + class PostScriptStack { + constructor(initialStack) { + this.stack = !initialStack + ? [] + : Array.prototype.slice.call(initialStack, 0); + } - PostScriptStack.prototype = { - push: function PostScriptStack_push(value) { + push(value) { if (this.stack.length >= MAX_STACK_SIZE) { throw new Error("PostScript function stack overflow."); } this.stack.push(value); - }, - pop: function PostScriptStack_pop() { + } + + pop() { if (this.stack.length <= 0) { throw new Error("PostScript function stack underflow."); } return this.stack.pop(); - }, - copy: function PostScriptStack_copy(n) { + } + + copy(n) { if (this.stack.length + n >= MAX_STACK_SIZE) { throw new Error("PostScript function stack overflow."); } @@ -662,12 +664,14 @@ var PostScriptStack = (function PostScriptStackClosure() { for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) { stack.push(stack[i]); } - }, - index: function PostScriptStack_index(n) { + } + + index(n) { this.push(this.stack[this.stack.length - n - 1]); - }, + } + // rotate the last n stack elements p times - roll: function PostScriptStack_roll(n, p) { + roll(n, p) { var stack = this.stack; var l = stack.length - n; var r = stack.length - 1, @@ -690,246 +694,245 @@ var PostScriptStack = (function PostScriptStackClosure() { stack[i] = stack[j]; stack[j] = t; } - }, - }; + } + } + return PostScriptStack; })(); -var PostScriptEvaluator = (function PostScriptEvaluatorClosure() { - // eslint-disable-next-line no-shadow - function PostScriptEvaluator(operators) { + +class PostScriptEvaluator { + constructor(operators) { this.operators = operators; } - PostScriptEvaluator.prototype = { - execute: function PostScriptEvaluator_execute(initialStack) { - var stack = new PostScriptStack(initialStack); - var counter = 0; - var operators = this.operators; - var length = operators.length; - var operator, a, b; - while (counter < length) { - operator = operators[counter++]; - if (typeof operator === "number") { - // Operator is really an operand and should be pushed to the stack. - stack.push(operator); - continue; - } - switch (operator) { - // non standard ps operators - case "jz": // jump if false - b = stack.pop(); - a = stack.pop(); - if (!a) { - counter = b; - } - break; - case "j": // jump - a = stack.pop(); - counter = a; - break; - // all ps operators in alphabetical order (excluding if/ifelse) - case "abs": - a = stack.pop(); - stack.push(Math.abs(a)); - break; - case "add": - b = stack.pop(); - a = stack.pop(); - stack.push(a + b); - break; - case "and": - b = stack.pop(); - a = stack.pop(); - if (isBool(a) && isBool(b)) { - stack.push(a && b); - } else { - stack.push(a & b); - } - break; - case "atan": - a = stack.pop(); - stack.push(Math.atan(a)); - break; - case "bitshift": - b = stack.pop(); - a = stack.pop(); - if (a > 0) { - stack.push(a << b); - } else { - stack.push(a >> b); - } - break; - case "ceiling": - a = stack.pop(); - stack.push(Math.ceil(a)); - break; - case "copy": - a = stack.pop(); - stack.copy(a); - break; - case "cos": - a = stack.pop(); - stack.push(Math.cos(a)); - break; - case "cvi": - a = stack.pop() | 0; - stack.push(a); - break; - case "cvr": - // noop - break; - case "div": - b = stack.pop(); - a = stack.pop(); - stack.push(a / b); - break; - case "dup": - stack.copy(1); - break; - case "eq": - b = stack.pop(); - a = stack.pop(); - stack.push(a === b); - break; - case "exch": - stack.roll(2, 1); - break; - case "exp": - b = stack.pop(); - a = stack.pop(); - stack.push(a ** b); - break; - case "false": - stack.push(false); - break; - case "floor": - a = stack.pop(); - stack.push(Math.floor(a)); - break; - case "ge": - b = stack.pop(); - a = stack.pop(); - stack.push(a >= b); - break; - case "gt": - b = stack.pop(); - a = stack.pop(); - stack.push(a > b); - break; - case "idiv": - b = stack.pop(); - a = stack.pop(); - stack.push((a / b) | 0); - break; - case "index": - a = stack.pop(); - stack.index(a); - break; - case "le": - b = stack.pop(); - a = stack.pop(); - stack.push(a <= b); - break; - case "ln": - a = stack.pop(); - stack.push(Math.log(a)); - break; - case "log": - a = stack.pop(); - stack.push(Math.log(a) / Math.LN10); - break; - case "lt": - b = stack.pop(); - a = stack.pop(); - stack.push(a < b); - break; - case "mod": - b = stack.pop(); - a = stack.pop(); - stack.push(a % b); - break; - case "mul": - b = stack.pop(); - a = stack.pop(); - stack.push(a * b); - break; - case "ne": - b = stack.pop(); - a = stack.pop(); - stack.push(a !== b); - break; - case "neg": - a = stack.pop(); - stack.push(-a); - break; - case "not": - a = stack.pop(); - if (isBool(a)) { - stack.push(!a); - } else { - stack.push(~a); - } - break; - case "or": - b = stack.pop(); - a = stack.pop(); - if (isBool(a) && isBool(b)) { - stack.push(a || b); - } else { - stack.push(a | b); - } - break; - case "pop": - stack.pop(); - break; - case "roll": - b = stack.pop(); - a = stack.pop(); - stack.roll(a, b); - break; - case "round": - a = stack.pop(); - stack.push(Math.round(a)); - break; - case "sin": - a = stack.pop(); - stack.push(Math.sin(a)); - break; - case "sqrt": - a = stack.pop(); - stack.push(Math.sqrt(a)); - break; - case "sub": - b = stack.pop(); - a = stack.pop(); - stack.push(a - b); - break; - case "true": - stack.push(true); - break; - case "truncate": - a = stack.pop(); - a = a < 0 ? Math.ceil(a) : Math.floor(a); - stack.push(a); - break; - case "xor": - b = stack.pop(); - a = stack.pop(); - if (isBool(a) && isBool(b)) { - stack.push(a !== b); - } else { - stack.push(a ^ b); - } - break; - default: - throw new FormatError(`Unknown operator ${operator}`); - } + execute(initialStack) { + var stack = new PostScriptStack(initialStack); + var counter = 0; + var operators = this.operators; + var length = operators.length; + var operator, a, b; + while (counter < length) { + operator = operators[counter++]; + if (typeof operator === "number") { + // Operator is really an operand and should be pushed to the stack. + stack.push(operator); + continue; } - return stack.stack; - }, - }; - return PostScriptEvaluator; -})(); + switch (operator) { + // non standard ps operators + case "jz": // jump if false + b = stack.pop(); + a = stack.pop(); + if (!a) { + counter = b; + } + break; + case "j": // jump + a = stack.pop(); + counter = a; + break; + + // all ps operators in alphabetical order (excluding if/ifelse) + case "abs": + a = stack.pop(); + stack.push(Math.abs(a)); + break; + case "add": + b = stack.pop(); + a = stack.pop(); + stack.push(a + b); + break; + case "and": + b = stack.pop(); + a = stack.pop(); + if (isBool(a) && isBool(b)) { + stack.push(a && b); + } else { + stack.push(a & b); + } + break; + case "atan": + a = stack.pop(); + stack.push(Math.atan(a)); + break; + case "bitshift": + b = stack.pop(); + a = stack.pop(); + if (a > 0) { + stack.push(a << b); + } else { + stack.push(a >> b); + } + break; + case "ceiling": + a = stack.pop(); + stack.push(Math.ceil(a)); + break; + case "copy": + a = stack.pop(); + stack.copy(a); + break; + case "cos": + a = stack.pop(); + stack.push(Math.cos(a)); + break; + case "cvi": + a = stack.pop() | 0; + stack.push(a); + break; + case "cvr": + // noop + break; + case "div": + b = stack.pop(); + a = stack.pop(); + stack.push(a / b); + break; + case "dup": + stack.copy(1); + break; + case "eq": + b = stack.pop(); + a = stack.pop(); + stack.push(a === b); + break; + case "exch": + stack.roll(2, 1); + break; + case "exp": + b = stack.pop(); + a = stack.pop(); + stack.push(a ** b); + break; + case "false": + stack.push(false); + break; + case "floor": + a = stack.pop(); + stack.push(Math.floor(a)); + break; + case "ge": + b = stack.pop(); + a = stack.pop(); + stack.push(a >= b); + break; + case "gt": + b = stack.pop(); + a = stack.pop(); + stack.push(a > b); + break; + case "idiv": + b = stack.pop(); + a = stack.pop(); + stack.push((a / b) | 0); + break; + case "index": + a = stack.pop(); + stack.index(a); + break; + case "le": + b = stack.pop(); + a = stack.pop(); + stack.push(a <= b); + break; + case "ln": + a = stack.pop(); + stack.push(Math.log(a)); + break; + case "log": + a = stack.pop(); + stack.push(Math.log(a) / Math.LN10); + break; + case "lt": + b = stack.pop(); + a = stack.pop(); + stack.push(a < b); + break; + case "mod": + b = stack.pop(); + a = stack.pop(); + stack.push(a % b); + break; + case "mul": + b = stack.pop(); + a = stack.pop(); + stack.push(a * b); + break; + case "ne": + b = stack.pop(); + a = stack.pop(); + stack.push(a !== b); + break; + case "neg": + a = stack.pop(); + stack.push(-a); + break; + case "not": + a = stack.pop(); + if (isBool(a)) { + stack.push(!a); + } else { + stack.push(~a); + } + break; + case "or": + b = stack.pop(); + a = stack.pop(); + if (isBool(a) && isBool(b)) { + stack.push(a || b); + } else { + stack.push(a | b); + } + break; + case "pop": + stack.pop(); + break; + case "roll": + b = stack.pop(); + a = stack.pop(); + stack.roll(a, b); + break; + case "round": + a = stack.pop(); + stack.push(Math.round(a)); + break; + case "sin": + a = stack.pop(); + stack.push(Math.sin(a)); + break; + case "sqrt": + a = stack.pop(); + stack.push(Math.sqrt(a)); + break; + case "sub": + b = stack.pop(); + a = stack.pop(); + stack.push(a - b); + break; + case "true": + stack.push(true); + break; + case "truncate": + a = stack.pop(); + a = a < 0 ? Math.ceil(a) : Math.floor(a); + stack.push(a); + break; + case "xor": + b = stack.pop(); + a = stack.pop(); + if (isBool(a) && isBool(b)) { + stack.push(a !== b); + } else { + stack.push(a ^ b); + } + break; + default: + throw new FormatError(`Unknown operator ${operator}`); + } + } + return stack.stack; + } +} // Most of the PDFs functions consist of simple operations such as: // roll, exch, sub, cvr, pop, index, dup, mul, if, gt, add. @@ -938,84 +941,100 @@ var PostScriptEvaluator = (function PostScriptEvaluatorClosure() { // optimize some expressions using basic math properties. Keeping track of // min/max values will allow us to avoid extra Math.min/Math.max calls. var PostScriptCompiler = (function PostScriptCompilerClosure() { - function AstNode(type) { - this.type = type; - } - AstNode.prototype.visit = function (visitor) { - unreachable("abstract method"); - }; + class AstNode { + constructor(type) { + this.type = type; + } - function AstArgument(index, min, max) { - AstNode.call(this, "args"); - this.index = index; - this.min = min; - this.max = max; + visit(visitor) { + unreachable("abstract method"); + } } - AstArgument.prototype = Object.create(AstNode.prototype); - AstArgument.prototype.visit = function (visitor) { - visitor.visitArgument(this); - }; - function AstLiteral(number) { - AstNode.call(this, "literal"); - this.number = number; - this.min = number; - this.max = number; - } - AstLiteral.prototype = Object.create(AstNode.prototype); - AstLiteral.prototype.visit = function (visitor) { - visitor.visitLiteral(this); - }; + class AstArgument extends AstNode { + constructor(index, min, max) { + super("args"); + this.index = index; + this.min = min; + this.max = max; + } - function AstBinaryOperation(op, arg1, arg2, min, max) { - AstNode.call(this, "binary"); - this.op = op; - this.arg1 = arg1; - this.arg2 = arg2; - this.min = min; - this.max = max; + visit(visitor) { + visitor.visitArgument(this); + } } - AstBinaryOperation.prototype = Object.create(AstNode.prototype); - AstBinaryOperation.prototype.visit = function (visitor) { - visitor.visitBinaryOperation(this); - }; - function AstMin(arg, max) { - AstNode.call(this, "max"); - this.arg = arg; - this.min = arg.min; - this.max = max; - } - AstMin.prototype = Object.create(AstNode.prototype); - AstMin.prototype.visit = function (visitor) { - visitor.visitMin(this); - }; + class AstLiteral extends AstNode { + constructor(number) { + super("literal"); + this.number = number; + this.min = number; + this.max = number; + } - function AstVariable(index, min, max) { - AstNode.call(this, "var"); - this.index = index; - this.min = min; - this.max = max; + visit(visitor) { + visitor.visitLiteral(this); + } } - AstVariable.prototype = Object.create(AstNode.prototype); - AstVariable.prototype.visit = function (visitor) { - visitor.visitVariable(this); - }; - function AstVariableDefinition(variable, arg) { - AstNode.call(this, "definition"); - this.variable = variable; - this.arg = arg; - } - AstVariableDefinition.prototype = Object.create(AstNode.prototype); - AstVariableDefinition.prototype.visit = function (visitor) { - visitor.visitVariableDefinition(this); - }; + class AstBinaryOperation extends AstNode { + constructor(op, arg1, arg2, min, max) { + super("binary"); + this.op = op; + this.arg1 = arg1; + this.arg2 = arg2; + this.min = min; + this.max = max; + } - function ExpressionBuilderVisitor() { - this.parts = []; + visit(visitor) { + visitor.visitBinaryOperation(this); + } } - ExpressionBuilderVisitor.prototype = { + + class AstMin extends AstNode { + constructor(arg, max) { + super("max"); + this.arg = arg; + this.min = arg.min; + this.max = max; + } + + visit(visitor) { + visitor.visitMin(this); + } + } + + class AstVariable extends AstNode { + constructor(index, min, max) { + super("var"); + this.index = index; + this.min = min; + this.max = max; + } + + visit(visitor) { + visitor.visitVariable(this); + } + } + + class AstVariableDefinition extends AstNode { + constructor(variable, arg) { + super("definition"); + this.variable = variable; + this.arg = arg; + } + + visit(visitor) { + visitor.visitVariableDefinition(this); + } + } + + class ExpressionBuilderVisitor { + constructor() { + this.parts = []; + } + visitArgument(arg) { this.parts.push( "Math.max(", @@ -1026,36 +1045,42 @@ var PostScriptCompiler = (function PostScriptCompilerClosure() { arg.index, "]))" ); - }, + } + visitVariable(variable) { this.parts.push("v", variable.index); - }, + } + visitLiteral(literal) { this.parts.push(literal.number); - }, + } + visitBinaryOperation(operation) { this.parts.push("("); operation.arg1.visit(this); this.parts.push(" ", operation.op, " "); operation.arg2.visit(this); this.parts.push(")"); - }, + } + visitVariableDefinition(definition) { this.parts.push("var "); definition.variable.visit(this); this.parts.push(" = "); definition.arg.visit(this); this.parts.push(";"); - }, + } + visitMin(max) { this.parts.push("Math.min("); max.arg.visit(this); this.parts.push(", ", max.max, ")"); - }, + } + toString() { return this.parts.join(""); - }, - }; + } + } function buildAddOperation(num1, num2) { if (num2.type === "literal" && num2.number === 0) { @@ -1156,9 +1181,8 @@ var PostScriptCompiler = (function PostScriptCompilerClosure() { } // eslint-disable-next-line no-shadow - function PostScriptCompiler() {} - PostScriptCompiler.prototype = { - compile: function PostScriptCompiler_compile(code, domain, range) { + class PostScriptCompiler { + compile(code, domain, range) { var stack = []; var instructions = []; var inputSize = domain.length >> 1, @@ -1337,8 +1361,8 @@ var PostScriptCompiler = (function PostScriptCompilerClosure() { result.push(out.join("")); }); return result.join("\n"); - }, - }; + } + } return PostScriptCompiler; })();