Switch to two arrays for instructions.
This commit is contained in:
parent
971f35d165
commit
27b0d0c941
@ -360,7 +360,7 @@ var PDFFunction = (function PDFFunctionClosure() {
|
|||||||
var range = IR[2];
|
var range = IR[2];
|
||||||
var code = IR[3];
|
var code = IR[3];
|
||||||
var numOutputs = range.length / 2;
|
var numOutputs = range.length / 2;
|
||||||
var evaluator = new PostScriptEvaluator(code);
|
var evaluator = new PostScriptEvaluator(code[0], code[1]);
|
||||||
// Cache the values for a big speed up, the cache size is limited though
|
// Cache the values for a big speed up, the cache size is limited though
|
||||||
// since the number of possible values can be huge from a PS function.
|
// since the number of possible values can be huge from a PS function.
|
||||||
var cache = new FunctionCache();
|
var cache = new FunctionCache();
|
||||||
@ -455,31 +455,36 @@ var PostScriptStack = (function PostScriptStack() {
|
|||||||
return PostScriptStack;
|
return PostScriptStack;
|
||||||
})();
|
})();
|
||||||
var PostScriptEvaluator = (function PostScriptEvaluator() {
|
var PostScriptEvaluator = (function PostScriptEvaluator() {
|
||||||
function PostScriptEvaluator(code) {
|
function PostScriptEvaluator(operators, operands) {
|
||||||
this.code = code;
|
this.operators = operators;
|
||||||
console.log(code);
|
this.operands = operands;
|
||||||
}
|
}
|
||||||
PostScriptEvaluator.prototype = {
|
PostScriptEvaluator.prototype = {
|
||||||
execute: function(initialStack) {
|
execute: function(initialStack) {
|
||||||
var stack = new PostScriptStack(initialStack);
|
var stack = new PostScriptStack(initialStack);
|
||||||
var counter = 0;
|
var counter = 0;
|
||||||
var code = this.code;
|
var operators = this.operators;
|
||||||
var a, b;
|
var operands = this.operands;
|
||||||
while (counter < this.code.length) {
|
var length = operators.length;
|
||||||
var instruction = this.code[counter++];
|
var a, b, operand;
|
||||||
var operator = instruction[0];
|
while (counter < length) {
|
||||||
|
var operator = operators[counter];
|
||||||
|
++counter;
|
||||||
switch (operator) {
|
switch (operator) {
|
||||||
// non standard ps operators
|
// non standard ps operators
|
||||||
case 'push':
|
case 'push':
|
||||||
stack.push(instruction[1]);
|
operand = operands[counter - 1];
|
||||||
|
stack.push(operand);
|
||||||
break;
|
break;
|
||||||
case 'jz': // jump if false
|
case 'jz': // jump if false
|
||||||
|
operand = operands[counter - 1];
|
||||||
a = stack.pop();
|
a = stack.pop();
|
||||||
if (!a)
|
if (!a)
|
||||||
counter = instruction[1];
|
counter = operand;
|
||||||
break;
|
break;
|
||||||
case 'j': // jump
|
case 'j': // jump
|
||||||
counter = instruction[1];
|
operand = operands[counter - 1];
|
||||||
|
counter = operand;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// all ps operators in alphabetical order (excluding if/ifelse)
|
// all ps operators in alphabetical order (excluding if/ifelse)
|
||||||
@ -690,7 +695,8 @@ var PostScriptEvaluator = (function PostScriptEvaluator() {
|
|||||||
var PostScriptParser = (function PostScriptParser() {
|
var PostScriptParser = (function PostScriptParser() {
|
||||||
function PostScriptParser(lexer) {
|
function PostScriptParser(lexer) {
|
||||||
this.lexer = lexer;
|
this.lexer = lexer;
|
||||||
this.code = [];
|
this.operators = [];
|
||||||
|
this.operands = [];
|
||||||
this.token;
|
this.token;
|
||||||
this.prev;
|
this.prev;
|
||||||
}
|
}
|
||||||
@ -717,14 +723,16 @@ var PostScriptParser = (function PostScriptParser() {
|
|||||||
this.expect(PostScriptTokenTypes.LBRACE);
|
this.expect(PostScriptTokenTypes.LBRACE);
|
||||||
this.parseBlock();
|
this.parseBlock();
|
||||||
this.expect(PostScriptTokenTypes.RBRACE);
|
this.expect(PostScriptTokenTypes.RBRACE);
|
||||||
return this.code;
|
return [this.operators, this.operands];
|
||||||
},
|
},
|
||||||
parseBlock: function parseBlock() {
|
parseBlock: function parseBlock() {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (this.accept(PostScriptTokenTypes.NUMBER)) {
|
if (this.accept(PostScriptTokenTypes.NUMBER)) {
|
||||||
this.code.push(['push', this.prev.value]);
|
this.operators.push('push');
|
||||||
|
this.operands.push(this.prev.value);
|
||||||
} else if (this.accept(PostScriptTokenTypes.OPERATOR)) {
|
} else if (this.accept(PostScriptTokenTypes.OPERATOR)) {
|
||||||
this.code.push([this.prev.value]);
|
this.operators.push(this.prev.value);
|
||||||
|
this.operands.push(null);
|
||||||
} else if (this.accept(PostScriptTokenTypes.LBRACE)) {
|
} else if (this.accept(PostScriptTokenTypes.LBRACE)) {
|
||||||
this.parseCondition();
|
this.parseCondition();
|
||||||
} else {
|
} else {
|
||||||
@ -733,26 +741,33 @@ var PostScriptParser = (function PostScriptParser() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
parseCondition: function parseCondition() {
|
parseCondition: function parseCondition() {
|
||||||
var counter = this.code.length - 1;
|
// Add two place holders that will be updated later
|
||||||
var condition = [];
|
var conditionLocation = this.operators.length;
|
||||||
this.code.push(condition);
|
this.operators.push(null);
|
||||||
|
this.operands.push(null);
|
||||||
|
|
||||||
this.parseBlock();
|
this.parseBlock();
|
||||||
this.expect(PostScriptTokenTypes.RBRACE);
|
this.expect(PostScriptTokenTypes.RBRACE);
|
||||||
if (this.accept(PostScriptTokenTypes.IF)) {
|
if (this.accept(PostScriptTokenTypes.IF)) {
|
||||||
// The true block is right after the 'if' so it just falls through on
|
// The true block is right after the 'if' so it just falls through on
|
||||||
// true else it jumps and skips the true block.
|
// true else it jumps and skips the true block.
|
||||||
condition.push('jz', this.code.length);
|
this.operators[conditionLocation] = 'jz';
|
||||||
|
this.operands[conditionLocation] = this.operators.length;
|
||||||
} else if (this.accept(PostScriptTokenTypes.LBRACE)) {
|
} else if (this.accept(PostScriptTokenTypes.LBRACE)) {
|
||||||
var jump = [];
|
var jumpLocation = this.operators.length;
|
||||||
this.code.push(jump);
|
this.operators.push(null);
|
||||||
var endOfTrue = this.code.length;
|
this.operands.push(null);
|
||||||
|
var endOfTrue = this.operators.length;
|
||||||
this.parseBlock();
|
this.parseBlock();
|
||||||
this.expect(PostScriptTokenTypes.RBRACE);
|
this.expect(PostScriptTokenTypes.RBRACE);
|
||||||
this.expect(PostScriptTokenTypes.IFELSE);
|
this.expect(PostScriptTokenTypes.IFELSE);
|
||||||
// The jump is added at the end of the true block to skip the false
|
// The jump is added at the end of the true block to skip the false
|
||||||
// block.
|
// block.
|
||||||
jump.push('j', this.code.length);
|
this.operators[jumpLocation] = 'j';
|
||||||
condition.push('jz', endOfTrue);
|
this.operands[jumpLocation] = this.operands.length;
|
||||||
|
|
||||||
|
this.operators[conditionLocation] = 'jz';
|
||||||
|
this.operands[conditionLocation] = endOfTrue;
|
||||||
} else {
|
} else {
|
||||||
error('PS Function: error parsing conditional.');
|
error('PS Function: error parsing conditional.');
|
||||||
}
|
}
|
||||||
|
@ -38,13 +38,13 @@ describe('function', function() {
|
|||||||
}
|
}
|
||||||
it('parses empty programs', function() {
|
it('parses empty programs', function() {
|
||||||
var output = parse('{}');
|
var output = parse('{}');
|
||||||
expect(output.length).toEqual(0);
|
expect(output[0].length).toEqual(0);
|
||||||
});
|
});
|
||||||
it('parses positive numbers', function() {
|
it('parses positive numbers', function() {
|
||||||
var number = 999;
|
var number = 999;
|
||||||
var program = parse('{ ' + number + ' }');
|
var program = parse('{ ' + number + ' }');
|
||||||
var expectedProgram = [
|
var expectedProgram = [
|
||||||
['push', number]
|
['push'], [number]
|
||||||
];
|
];
|
||||||
expect(program).toMatchArray(expectedProgram);
|
expect(program).toMatchArray(expectedProgram);
|
||||||
});
|
});
|
||||||
@ -52,7 +52,7 @@ describe('function', function() {
|
|||||||
var number = -999;
|
var number = -999;
|
||||||
var program = parse('{ ' + number + ' }');
|
var program = parse('{ ' + number + ' }');
|
||||||
var expectedProgram = [
|
var expectedProgram = [
|
||||||
['push', number]
|
['push'], [number]
|
||||||
];
|
];
|
||||||
expect(program).toMatchArray(expectedProgram);
|
expect(program).toMatchArray(expectedProgram);
|
||||||
});
|
});
|
||||||
@ -60,32 +60,28 @@ describe('function', function() {
|
|||||||
var number = 3.3;
|
var number = 3.3;
|
||||||
var program = parse('{ ' + number + ' }');
|
var program = parse('{ ' + number + ' }');
|
||||||
var expectedProgram = [
|
var expectedProgram = [
|
||||||
['push', number]
|
['push'], [number]
|
||||||
];
|
];
|
||||||
expect(program).toMatchArray(expectedProgram);
|
expect(program).toMatchArray(expectedProgram);
|
||||||
});
|
});
|
||||||
it('parses operators', function() {
|
it('parses operators', function() {
|
||||||
var program = parse('{ sub }');
|
var program = parse('{ sub }');
|
||||||
var expectedProgram = [
|
var expectedProgram = [
|
||||||
['sub']
|
['sub'], [null]
|
||||||
];
|
];
|
||||||
expect(program).toMatchArray(expectedProgram);
|
expect(program).toMatchArray(expectedProgram);
|
||||||
});
|
});
|
||||||
it('parses if statements', function() {
|
it('parses if statements', function() {
|
||||||
var program = parse('{ { 99 } if }');
|
var program = parse('{ { 99 } if }');
|
||||||
var expectedProgram = [
|
var expectedProgram = [
|
||||||
['jz', 2],
|
['jz', 'push'], [2, 99]
|
||||||
['push', 99]
|
|
||||||
];
|
];
|
||||||
expect(program).toMatchArray(expectedProgram);
|
expect(program).toMatchArray(expectedProgram);
|
||||||
});
|
});
|
||||||
it('parses ifelse statements', function() {
|
it('parses ifelse statements', function() {
|
||||||
var program = parse('{ { 99 } { 44 } ifelse }');
|
var program = parse('{ { 99 } { 44 } ifelse }');
|
||||||
var expectedProgram = [
|
var expectedProgram = [
|
||||||
['jz', 3],
|
['jz', 'push', 'j', 'push'], [3, 99, 4, 44]
|
||||||
['push', 99],
|
|
||||||
['j', 4],
|
|
||||||
['push', 44]
|
|
||||||
];
|
];
|
||||||
expect(program).toMatchArray(expectedProgram);
|
expect(program).toMatchArray(expectedProgram);
|
||||||
});
|
});
|
||||||
@ -100,7 +96,7 @@ describe('function', function() {
|
|||||||
var stream = new StringStream(program);
|
var stream = new StringStream(program);
|
||||||
var parser = new PostScriptParser(new PostScriptLexer(stream));
|
var parser = new PostScriptParser(new PostScriptLexer(stream));
|
||||||
var code = parser.parse();
|
var code = parser.parse();
|
||||||
var evaluator = new PostScriptEvaluator(code);
|
var evaluator = new PostScriptEvaluator(code[0], code[1]);
|
||||||
var output = evaluator.execute();
|
var output = evaluator.execute();
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user