2
0

ps_parser.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /* Copyright 2017 Mozilla Foundation
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. 'use strict';
  16. var sharedUtil = require('../shared/util.js');
  17. var corePrimitives = require('./primitives.js');
  18. var error = sharedUtil.error;
  19. var isSpace = sharedUtil.isSpace;
  20. var EOF = corePrimitives.EOF;
  21. var PostScriptParser = function PostScriptParserClosure() {
  22. function PostScriptParser(lexer) {
  23. this.lexer = lexer;
  24. this.operators = [];
  25. this.token = null;
  26. this.prev = null;
  27. }
  28. PostScriptParser.prototype = {
  29. nextToken: function PostScriptParser_nextToken() {
  30. this.prev = this.token;
  31. this.token = this.lexer.getToken();
  32. },
  33. accept: function PostScriptParser_accept(type) {
  34. if (this.token.type === type) {
  35. this.nextToken();
  36. return true;
  37. }
  38. return false;
  39. },
  40. expect: function PostScriptParser_expect(type) {
  41. if (this.accept(type)) {
  42. return true;
  43. }
  44. error('Unexpected symbol: found ' + this.token.type + ' expected ' + type + '.');
  45. },
  46. parse: function PostScriptParser_parse() {
  47. this.nextToken();
  48. this.expect(PostScriptTokenTypes.LBRACE);
  49. this.parseBlock();
  50. this.expect(PostScriptTokenTypes.RBRACE);
  51. return this.operators;
  52. },
  53. parseBlock: function PostScriptParser_parseBlock() {
  54. while (true) {
  55. if (this.accept(PostScriptTokenTypes.NUMBER)) {
  56. this.operators.push(this.prev.value);
  57. } else if (this.accept(PostScriptTokenTypes.OPERATOR)) {
  58. this.operators.push(this.prev.value);
  59. } else if (this.accept(PostScriptTokenTypes.LBRACE)) {
  60. this.parseCondition();
  61. } else {
  62. return;
  63. }
  64. }
  65. },
  66. parseCondition: function PostScriptParser_parseCondition() {
  67. var conditionLocation = this.operators.length;
  68. this.operators.push(null, null);
  69. this.parseBlock();
  70. this.expect(PostScriptTokenTypes.RBRACE);
  71. if (this.accept(PostScriptTokenTypes.IF)) {
  72. this.operators[conditionLocation] = this.operators.length;
  73. this.operators[conditionLocation + 1] = 'jz';
  74. } else if (this.accept(PostScriptTokenTypes.LBRACE)) {
  75. var jumpLocation = this.operators.length;
  76. this.operators.push(null, null);
  77. var endOfTrue = this.operators.length;
  78. this.parseBlock();
  79. this.expect(PostScriptTokenTypes.RBRACE);
  80. this.expect(PostScriptTokenTypes.IFELSE);
  81. this.operators[jumpLocation] = this.operators.length;
  82. this.operators[jumpLocation + 1] = 'j';
  83. this.operators[conditionLocation] = endOfTrue;
  84. this.operators[conditionLocation + 1] = 'jz';
  85. } else {
  86. error('PS Function: error parsing conditional.');
  87. }
  88. }
  89. };
  90. return PostScriptParser;
  91. }();
  92. var PostScriptTokenTypes = {
  93. LBRACE: 0,
  94. RBRACE: 1,
  95. NUMBER: 2,
  96. OPERATOR: 3,
  97. IF: 4,
  98. IFELSE: 5
  99. };
  100. var PostScriptToken = function PostScriptTokenClosure() {
  101. function PostScriptToken(type, value) {
  102. this.type = type;
  103. this.value = value;
  104. }
  105. var opCache = Object.create(null);
  106. PostScriptToken.getOperator = function PostScriptToken_getOperator(op) {
  107. var opValue = opCache[op];
  108. if (opValue) {
  109. return opValue;
  110. }
  111. return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op);
  112. };
  113. PostScriptToken.LBRACE = new PostScriptToken(PostScriptTokenTypes.LBRACE, '{');
  114. PostScriptToken.RBRACE = new PostScriptToken(PostScriptTokenTypes.RBRACE, '}');
  115. PostScriptToken.IF = new PostScriptToken(PostScriptTokenTypes.IF, 'IF');
  116. PostScriptToken.IFELSE = new PostScriptToken(PostScriptTokenTypes.IFELSE, 'IFELSE');
  117. return PostScriptToken;
  118. }();
  119. var PostScriptLexer = function PostScriptLexerClosure() {
  120. function PostScriptLexer(stream) {
  121. this.stream = stream;
  122. this.nextChar();
  123. this.strBuf = [];
  124. }
  125. PostScriptLexer.prototype = {
  126. nextChar: function PostScriptLexer_nextChar() {
  127. return this.currentChar = this.stream.getByte();
  128. },
  129. getToken: function PostScriptLexer_getToken() {
  130. var comment = false;
  131. var ch = this.currentChar;
  132. while (true) {
  133. if (ch < 0) {
  134. return EOF;
  135. }
  136. if (comment) {
  137. if (ch === 0x0A || ch === 0x0D) {
  138. comment = false;
  139. }
  140. } else if (ch === 0x25) {
  141. comment = true;
  142. } else if (!isSpace(ch)) {
  143. break;
  144. }
  145. ch = this.nextChar();
  146. }
  147. switch (ch | 0) {
  148. case 0x30:
  149. case 0x31:
  150. case 0x32:
  151. case 0x33:
  152. case 0x34:
  153. case 0x35:
  154. case 0x36:
  155. case 0x37:
  156. case 0x38:
  157. case 0x39:
  158. case 0x2B:
  159. case 0x2D:
  160. case 0x2E:
  161. return new PostScriptToken(PostScriptTokenTypes.NUMBER, this.getNumber());
  162. case 0x7B:
  163. this.nextChar();
  164. return PostScriptToken.LBRACE;
  165. case 0x7D:
  166. this.nextChar();
  167. return PostScriptToken.RBRACE;
  168. }
  169. var strBuf = this.strBuf;
  170. strBuf.length = 0;
  171. strBuf[0] = String.fromCharCode(ch);
  172. while ((ch = this.nextChar()) >= 0 && (ch >= 0x41 && ch <= 0x5A || ch >= 0x61 && ch <= 0x7A)) {
  173. strBuf.push(String.fromCharCode(ch));
  174. }
  175. var str = strBuf.join('');
  176. switch (str.toLowerCase()) {
  177. case 'if':
  178. return PostScriptToken.IF;
  179. case 'ifelse':
  180. return PostScriptToken.IFELSE;
  181. default:
  182. return PostScriptToken.getOperator(str);
  183. }
  184. },
  185. getNumber: function PostScriptLexer_getNumber() {
  186. var ch = this.currentChar;
  187. var strBuf = this.strBuf;
  188. strBuf.length = 0;
  189. strBuf[0] = String.fromCharCode(ch);
  190. while ((ch = this.nextChar()) >= 0) {
  191. if (ch >= 0x30 && ch <= 0x39 || ch === 0x2D || ch === 0x2E) {
  192. strBuf.push(String.fromCharCode(ch));
  193. } else {
  194. break;
  195. }
  196. }
  197. var value = parseFloat(strBuf.join(''));
  198. if (isNaN(value)) {
  199. error('Invalid floating point number: ' + value);
  200. }
  201. return value;
  202. }
  203. };
  204. return PostScriptLexer;
  205. }();
  206. exports.PostScriptLexer = PostScriptLexer;
  207. exports.PostScriptParser = PostScriptParser;