|
|
@ -4,37 +4,37 @@ |
|
|
|
'use strict'; |
|
|
|
'use strict'; |
|
|
|
|
|
|
|
|
|
|
|
describe('function', function() { |
|
|
|
describe('function', function() { |
|
|
|
beforeEach(function () { |
|
|
|
beforeEach(function() { |
|
|
|
this.addMatchers({ |
|
|
|
this.addMatchers({ |
|
|
|
toMatchArray: function(expected) { |
|
|
|
toMatchArray: function(expected) { |
|
|
|
var actual = this.actual; |
|
|
|
var actual = this.actual; |
|
|
|
if (actual.length != expected.length) |
|
|
|
if (actual.length != expected.length) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
for (var i = 0; i < expected.length; i++) { |
|
|
|
for (var i = 0; i < expected.length; i++) { |
|
|
|
var a = actual[i], b = expected[i]; |
|
|
|
var a = actual[i], b = expected[i]; |
|
|
|
if (isArray(b)) { |
|
|
|
if (isArray(b)) { |
|
|
|
if (a.length != b.length) |
|
|
|
if (a.length != b.length) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
for (var j = 0; j < a.length; j++) { |
|
|
|
for (var j = 0; j < a.length; j++) { |
|
|
|
var suba = a[j], subb = b[j]; |
|
|
|
var suba = a[j], subb = b[j]; |
|
|
|
if (suba !== subb) |
|
|
|
if (suba !== subb) |
|
|
|
return false |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
if (a !== b) |
|
|
|
if (a !== b) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
describe('PostScriptParser', function() { |
|
|
|
describe('PostScriptParser', function() { |
|
|
|
function parse(program) { |
|
|
|
function parse(program) { |
|
|
|
var stream = new StringStream(program); |
|
|
|
var stream = new StringStream(program); |
|
|
|
var parser = new PostScriptParser(new PostScriptLexer(stream)); |
|
|
|
var parser = new PostScriptParser(new PostScriptLexer(stream)); |
|
|
|
return parser.parse(); |
|
|
|
return parser.parse(); |
|
|
|
} |
|
|
|
} |
|
|
|
it('parses empty programs', function() { |
|
|
|
it('parses empty programs', function() { |
|
|
|
var output = parse('{}'); |
|
|
|
var output = parse('{}'); |
|
|
@ -44,180 +44,179 @@ 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); |
|
|
|
}); |
|
|
|
}); |
|
|
|
it('parses negative numbers', function() { |
|
|
|
it('parses negative 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); |
|
|
|
}); |
|
|
|
}); |
|
|
|
it('parses negative floats', function() { |
|
|
|
it('parses negative floats', 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'] |
|
|
|
]; |
|
|
|
]; |
|
|
|
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', 2], |
|
|
|
['push', 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', 3], |
|
|
|
['push', 99], |
|
|
|
['push', 99], |
|
|
|
['j', 4], |
|
|
|
['j', 4], |
|
|
|
['push', 44], |
|
|
|
['push', 44] |
|
|
|
]; |
|
|
|
]; |
|
|
|
expect(program).toMatchArray(expectedProgram); |
|
|
|
expect(program).toMatchArray(expectedProgram); |
|
|
|
}); |
|
|
|
}); |
|
|
|
it('handles missing brackets', function() { |
|
|
|
it('handles missing brackets', function() { |
|
|
|
expect(function() { parse('{'); }).toThrow( |
|
|
|
expect(function() { parse('{'); }).toThrow( |
|
|
|
new Error('Unexpected symbol: found undefined expected 1.')); |
|
|
|
new Error('Unexpected symbol: found undefined expected 1.')); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
describe('PostScriptEvaluator', function() { |
|
|
|
describe('PostScriptEvaluator', function() { |
|
|
|
function evaluate(program) { |
|
|
|
function evaluate(program) { |
|
|
|
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); |
|
|
|
var output = evaluator.execute(); |
|
|
|
var output = evaluator.execute(); |
|
|
|
console.log(output); |
|
|
|
return output; |
|
|
|
return output; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
it('pushes stack', function() { |
|
|
|
it('pushes stack', function() { |
|
|
|
var stack = evaluate('{ 99 }'); |
|
|
|
var stack = evaluate('{ 99 }'); |
|
|
|
var expectedStack = [99]; |
|
|
|
var expectedStack = [99]; |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
}); |
|
|
|
}); |
|
|
|
it('handles if with true', function() { |
|
|
|
it('handles if with true', function() { |
|
|
|
var stack = evaluate('{ 1 {99} if }'); |
|
|
|
var stack = evaluate('{ 1 {99} if }'); |
|
|
|
var expectedStack = [99]; |
|
|
|
var expectedStack = [99]; |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
}); |
|
|
|
}); |
|
|
|
it('handles if with false', function() { |
|
|
|
it('handles if with false', function() { |
|
|
|
var stack = evaluate('{ 0 {99} if }'); |
|
|
|
var stack = evaluate('{ 0 {99} if }'); |
|
|
|
var expectedStack = []; |
|
|
|
var expectedStack = []; |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
}); |
|
|
|
}); |
|
|
|
it('handles ifelse with true', function() { |
|
|
|
it('handles ifelse with true', function() { |
|
|
|
var stack = evaluate('{ 1 {99} {77} ifelse }'); |
|
|
|
var stack = evaluate('{ 1 {99} {77} ifelse }'); |
|
|
|
var expectedStack = [99]; |
|
|
|
var expectedStack = [99]; |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
}); |
|
|
|
}); |
|
|
|
it('handles ifelse with false', function() { |
|
|
|
it('handles ifelse with false', function() { |
|
|
|
var stack = evaluate('{ 0 {99} {77} ifelse }'); |
|
|
|
var stack = evaluate('{ 0 {99} {77} ifelse }'); |
|
|
|
var expectedStack = [77]; |
|
|
|
var expectedStack = [77]; |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
}); |
|
|
|
}); |
|
|
|
it('handles nested if', function() { |
|
|
|
it('handles nested if', function() { |
|
|
|
var stack = evaluate('{ 1 {1 {77} if} if }'); |
|
|
|
var stack = evaluate('{ 1 {1 {77} if} if }'); |
|
|
|
var expectedStack = [77]; |
|
|
|
var expectedStack = [77]; |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it('abs', function() { |
|
|
|
it('abs', function() { |
|
|
|
var stack = evaluate('{ -2 abs }'); |
|
|
|
var stack = evaluate('{ -2 abs }'); |
|
|
|
var expectedStack = [2]; |
|
|
|
var expectedStack = [2]; |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
}); |
|
|
|
}); |
|
|
|
it('adds', function() { |
|
|
|
it('adds', function() { |
|
|
|
var stack = evaluate('{ 1 2 add }'); |
|
|
|
var stack = evaluate('{ 1 2 add }'); |
|
|
|
var expectedStack = [3]; |
|
|
|
var expectedStack = [3]; |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
}); |
|
|
|
}); |
|
|
|
it('boolean ands', function() { |
|
|
|
it('boolean ands', function() { |
|
|
|
var stack = evaluate('{ true false and }'); |
|
|
|
var stack = evaluate('{ true false and }'); |
|
|
|
var expectedStack = [false]; |
|
|
|
var expectedStack = [false]; |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
}); |
|
|
|
}); |
|
|
|
it('bitwise ands', function() { |
|
|
|
it('bitwise ands', function() { |
|
|
|
var stack = evaluate('{ 254 1 and }'); |
|
|
|
var stack = evaluate('{ 254 1 and }'); |
|
|
|
var expectedStack = [254 & 1]; |
|
|
|
var expectedStack = [254 & 1]; |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
}); |
|
|
|
}); |
|
|
|
// TODO atan
|
|
|
|
// TODO atan
|
|
|
|
// TODO bitshift
|
|
|
|
// TODO bitshift
|
|
|
|
// TODO ceiling
|
|
|
|
// TODO ceiling
|
|
|
|
// TODO copy
|
|
|
|
// TODO copy
|
|
|
|
// TODO cos
|
|
|
|
// TODO cos
|
|
|
|
// TODO cvi
|
|
|
|
// TODO cvi
|
|
|
|
// TODO cvr
|
|
|
|
// TODO cvr
|
|
|
|
// TODO div
|
|
|
|
// TODO div
|
|
|
|
it('duplicates', function() { |
|
|
|
it('duplicates', function() { |
|
|
|
var stack = evaluate('{ 99 dup }'); |
|
|
|
var stack = evaluate('{ 99 dup }'); |
|
|
|
var expectedStack = [99, 99]; |
|
|
|
var expectedStack = [99, 99]; |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
}); |
|
|
|
}); |
|
|
|
// TODO eq
|
|
|
|
// TODO eq
|
|
|
|
it('exchanges', function() { |
|
|
|
it('exchanges', function() { |
|
|
|
var stack = evaluate('{ 44 99 exch }'); |
|
|
|
var stack = evaluate('{ 44 99 exch }'); |
|
|
|
var expectedStack = [99, 44]; |
|
|
|
var expectedStack = [99, 44]; |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
}); |
|
|
|
}); |
|
|
|
// TODO exp
|
|
|
|
// TODO exp
|
|
|
|
// TODO false
|
|
|
|
// TODO false
|
|
|
|
// TODO floor
|
|
|
|
// TODO floor
|
|
|
|
// TODO ge
|
|
|
|
// TODO ge
|
|
|
|
// TODO gt
|
|
|
|
// TODO gt
|
|
|
|
// TODO idiv
|
|
|
|
// TODO idiv
|
|
|
|
it('duplicates index', function() { |
|
|
|
it('duplicates index', function() { |
|
|
|
var stack = evaluate('{ 4 3 2 1 2 index }'); |
|
|
|
var stack = evaluate('{ 4 3 2 1 2 index }'); |
|
|
|
var expectedStack = [4, 3, 2, 1, 3]; |
|
|
|
var expectedStack = [4, 3, 2, 1, 3]; |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
}); |
|
|
|
}); |
|
|
|
// TODO le
|
|
|
|
// TODO le
|
|
|
|
// TODO ln
|
|
|
|
// TODO ln
|
|
|
|
// TODO log
|
|
|
|
// TODO log
|
|
|
|
// TODO lt
|
|
|
|
// TODO lt
|
|
|
|
// TODO mod
|
|
|
|
// TODO mod
|
|
|
|
// TODO mul
|
|
|
|
// TODO mul
|
|
|
|
// TODO ne
|
|
|
|
// TODO ne
|
|
|
|
// TODO neg
|
|
|
|
// TODO neg
|
|
|
|
// TODO not
|
|
|
|
// TODO not
|
|
|
|
// TODO or
|
|
|
|
// TODO or
|
|
|
|
it('pops stack', function() { |
|
|
|
it('pops stack', function() { |
|
|
|
var stack = evaluate('{ 1 2 pop }'); |
|
|
|
var stack = evaluate('{ 1 2 pop }'); |
|
|
|
var expectedStack = [1]; |
|
|
|
var expectedStack = [1]; |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
}); |
|
|
|
}); |
|
|
|
it('rolls stack right', function() { |
|
|
|
it('rolls stack right', function() { |
|
|
|
var stack = evaluate('{ 1 3 2 2 4 1 roll }'); |
|
|
|
var stack = evaluate('{ 1 3 2 2 4 1 roll }'); |
|
|
|
var expectedStack = [2, 1, 3, 2]; |
|
|
|
var expectedStack = [2, 1, 3, 2]; |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
}); |
|
|
|
}); |
|
|
|
it('rolls stack left', function() { |
|
|
|
it('rolls stack left', function() { |
|
|
|
var stack = evaluate('{ 1 3 2 2 4 -1 roll }'); |
|
|
|
var stack = evaluate('{ 1 3 2 2 4 -1 roll }'); |
|
|
|
var expectedStack = [3, 2, 2, 1]; |
|
|
|
var expectedStack = [3, 2, 2, 1]; |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
expect(stack).toMatchArray(expectedStack); |
|
|
|
}); |
|
|
|
}); |
|
|
|
// TODO round
|
|
|
|
// TODO round
|
|
|
|
// TODO sin
|
|
|
|
// TODO sin
|
|
|
|
// TODO sqrt
|
|
|
|
// TODO sqrt
|
|
|
|
// TODO sub
|
|
|
|
// TODO sub
|
|
|
|
// TODO true
|
|
|
|
// TODO true
|
|
|
|
// TODO truncate
|
|
|
|
// TODO truncate
|
|
|
|
// TODO xor
|
|
|
|
// TODO xor
|
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|