parser.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. // Copyright 2019 Google LLC
  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. import { TokenType } from "./token.js";
  15. import * as AST from "./ast.js";
  16. export default class Parser {
  17. /**
  18. * @param {Hash} The SPIR-V grammar
  19. * @param {Lexer} The lexer
  20. * @return {AST} Attempts to build an AST from the tokens returned by the
  21. * given lexer
  22. */
  23. constructor(grammar, lexer) {
  24. this.grammar_ = grammar;
  25. this.lexer_ = lexer;
  26. this.peek_ = [];
  27. this.error_ = "";
  28. }
  29. get error() { return this.error_; }
  30. next() {
  31. return this.peek_.shift() || this.lexer_.next();
  32. }
  33. peek(idx) {
  34. while (this.peek_.length <= idx) {
  35. this.peek_.push(this.lexer_.next());
  36. }
  37. return this.peek_[idx];
  38. }
  39. /**
  40. * Executes the parser.
  41. *
  42. * @return {AST|undefined} returns a parsed AST on success or undefined
  43. * on error. The error message can be retrieved by
  44. * calling error().
  45. */
  46. parse() {
  47. let ast = new AST.Module();
  48. for(;;) {
  49. let token = this.next();
  50. if (token === TokenType.kError) {
  51. this.error_ = token.line() + ": " + token.data();
  52. return undefined;
  53. }
  54. if (token.type === TokenType.kEOF)
  55. break;
  56. let result_id = undefined;
  57. if (token.type === TokenType.kResultId) {
  58. result_id = token;
  59. token = this.next();
  60. if (token.type !== TokenType.kEqual) {
  61. this.error_ = token.line + ": expected = after result id";
  62. return undefined;
  63. }
  64. token = this.next();
  65. }
  66. if (token.type !== TokenType.kOp) {
  67. this.error_ = token.line + ": expected Op got " + token.type;
  68. return undefined;
  69. }
  70. let name = token.data.name;
  71. let data = this.getInstructionData(name);
  72. let operands = [];
  73. let result_type = undefined;
  74. for (let operand of data.operands) {
  75. if (operand.kind === "IdResult") {
  76. if (result_id === undefined) {
  77. this.error_ = token.line + ": expected result id";
  78. return undefined;
  79. }
  80. let o = new AST.Operand(ast, result_id.data.name, "result_id",
  81. result_id.data.val, []);
  82. if (o === undefined) {
  83. return undefined;
  84. }
  85. operands.push(o);
  86. } else {
  87. if (operand.quantifier === "?") {
  88. if (this.nextIsNewInstr()) {
  89. break;
  90. }
  91. } else if (operand.quantifier === "*") {
  92. while (!this.nextIsNewInstr()) {
  93. let o = this.extractOperand(ast, result_type, operand);
  94. if (o === undefined) {
  95. return undefined;
  96. }
  97. operands.push(o);
  98. }
  99. break;
  100. }
  101. let o = this.extractOperand(ast, result_type, operand);
  102. if (o === undefined) {
  103. return undefined;
  104. }
  105. // Store the result type away so we can use it for context dependent
  106. // numbers if needed.
  107. if (operand.kind === "IdResultType") {
  108. result_type = ast.getType(o.name());
  109. }
  110. operands.push(o);
  111. }
  112. }
  113. // Verify only GLSL extended instructions are used
  114. if (name === "OpExtInstImport" && operands[1].value() !== "GLSL.std.450") {
  115. this.error_ = token.line + ": Only GLSL.std.450 external instructions supported";
  116. return undefined;
  117. }
  118. let inst = new AST.Instruction(name, data.opcode, operands);
  119. ast.addInstruction(inst);
  120. }
  121. return ast;
  122. }
  123. getInstructionData(name) {
  124. return this.grammar_["instructions"][name];
  125. }
  126. nextIsNewInstr() {
  127. let n0 = this.peek(0);
  128. if (n0.type === TokenType.kOp || n0.type === TokenType.kEOF) {
  129. return true;
  130. }
  131. let n1 = this.peek(1);
  132. if (n1.type === TokenType.kEOF) {
  133. return false;
  134. }
  135. if (n0.type === TokenType.kResultId && n1.type === TokenType.kEqual)
  136. return true;
  137. return false;
  138. }
  139. extractOperand(ast, result_type, data) {
  140. let t = this.next();
  141. let name = undefined;
  142. let kind = undefined;
  143. let value = undefined;
  144. let params = [];
  145. // TODO(dsinclair): There are a bunch of missing types here. See
  146. // https://github.com/KhronosGroup/SPIRV-Tools/blob/master/source/text.cpp#L210
  147. //
  148. // LiteralSpecConstantOpInteger
  149. // PairLiteralIntegerIdRef
  150. // PairIdRefLiteralInteger
  151. // PairIdRefIdRef
  152. if (data.kind === "IdResult" || data.kind === "IdRef"
  153. || data.kind === "IdResultType" || data.kind === "IdScope"
  154. || data.kind === "IdMemorySemantics") {
  155. if (t.type !== TokenType.kResultId) {
  156. this.error_ = t.line + ": expected result id";
  157. return undefined;
  158. }
  159. name = t.data.name;
  160. kind = "result_id";
  161. value = t.data.val;
  162. } else if (data.kind === "LiteralString") {
  163. if (t.type !== TokenType.kStringLiteral) {
  164. this.error_ = t.line + ": expected string not found";
  165. return undefined;
  166. }
  167. name = t.data;
  168. kind = "string";
  169. value = t.data;
  170. } else if (data.kind === "LiteralInteger") {
  171. if (t.type !== TokenType.kIntegerLiteral) {
  172. this.error_ = t.line + ": expected integer not found";
  173. return undefined;
  174. }
  175. name = "" + t.data;
  176. kind = t.type;
  177. value = t.data;
  178. } else if (data.kind === "LiteralContextDependentNumber") {
  179. if (result_type === undefined) {
  180. this.error_ = t.line +
  181. ": missing result type for context dependent number";
  182. return undefined;
  183. }
  184. if (t.type !== TokenType.kIntegerLiteral
  185. && t.type !== TokenType.kFloatLiteral) {
  186. this.error_ = t.line + ": expected number not found";
  187. return undefined;
  188. }
  189. name = "" + t.data;
  190. kind = result_type.type;
  191. value = t.data;
  192. } else if (data.kind === "LiteralExtInstInteger") {
  193. if (t.type !== TokenType.kIdentifier) {
  194. this.error_ = t.line + ": expected instruction identifier";
  195. return undefined;
  196. }
  197. if (this.grammar_.ext[t.data] === undefined) {
  198. this.error_ = t.line + `: unable to find extended instruction (${t.data})`;
  199. return undefined;
  200. }
  201. name = t.data;
  202. kind = "integer";
  203. value = this.grammar_.ext[t.data];
  204. } else {
  205. let d = this.grammar_.operand_kinds[data.kind];
  206. if (d === undefined) {
  207. this.error_ = t.line + ": expected " + data.kind + " not found";
  208. return undefined;
  209. }
  210. let val = d.values[t.data]["value"];
  211. let names = [t.data];
  212. if (d.type === "BitEnum") {
  213. for(;;) {
  214. let tmp = this.peek(0);
  215. if (tmp.type !== TokenType.kPipe) {
  216. break;
  217. }
  218. this.next(); // skip pipe
  219. tmp = this.next();
  220. if (tmp.type !== TokenType.kIdentifier) {
  221. this.error_ = tmp.line() + ": expected identifier";
  222. return undefined;
  223. }
  224. val |= d.values[tmp.data]["value"];
  225. names.push(tmp.data);
  226. }
  227. }
  228. name = names.join("|");
  229. kind = d.type;
  230. value = val;
  231. for (const op_name of names) {
  232. if (d.values[op_name]['params'] === undefined) {
  233. continue;
  234. }
  235. for (const param of d.values[op_name]["params"]) {
  236. params.push(this.extractOperand(ast, result_type, { kind: param }));
  237. }
  238. }
  239. }
  240. return new AST.Operand(ast, name, kind, value, params);
  241. }
  242. }