grammar.js 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.parse = parse;
  6. var _helperCodeFrame = require("@webassemblyjs/helper-code-frame");
  7. var t = _interopRequireWildcard(require("@webassemblyjs/ast"));
  8. var _numberLiterals = require("./number-literals");
  9. var _stringLiterals = require("./string-literals");
  10. var _tokenizer = require("./tokenizer");
  11. function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
  12. function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
  13. function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
  14. function hasPlugin(name) {
  15. if (name !== "wast") throw new Error("unknow plugin");
  16. return true;
  17. }
  18. function isKeyword(token, id) {
  19. return token.type === _tokenizer.tokens.keyword && token.value === id;
  20. }
  21. function tokenToString(token) {
  22. if (token.type === "keyword") {
  23. return "keyword (".concat(token.value, ")");
  24. }
  25. return token.type;
  26. }
  27. function identifierFromToken(token) {
  28. var _token$loc = token.loc,
  29. end = _token$loc.end,
  30. start = _token$loc.start;
  31. return t.withLoc(t.identifier(token.value), end, start);
  32. }
  33. function parse(tokensList, source) {
  34. var current = 0;
  35. var getUniqueName = t.getUniqueNameGenerator();
  36. var state = {
  37. registredExportedElements: []
  38. }; // But this time we're going to use recursion instead of a `while` loop. So we
  39. // define a `walk` function.
  40. function walk() {
  41. var token = tokensList[current];
  42. function eatToken() {
  43. token = tokensList[++current];
  44. }
  45. function getEndLoc() {
  46. var currentToken = token;
  47. if (typeof currentToken === "undefined") {
  48. var lastToken = tokensList[tokensList.length - 1];
  49. currentToken = lastToken;
  50. }
  51. return currentToken.loc.end;
  52. }
  53. function getStartLoc() {
  54. return token.loc.start;
  55. }
  56. function eatTokenOfType(type) {
  57. if (token.type !== type) {
  58. throw new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "Assertion error: expected token of type " + type + ", given " + tokenToString(token));
  59. }
  60. eatToken();
  61. }
  62. function parseExportIndex(token) {
  63. if (token.type === _tokenizer.tokens.identifier) {
  64. var index = identifierFromToken(token);
  65. eatToken();
  66. return index;
  67. } else if (token.type === _tokenizer.tokens.number) {
  68. var _index = t.numberLiteralFromRaw(token.value);
  69. eatToken();
  70. return _index;
  71. } else {
  72. throw function () {
  73. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "unknown export index" + ", given " + tokenToString(token));
  74. }();
  75. }
  76. }
  77. function lookaheadAndCheck() {
  78. var len = arguments.length;
  79. for (var i = 0; i < len; i++) {
  80. var tokenAhead = tokensList[current + i];
  81. var expectedToken = i < 0 || arguments.length <= i ? undefined : arguments[i];
  82. if (tokenAhead.type === "keyword") {
  83. if (isKeyword(tokenAhead, expectedToken) === false) {
  84. return false;
  85. }
  86. } else if (expectedToken !== tokenAhead.type) {
  87. return false;
  88. }
  89. }
  90. return true;
  91. } // TODO(sven): there is probably a better way to do this
  92. // can refactor it if it get out of hands
  93. function maybeIgnoreComment() {
  94. if (typeof token === "undefined") {
  95. // Ignore
  96. return;
  97. }
  98. while (token.type === _tokenizer.tokens.comment) {
  99. eatToken();
  100. if (typeof token === "undefined") {
  101. // Hit the end
  102. break;
  103. }
  104. }
  105. }
  106. /**
  107. * Parses a memory instruction
  108. *
  109. * WAST:
  110. *
  111. * memory: ( memory <name>? <memory_sig> )
  112. * ( memory <name>? ( export <string> ) <...> )
  113. * ( memory <name>? ( import <string> <string> ) <memory_sig> )
  114. * ( memory <name>? ( export <string> )* ( data <string>* )
  115. * memory_sig: <nat> <nat>?
  116. *
  117. */
  118. function parseMemory() {
  119. var id = t.identifier(getUniqueName("memory"));
  120. var limits = t.limit(0);
  121. if (token.type === _tokenizer.tokens.string || token.type === _tokenizer.tokens.identifier) {
  122. id = t.identifier(token.value);
  123. eatToken();
  124. } else {
  125. id = t.withRaw(id, ""); // preserve anonymous
  126. }
  127. /**
  128. * Maybe data
  129. */
  130. if (lookaheadAndCheck(_tokenizer.tokens.openParen, _tokenizer.keywords.data)) {
  131. eatToken(); // (
  132. eatToken(); // data
  133. // TODO(sven): do something with the data collected here
  134. var stringInitializer = token.value;
  135. eatTokenOfType(_tokenizer.tokens.string); // Update limits accordingly
  136. limits = t.limit(stringInitializer.length);
  137. eatTokenOfType(_tokenizer.tokens.closeParen);
  138. }
  139. /**
  140. * Maybe export
  141. */
  142. if (lookaheadAndCheck(_tokenizer.tokens.openParen, _tokenizer.keywords.export)) {
  143. eatToken(); // (
  144. eatToken(); // export
  145. if (token.type !== _tokenizer.tokens.string) {
  146. throw function () {
  147. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Expected string in export" + ", given " + tokenToString(token));
  148. }();
  149. }
  150. var _name = token.value;
  151. eatToken();
  152. state.registredExportedElements.push({
  153. exportType: "Memory",
  154. name: _name,
  155. id: id
  156. });
  157. eatTokenOfType(_tokenizer.tokens.closeParen);
  158. }
  159. /**
  160. * Memory signature
  161. */
  162. if (token.type === _tokenizer.tokens.number) {
  163. limits = t.limit((0, _numberLiterals.parse32I)(token.value));
  164. eatToken();
  165. if (token.type === _tokenizer.tokens.number) {
  166. limits.max = (0, _numberLiterals.parse32I)(token.value);
  167. eatToken();
  168. }
  169. }
  170. return t.memory(limits, id);
  171. }
  172. /**
  173. * Parses a data section
  174. * https://webassembly.github.io/spec/core/text/modules.html#data-segments
  175. *
  176. * WAST:
  177. *
  178. * data: ( data <index>? <offset> <string> )
  179. */
  180. function parseData() {
  181. // optional memory index
  182. var memidx = 0;
  183. if (token.type === _tokenizer.tokens.number) {
  184. memidx = token.value;
  185. eatTokenOfType(_tokenizer.tokens.number); // .
  186. }
  187. eatTokenOfType(_tokenizer.tokens.openParen);
  188. var offset;
  189. if (token.type === _tokenizer.tokens.valtype) {
  190. eatTokenOfType(_tokenizer.tokens.valtype); // i32
  191. eatTokenOfType(_tokenizer.tokens.dot); // .
  192. if (token.value !== "const") {
  193. throw new Error("constant expression required");
  194. }
  195. eatTokenOfType(_tokenizer.tokens.name); // const
  196. var numberLiteral = t.numberLiteralFromRaw(token.value, "i32");
  197. offset = t.objectInstruction("const", "i32", [numberLiteral]);
  198. eatToken();
  199. eatTokenOfType(_tokenizer.tokens.closeParen);
  200. } else {
  201. eatTokenOfType(_tokenizer.tokens.name); // get_global
  202. var _numberLiteral = t.numberLiteralFromRaw(token.value, "i32");
  203. offset = t.instruction("get_global", [_numberLiteral]);
  204. eatToken();
  205. eatTokenOfType(_tokenizer.tokens.closeParen);
  206. }
  207. var byteArray = (0, _stringLiterals.parseString)(token.value);
  208. eatToken(); // "string"
  209. return t.data(t.memIndexLiteral(memidx), offset, t.byteArray(byteArray));
  210. }
  211. /**
  212. * Parses a table instruction
  213. *
  214. * WAST:
  215. *
  216. * table: ( table <name>? <table_type> )
  217. * ( table <name>? ( export <string> ) <...> )
  218. * ( table <name>? ( import <string> <string> ) <table_type> )
  219. * ( table <name>? ( export <string> )* <elem_type> ( elem <var>* ) )
  220. *
  221. * table_type: <nat> <nat>? <elem_type>
  222. * elem_type: anyfunc
  223. *
  224. * elem: ( elem <var>? (offset <instr>* ) <var>* )
  225. * ( elem <var>? <expr> <var>* )
  226. */
  227. function parseTable() {
  228. var name = t.identifier(getUniqueName("table"));
  229. var limit = t.limit(0);
  230. var elemIndices = [];
  231. var elemType = "anyfunc";
  232. if (token.type === _tokenizer.tokens.string || token.type === _tokenizer.tokens.identifier) {
  233. name = identifierFromToken(token);
  234. eatToken();
  235. } else {
  236. name = t.withRaw(name, ""); // preserve anonymous
  237. }
  238. while (token.type !== _tokenizer.tokens.closeParen) {
  239. /**
  240. * Maybe export
  241. */
  242. if (lookaheadAndCheck(_tokenizer.tokens.openParen, _tokenizer.keywords.elem)) {
  243. eatToken(); // (
  244. eatToken(); // elem
  245. while (token.type === _tokenizer.tokens.identifier) {
  246. elemIndices.push(t.identifier(token.value));
  247. eatToken();
  248. }
  249. eatTokenOfType(_tokenizer.tokens.closeParen);
  250. } else if (lookaheadAndCheck(_tokenizer.tokens.openParen, _tokenizer.keywords.export)) {
  251. eatToken(); // (
  252. eatToken(); // export
  253. if (token.type !== _tokenizer.tokens.string) {
  254. throw function () {
  255. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Expected string in export" + ", given " + tokenToString(token));
  256. }();
  257. }
  258. var exportName = token.value;
  259. eatToken();
  260. state.registredExportedElements.push({
  261. exportType: "Table",
  262. name: exportName,
  263. id: name
  264. });
  265. eatTokenOfType(_tokenizer.tokens.closeParen);
  266. } else if (isKeyword(token, _tokenizer.keywords.anyfunc)) {
  267. // It's the default value, we can ignore it
  268. eatToken(); // anyfunc
  269. } else if (token.type === _tokenizer.tokens.number) {
  270. /**
  271. * Table type
  272. */
  273. var min = parseInt(token.value);
  274. eatToken();
  275. if (token.type === _tokenizer.tokens.number) {
  276. var max = parseInt(token.value);
  277. eatToken();
  278. limit = t.limit(min, max);
  279. } else {
  280. limit = t.limit(min);
  281. }
  282. eatToken();
  283. } else {
  284. throw function () {
  285. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Unexpected token" + ", given " + tokenToString(token));
  286. }();
  287. }
  288. }
  289. if (elemIndices.length > 0) {
  290. return t.table(elemType, limit, name, elemIndices);
  291. } else {
  292. return t.table(elemType, limit, name);
  293. }
  294. }
  295. /**
  296. * Parses an import statement
  297. *
  298. * WAST:
  299. *
  300. * import: ( import <string> <string> <imkind> )
  301. * imkind: ( func <name>? <func_sig> )
  302. * ( global <name>? <global_sig> )
  303. * ( table <name>? <table_sig> )
  304. * ( memory <name>? <memory_sig> )
  305. *
  306. * global_sig: <type> | ( mut <type> )
  307. */
  308. function parseImport() {
  309. if (token.type !== _tokenizer.tokens.string) {
  310. throw new Error("Expected a string, " + token.type + " given.");
  311. }
  312. var moduleName = token.value;
  313. eatToken();
  314. if (token.type !== _tokenizer.tokens.string) {
  315. throw new Error("Expected a string, " + token.type + " given.");
  316. }
  317. var name = token.value;
  318. eatToken();
  319. eatTokenOfType(_tokenizer.tokens.openParen);
  320. var descr;
  321. if (isKeyword(token, _tokenizer.keywords.func)) {
  322. eatToken(); // keyword
  323. var fnParams = [];
  324. var fnResult = [];
  325. var typeRef;
  326. var fnName = t.identifier(getUniqueName("func"));
  327. if (token.type === _tokenizer.tokens.identifier) {
  328. fnName = identifierFromToken(token);
  329. eatToken();
  330. }
  331. while (token.type === _tokenizer.tokens.openParen) {
  332. eatToken();
  333. if (lookaheadAndCheck(_tokenizer.keywords.type) === true) {
  334. eatToken();
  335. typeRef = parseTypeReference();
  336. } else if (lookaheadAndCheck(_tokenizer.keywords.param) === true) {
  337. eatToken();
  338. fnParams.push.apply(fnParams, _toConsumableArray(parseFuncParam()));
  339. } else if (lookaheadAndCheck(_tokenizer.keywords.result) === true) {
  340. eatToken();
  341. fnResult.push.apply(fnResult, _toConsumableArray(parseFuncResult()));
  342. } else {
  343. throw function () {
  344. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Unexpected token in import of type" + ", given " + tokenToString(token));
  345. }();
  346. }
  347. eatTokenOfType(_tokenizer.tokens.closeParen);
  348. }
  349. if (typeof fnName === "undefined") {
  350. throw new Error("Imported function must have a name");
  351. }
  352. descr = t.funcImportDescr(fnName, typeRef !== undefined ? typeRef : t.signature(fnParams, fnResult));
  353. } else if (isKeyword(token, _tokenizer.keywords.global)) {
  354. eatToken(); // keyword
  355. if (token.type === _tokenizer.tokens.openParen) {
  356. eatToken(); // (
  357. eatTokenOfType(_tokenizer.tokens.keyword); // mut keyword
  358. var valtype = token.value;
  359. eatToken();
  360. descr = t.globalType(valtype, "var");
  361. eatTokenOfType(_tokenizer.tokens.closeParen);
  362. } else {
  363. var _valtype = token.value;
  364. eatTokenOfType(_tokenizer.tokens.valtype);
  365. descr = t.globalType(_valtype, "const");
  366. }
  367. } else if (isKeyword(token, _tokenizer.keywords.memory) === true) {
  368. eatToken(); // Keyword
  369. descr = parseMemory();
  370. } else if (isKeyword(token, _tokenizer.keywords.table) === true) {
  371. eatToken(); // Keyword
  372. descr = parseTable();
  373. } else {
  374. throw new Error("Unsupported import type: " + tokenToString(token));
  375. }
  376. eatTokenOfType(_tokenizer.tokens.closeParen);
  377. return t.moduleImport(moduleName, name, descr);
  378. }
  379. /**
  380. * Parses a block instruction
  381. *
  382. * WAST:
  383. *
  384. * expr: ( block <name>? <block_sig> <instr>* )
  385. * instr: block <name>? <block_sig> <instr>* end <name>?
  386. * block_sig : ( result <type>* )*
  387. *
  388. */
  389. function parseBlock() {
  390. var label = t.identifier(getUniqueName("block"));
  391. var blockResult = null;
  392. var instr = [];
  393. if (token.type === _tokenizer.tokens.identifier) {
  394. label = identifierFromToken(token);
  395. eatToken();
  396. } else {
  397. label = t.withRaw(label, ""); // preserve anonymous
  398. }
  399. while (token.type === _tokenizer.tokens.openParen) {
  400. eatToken();
  401. if (lookaheadAndCheck(_tokenizer.keywords.result) === true) {
  402. eatToken();
  403. blockResult = token.value;
  404. eatToken();
  405. } else if (lookaheadAndCheck(_tokenizer.tokens.name) === true || lookaheadAndCheck(_tokenizer.tokens.valtype) === true || token.type === "keyword" // is any keyword
  406. ) {
  407. // Instruction
  408. instr.push(parseFuncInstr());
  409. } else {
  410. throw function () {
  411. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Unexpected token in block body of type" + ", given " + tokenToString(token));
  412. }();
  413. }
  414. maybeIgnoreComment();
  415. eatTokenOfType(_tokenizer.tokens.closeParen);
  416. }
  417. return t.blockInstruction(label, instr, blockResult);
  418. }
  419. /**
  420. * Parses a if instruction
  421. *
  422. * WAST:
  423. *
  424. * expr:
  425. * ( if <name>? <block_sig> ( then <instr>* ) ( else <instr>* )? )
  426. * ( if <name>? <block_sig> <expr>+ ( then <instr>* ) ( else <instr>* )? )
  427. *
  428. * instr:
  429. * if <name>? <block_sig> <instr>* end <name>?
  430. * if <name>? <block_sig> <instr>* else <name>? <instr>* end <name>?
  431. *
  432. * block_sig : ( result <type>* )*
  433. *
  434. */
  435. function parseIf() {
  436. var blockResult = null;
  437. var label = t.identifier(getUniqueName("if"));
  438. var testInstrs = [];
  439. var consequent = [];
  440. var alternate = [];
  441. if (token.type === _tokenizer.tokens.identifier) {
  442. label = identifierFromToken(token);
  443. eatToken();
  444. } else {
  445. label = t.withRaw(label, ""); // preserve anonymous
  446. }
  447. while (token.type === _tokenizer.tokens.openParen) {
  448. eatToken(); // (
  449. /**
  450. * Block signature
  451. */
  452. if (isKeyword(token, _tokenizer.keywords.result) === true) {
  453. eatToken();
  454. blockResult = token.value;
  455. eatTokenOfType(_tokenizer.tokens.valtype);
  456. eatTokenOfType(_tokenizer.tokens.closeParen);
  457. continue;
  458. }
  459. /**
  460. * Then
  461. */
  462. if (isKeyword(token, _tokenizer.keywords.then) === true) {
  463. eatToken(); // then
  464. while (token.type === _tokenizer.tokens.openParen) {
  465. eatToken(); // Instruction
  466. if (lookaheadAndCheck(_tokenizer.tokens.name) === true || lookaheadAndCheck(_tokenizer.tokens.valtype) === true || token.type === "keyword" // is any keyword
  467. ) {
  468. consequent.push(parseFuncInstr());
  469. } else {
  470. throw function () {
  471. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Unexpected token in consequent body of type" + ", given " + tokenToString(token));
  472. }();
  473. }
  474. eatTokenOfType(_tokenizer.tokens.closeParen);
  475. }
  476. eatTokenOfType(_tokenizer.tokens.closeParen);
  477. continue;
  478. }
  479. /**
  480. * Alternate
  481. */
  482. if (isKeyword(token, _tokenizer.keywords.else)) {
  483. eatToken(); // else
  484. while (token.type === _tokenizer.tokens.openParen) {
  485. eatToken(); // Instruction
  486. if (lookaheadAndCheck(_tokenizer.tokens.name) === true || lookaheadAndCheck(_tokenizer.tokens.valtype) === true || token.type === "keyword" // is any keyword
  487. ) {
  488. alternate.push(parseFuncInstr());
  489. } else {
  490. throw function () {
  491. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Unexpected token in alternate body of type" + ", given " + tokenToString(token));
  492. }();
  493. }
  494. eatTokenOfType(_tokenizer.tokens.closeParen);
  495. }
  496. eatTokenOfType(_tokenizer.tokens.closeParen);
  497. continue;
  498. }
  499. /**
  500. * Test instruction
  501. */
  502. if (lookaheadAndCheck(_tokenizer.tokens.name) === true || lookaheadAndCheck(_tokenizer.tokens.valtype) === true || token.type === "keyword" // is any keyword
  503. ) {
  504. testInstrs.push(parseFuncInstr());
  505. eatTokenOfType(_tokenizer.tokens.closeParen);
  506. continue;
  507. }
  508. throw function () {
  509. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Unexpected token in if body" + ", given " + tokenToString(token));
  510. }();
  511. }
  512. return t.ifInstruction(label, testInstrs, blockResult, consequent, alternate);
  513. }
  514. /**
  515. * Parses a loop instruction
  516. *
  517. * WAT:
  518. *
  519. * blockinstr :: 'loop' I:label rt:resulttype (in:instr*) 'end' id?
  520. *
  521. * WAST:
  522. *
  523. * instr :: loop <name>? <block_sig> <instr>* end <name>?
  524. * expr :: ( loop <name>? <block_sig> <instr>* )
  525. * block_sig :: ( result <type>* )*
  526. *
  527. */
  528. function parseLoop() {
  529. var label = t.identifier(getUniqueName("loop"));
  530. var blockResult;
  531. var instr = [];
  532. if (token.type === _tokenizer.tokens.identifier) {
  533. label = identifierFromToken(token);
  534. eatToken();
  535. } else {
  536. label = t.withRaw(label, ""); // preserve anonymous
  537. }
  538. while (token.type === _tokenizer.tokens.openParen) {
  539. eatToken();
  540. if (lookaheadAndCheck(_tokenizer.keywords.result) === true) {
  541. eatToken();
  542. blockResult = token.value;
  543. eatToken();
  544. } else if (lookaheadAndCheck(_tokenizer.tokens.name) === true || lookaheadAndCheck(_tokenizer.tokens.valtype) === true || token.type === "keyword" // is any keyword
  545. ) {
  546. // Instruction
  547. instr.push(parseFuncInstr());
  548. } else {
  549. throw function () {
  550. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Unexpected token in loop body" + ", given " + tokenToString(token));
  551. }();
  552. }
  553. eatTokenOfType(_tokenizer.tokens.closeParen);
  554. }
  555. return t.loopInstruction(label, blockResult, instr);
  556. }
  557. function parseCallIndirect() {
  558. var typeRef;
  559. var params = [];
  560. var results = [];
  561. var instrs = [];
  562. while (token.type !== _tokenizer.tokens.closeParen) {
  563. if (lookaheadAndCheck(_tokenizer.tokens.openParen, _tokenizer.keywords.type)) {
  564. eatToken(); // (
  565. eatToken(); // type
  566. typeRef = parseTypeReference();
  567. } else if (lookaheadAndCheck(_tokenizer.tokens.openParen, _tokenizer.keywords.param)) {
  568. eatToken(); // (
  569. eatToken(); // param
  570. /**
  571. * Params can be empty:
  572. * (params)`
  573. */
  574. if (token.type !== _tokenizer.tokens.closeParen) {
  575. params.push.apply(params, _toConsumableArray(parseFuncParam()));
  576. }
  577. } else if (lookaheadAndCheck(_tokenizer.tokens.openParen, _tokenizer.keywords.result)) {
  578. eatToken(); // (
  579. eatToken(); // result
  580. /**
  581. * Results can be empty:
  582. * (result)`
  583. */
  584. if (token.type !== _tokenizer.tokens.closeParen) {
  585. results.push.apply(results, _toConsumableArray(parseFuncResult()));
  586. }
  587. } else {
  588. eatTokenOfType(_tokenizer.tokens.openParen);
  589. instrs.push(parseFuncInstr());
  590. }
  591. eatTokenOfType(_tokenizer.tokens.closeParen);
  592. }
  593. return t.callIndirectInstruction(typeRef !== undefined ? typeRef : t.signature(params, results), instrs);
  594. }
  595. /**
  596. * Parses an export instruction
  597. *
  598. * WAT:
  599. *
  600. * export: ( export <string> <exkind> )
  601. * exkind: ( func <var> )
  602. * ( global <var> )
  603. * ( table <var> )
  604. * ( memory <var> )
  605. * var: <nat> | <name>
  606. *
  607. */
  608. function parseExport() {
  609. if (token.type !== _tokenizer.tokens.string) {
  610. throw new Error("Expected string after export, got: " + token.type);
  611. }
  612. var name = token.value;
  613. eatToken();
  614. var moduleExportDescr = parseModuleExportDescr();
  615. return t.moduleExport(name, moduleExportDescr);
  616. }
  617. function parseModuleExportDescr() {
  618. var startLoc = getStartLoc();
  619. var type = "";
  620. var index;
  621. eatTokenOfType(_tokenizer.tokens.openParen);
  622. while (token.type !== _tokenizer.tokens.closeParen) {
  623. if (isKeyword(token, _tokenizer.keywords.func)) {
  624. type = "Func";
  625. eatToken();
  626. index = parseExportIndex(token);
  627. } else if (isKeyword(token, _tokenizer.keywords.table)) {
  628. type = "Table";
  629. eatToken();
  630. index = parseExportIndex(token);
  631. } else if (isKeyword(token, _tokenizer.keywords.global)) {
  632. type = "Global";
  633. eatToken();
  634. index = parseExportIndex(token);
  635. } else if (isKeyword(token, _tokenizer.keywords.memory)) {
  636. type = "Memory";
  637. eatToken();
  638. index = parseExportIndex(token);
  639. }
  640. eatToken();
  641. }
  642. if (type === "") {
  643. throw new Error("Unknown export type");
  644. }
  645. if (index === undefined) {
  646. throw new Error("Exported function must have a name");
  647. }
  648. var node = t.moduleExportDescr(type, index);
  649. var endLoc = getEndLoc();
  650. eatTokenOfType(_tokenizer.tokens.closeParen);
  651. return t.withLoc(node, endLoc, startLoc);
  652. }
  653. function parseModule() {
  654. var name = null;
  655. var isBinary = false;
  656. var isQuote = false;
  657. var moduleFields = [];
  658. if (token.type === _tokenizer.tokens.identifier) {
  659. name = token.value;
  660. eatToken();
  661. }
  662. if (hasPlugin("wast") && token.type === _tokenizer.tokens.name && token.value === "binary") {
  663. eatToken();
  664. isBinary = true;
  665. }
  666. if (hasPlugin("wast") && token.type === _tokenizer.tokens.name && token.value === "quote") {
  667. eatToken();
  668. isQuote = true;
  669. }
  670. if (isBinary === true) {
  671. var blob = [];
  672. while (token.type === _tokenizer.tokens.string) {
  673. blob.push(token.value);
  674. eatToken();
  675. maybeIgnoreComment();
  676. }
  677. eatTokenOfType(_tokenizer.tokens.closeParen);
  678. return t.binaryModule(name, blob);
  679. }
  680. if (isQuote === true) {
  681. var string = [];
  682. while (token.type === _tokenizer.tokens.string) {
  683. string.push(token.value);
  684. eatToken();
  685. }
  686. eatTokenOfType(_tokenizer.tokens.closeParen);
  687. return t.quoteModule(name, string);
  688. }
  689. while (token.type !== _tokenizer.tokens.closeParen) {
  690. moduleFields.push(walk());
  691. if (state.registredExportedElements.length > 0) {
  692. state.registredExportedElements.forEach(function (decl) {
  693. moduleFields.push(t.moduleExport(decl.name, t.moduleExportDescr(decl.exportType, decl.id)));
  694. });
  695. state.registredExportedElements = [];
  696. }
  697. token = tokensList[current];
  698. }
  699. eatTokenOfType(_tokenizer.tokens.closeParen);
  700. return t.module(name, moduleFields);
  701. }
  702. /**
  703. * Parses the arguments of an instruction
  704. */
  705. function parseFuncInstrArguments(signature) {
  706. var args = [];
  707. var namedArgs = {};
  708. var signaturePtr = 0;
  709. while (token.type === _tokenizer.tokens.name || isKeyword(token, _tokenizer.keywords.offset)) {
  710. var key = token.value;
  711. eatToken();
  712. eatTokenOfType(_tokenizer.tokens.equal);
  713. var value = void 0;
  714. if (token.type === _tokenizer.tokens.number) {
  715. value = t.numberLiteralFromRaw(token.value);
  716. } else {
  717. throw new Error("Unexpected type for argument: " + token.type);
  718. }
  719. namedArgs[key] = value;
  720. eatToken();
  721. } // $FlowIgnore
  722. var signatureLength = signature.vector ? Infinity : signature.length;
  723. while (token.type !== _tokenizer.tokens.closeParen && ( // $FlowIgnore
  724. token.type === _tokenizer.tokens.openParen || signaturePtr < signatureLength)) {
  725. if (token.type === _tokenizer.tokens.identifier) {
  726. args.push(t.identifier(token.value));
  727. eatToken();
  728. } else if (token.type === _tokenizer.tokens.valtype) {
  729. // Handle locals
  730. args.push(t.valtypeLiteral(token.value));
  731. eatToken();
  732. } else if (token.type === _tokenizer.tokens.string) {
  733. args.push(t.stringLiteral(token.value));
  734. eatToken();
  735. } else if (token.type === _tokenizer.tokens.number) {
  736. args.push( // TODO(sven): refactor the type signature handling
  737. // https://github.com/xtuc/webassemblyjs/pull/129 is a good start
  738. t.numberLiteralFromRaw(token.value, // $FlowIgnore
  739. signature[signaturePtr] || "f64")); // $FlowIgnore
  740. if (!signature.vector) {
  741. ++signaturePtr;
  742. }
  743. eatToken();
  744. } else if (token.type === _tokenizer.tokens.openParen) {
  745. /**
  746. * Maybe some nested instructions
  747. */
  748. eatToken(); // Instruction
  749. if (lookaheadAndCheck(_tokenizer.tokens.name) === true || lookaheadAndCheck(_tokenizer.tokens.valtype) === true || token.type === "keyword" // is any keyword
  750. ) {
  751. // $FlowIgnore
  752. args.push(parseFuncInstr());
  753. } else {
  754. throw function () {
  755. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Unexpected token in nested instruction" + ", given " + tokenToString(token));
  756. }();
  757. }
  758. if (token.type === _tokenizer.tokens.closeParen) {
  759. eatToken();
  760. }
  761. } else {
  762. throw function () {
  763. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Unexpected token in instruction argument" + ", given " + tokenToString(token));
  764. }();
  765. }
  766. }
  767. return {
  768. args: args,
  769. namedArgs: namedArgs
  770. };
  771. }
  772. /**
  773. * Parses an instruction
  774. *
  775. * WAT:
  776. *
  777. * instr :: plaininst
  778. * blockinstr
  779. *
  780. * blockinstr :: 'block' I:label rt:resulttype (in:instr*) 'end' id?
  781. * 'loop' I:label rt:resulttype (in:instr*) 'end' id?
  782. * 'if' I:label rt:resulttype (in:instr*) 'else' id? (in2:intr*) 'end' id?
  783. *
  784. * plaininst :: 'unreachable'
  785. * 'nop'
  786. * 'br' l:labelidx
  787. * 'br_if' l:labelidx
  788. * 'br_table' l*:vec(labelidx) ln:labelidx
  789. * 'return'
  790. * 'call' x:funcidx
  791. * 'call_indirect' x, I:typeuse
  792. *
  793. * WAST:
  794. *
  795. * instr:
  796. * <expr>
  797. * <op>
  798. * block <name>? <block_sig> <instr>* end <name>?
  799. * loop <name>? <block_sig> <instr>* end <name>?
  800. * if <name>? <block_sig> <instr>* end <name>?
  801. * if <name>? <block_sig> <instr>* else <name>? <instr>* end <name>?
  802. *
  803. * expr:
  804. * ( <op> )
  805. * ( <op> <expr>+ )
  806. * ( block <name>? <block_sig> <instr>* )
  807. * ( loop <name>? <block_sig> <instr>* )
  808. * ( if <name>? <block_sig> ( then <instr>* ) ( else <instr>* )? )
  809. * ( if <name>? <block_sig> <expr>+ ( then <instr>* ) ( else <instr>* )? )
  810. *
  811. * op:
  812. * unreachable
  813. * nop
  814. * br <var>
  815. * br_if <var>
  816. * br_table <var>+
  817. * return
  818. * call <var>
  819. * call_indirect <func_sig>
  820. * drop
  821. * select
  822. * get_local <var>
  823. * set_local <var>
  824. * tee_local <var>
  825. * get_global <var>
  826. * set_global <var>
  827. * <type>.load((8|16|32)_<sign>)? <offset>? <align>?
  828. * <type>.store(8|16|32)? <offset>? <align>?
  829. * current_memory
  830. * grow_memory
  831. * <type>.const <value>
  832. * <type>.<unop>
  833. * <type>.<binop>
  834. * <type>.<testop>
  835. * <type>.<relop>
  836. * <type>.<cvtop>/<type>
  837. *
  838. * func_type: ( type <var> )? <param>* <result>*
  839. */
  840. function parseFuncInstr() {
  841. var startLoc = getStartLoc();
  842. maybeIgnoreComment();
  843. /**
  844. * A simple instruction
  845. */
  846. if (token.type === _tokenizer.tokens.name || token.type === _tokenizer.tokens.valtype) {
  847. var _name2 = token.value;
  848. var object;
  849. eatToken();
  850. if (token.type === _tokenizer.tokens.dot) {
  851. object = _name2;
  852. eatToken();
  853. if (token.type !== _tokenizer.tokens.name) {
  854. throw new TypeError("Unknown token: " + token.type + ", name expected");
  855. }
  856. _name2 = token.value;
  857. eatToken();
  858. }
  859. if (token.type === _tokenizer.tokens.closeParen) {
  860. var _endLoc = token.loc.end;
  861. if (typeof object === "undefined") {
  862. return t.withLoc(t.instruction(_name2), _endLoc, startLoc);
  863. } else {
  864. return t.withLoc(t.objectInstruction(_name2, object, []), _endLoc, startLoc);
  865. }
  866. }
  867. var signature = t.signatureForOpcode(object || "", _name2);
  868. var _parseFuncInstrArgume = parseFuncInstrArguments(signature),
  869. _args = _parseFuncInstrArgume.args,
  870. _namedArgs = _parseFuncInstrArgume.namedArgs;
  871. var endLoc = token.loc.end;
  872. if (typeof object === "undefined") {
  873. return t.withLoc(t.instruction(_name2, _args, _namedArgs), endLoc, startLoc);
  874. } else {
  875. return t.withLoc(t.objectInstruction(_name2, object, _args, _namedArgs), endLoc, startLoc);
  876. }
  877. } else if (isKeyword(token, _tokenizer.keywords.loop)) {
  878. /**
  879. * Else a instruction with a keyword (loop or block)
  880. */
  881. eatToken(); // keyword
  882. return parseLoop();
  883. } else if (isKeyword(token, _tokenizer.keywords.block)) {
  884. eatToken(); // keyword
  885. return parseBlock();
  886. } else if (isKeyword(token, _tokenizer.keywords.call_indirect)) {
  887. eatToken(); // keyword
  888. return parseCallIndirect();
  889. } else if (isKeyword(token, _tokenizer.keywords.call)) {
  890. eatToken(); // keyword
  891. var index;
  892. if (token.type === _tokenizer.tokens.identifier) {
  893. index = identifierFromToken(token);
  894. eatToken();
  895. } else if (token.type === _tokenizer.tokens.number) {
  896. index = t.indexLiteral(token.value);
  897. eatToken();
  898. }
  899. var instrArgs = []; // Nested instruction
  900. while (token.type === _tokenizer.tokens.openParen) {
  901. eatToken();
  902. instrArgs.push(parseFuncInstr());
  903. eatTokenOfType(_tokenizer.tokens.closeParen);
  904. }
  905. if (typeof index === "undefined") {
  906. throw new Error("Missing argument in call instruciton");
  907. }
  908. if (instrArgs.length > 0) {
  909. return t.callInstruction(index, instrArgs);
  910. } else {
  911. return t.callInstruction(index);
  912. }
  913. } else if (isKeyword(token, _tokenizer.keywords.if)) {
  914. eatToken(); // Keyword
  915. return parseIf();
  916. } else if (isKeyword(token, _tokenizer.keywords.module) && hasPlugin("wast")) {
  917. eatToken(); // In WAST you can have a module as an instruction's argument
  918. // we will cast it into a instruction to not break the flow
  919. // $FlowIgnore
  920. var module = parseModule();
  921. return module;
  922. } else {
  923. throw function () {
  924. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Unexpected instruction in function body" + ", given " + tokenToString(token));
  925. }();
  926. }
  927. }
  928. /*
  929. * Parses a function
  930. *
  931. * WAT:
  932. *
  933. * functype :: ( 'func' t1:vec(param) t2:vec(result) )
  934. * param :: ( 'param' id? t:valtype )
  935. * result :: ( 'result' t:valtype )
  936. *
  937. * WAST:
  938. *
  939. * func :: ( func <name>? <func_sig> <local>* <instr>* )
  940. * ( func <name>? ( export <string> ) <...> )
  941. * ( func <name>? ( import <string> <string> ) <func_sig> )
  942. * func_sig :: ( type <var> )? <param>* <result>*
  943. * param :: ( param <type>* ) | ( param <name> <type> )
  944. * result :: ( result <type>* )
  945. * local :: ( local <type>* ) | ( local <name> <type> )
  946. *
  947. */
  948. function parseFunc() {
  949. var fnName = t.identifier(getUniqueName("func"));
  950. var typeRef;
  951. var fnBody = [];
  952. var fnParams = [];
  953. var fnResult = []; // name
  954. if (token.type === _tokenizer.tokens.identifier) {
  955. fnName = identifierFromToken(token);
  956. eatToken();
  957. } else {
  958. fnName = t.withRaw(fnName, ""); // preserve anonymous
  959. }
  960. maybeIgnoreComment();
  961. while (token.type === _tokenizer.tokens.openParen || token.type === _tokenizer.tokens.name || token.type === _tokenizer.tokens.valtype) {
  962. // Instructions without parens
  963. if (token.type === _tokenizer.tokens.name || token.type === _tokenizer.tokens.valtype) {
  964. fnBody.push(parseFuncInstr());
  965. continue;
  966. }
  967. eatToken();
  968. if (lookaheadAndCheck(_tokenizer.keywords.param) === true) {
  969. eatToken();
  970. fnParams.push.apply(fnParams, _toConsumableArray(parseFuncParam()));
  971. } else if (lookaheadAndCheck(_tokenizer.keywords.result) === true) {
  972. eatToken();
  973. fnResult.push.apply(fnResult, _toConsumableArray(parseFuncResult()));
  974. } else if (lookaheadAndCheck(_tokenizer.keywords.export) === true) {
  975. eatToken();
  976. parseFuncExport(fnName);
  977. } else if (lookaheadAndCheck(_tokenizer.keywords.type) === true) {
  978. eatToken();
  979. typeRef = parseTypeReference();
  980. } else if (lookaheadAndCheck(_tokenizer.tokens.name) === true || lookaheadAndCheck(_tokenizer.tokens.valtype) === true || token.type === "keyword" // is any keyword
  981. ) {
  982. // Instruction
  983. fnBody.push(parseFuncInstr());
  984. } else {
  985. throw function () {
  986. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Unexpected token in func body" + ", given " + tokenToString(token));
  987. }();
  988. }
  989. eatTokenOfType(_tokenizer.tokens.closeParen);
  990. }
  991. return t.func(fnName, typeRef !== undefined ? typeRef : t.signature(fnParams, fnResult), fnBody);
  992. }
  993. /**
  994. * Parses shorthand export in func
  995. *
  996. * export :: ( export <string> )
  997. */
  998. function parseFuncExport(funcId) {
  999. if (token.type !== _tokenizer.tokens.string) {
  1000. throw function () {
  1001. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Function export expected a string" + ", given " + tokenToString(token));
  1002. }();
  1003. }
  1004. var name = token.value;
  1005. eatToken();
  1006. /**
  1007. * Func export shorthand, we trait it as a syntaxic sugar.
  1008. * A export ModuleField will be added later.
  1009. *
  1010. * We give the anonymous function a generated name and export it.
  1011. */
  1012. var id = t.identifier(funcId.value);
  1013. state.registredExportedElements.push({
  1014. exportType: "Func",
  1015. name: name,
  1016. id: id
  1017. });
  1018. }
  1019. /**
  1020. * Parses a type instruction
  1021. *
  1022. * WAST:
  1023. *
  1024. * typedef: ( type <name>? ( func <param>* <result>* ) )
  1025. */
  1026. function parseType() {
  1027. var id;
  1028. var params = [];
  1029. var result = [];
  1030. if (token.type === _tokenizer.tokens.identifier) {
  1031. id = identifierFromToken(token);
  1032. eatToken();
  1033. }
  1034. if (lookaheadAndCheck(_tokenizer.tokens.openParen, _tokenizer.keywords.func)) {
  1035. eatToken(); // (
  1036. eatToken(); // func
  1037. if (token.type === _tokenizer.tokens.closeParen) {
  1038. eatToken(); // function with an empty signature, we can abort here
  1039. return t.typeInstruction(id, t.signature([], []));
  1040. }
  1041. if (lookaheadAndCheck(_tokenizer.tokens.openParen, _tokenizer.keywords.param)) {
  1042. eatToken(); // (
  1043. eatToken(); // param
  1044. params = parseFuncParam();
  1045. eatTokenOfType(_tokenizer.tokens.closeParen);
  1046. }
  1047. if (lookaheadAndCheck(_tokenizer.tokens.openParen, _tokenizer.keywords.result)) {
  1048. eatToken(); // (
  1049. eatToken(); // result
  1050. result = parseFuncResult();
  1051. eatTokenOfType(_tokenizer.tokens.closeParen);
  1052. }
  1053. eatTokenOfType(_tokenizer.tokens.closeParen);
  1054. }
  1055. return t.typeInstruction(id, t.signature(params, result));
  1056. }
  1057. /**
  1058. * Parses a function result
  1059. *
  1060. * WAST:
  1061. *
  1062. * result :: ( result <type>* )
  1063. */
  1064. function parseFuncResult() {
  1065. var results = [];
  1066. while (token.type !== _tokenizer.tokens.closeParen) {
  1067. if (token.type !== _tokenizer.tokens.valtype) {
  1068. throw function () {
  1069. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Unexpected token in func result" + ", given " + tokenToString(token));
  1070. }();
  1071. }
  1072. var valtype = token.value;
  1073. eatToken();
  1074. results.push(valtype);
  1075. }
  1076. return results;
  1077. }
  1078. /**
  1079. * Parses a type reference
  1080. *
  1081. */
  1082. function parseTypeReference() {
  1083. var ref;
  1084. if (token.type === _tokenizer.tokens.identifier) {
  1085. ref = identifierFromToken(token);
  1086. eatToken();
  1087. } else if (token.type === _tokenizer.tokens.number) {
  1088. ref = t.numberLiteralFromRaw(token.value);
  1089. eatToken();
  1090. }
  1091. return ref;
  1092. }
  1093. /**
  1094. * Parses a global instruction
  1095. *
  1096. * WAST:
  1097. *
  1098. * global: ( global <name>? <global_sig> <instr>* )
  1099. * ( global <name>? ( export <string> ) <...> )
  1100. * ( global <name>? ( import <string> <string> ) <global_sig> )
  1101. *
  1102. * global_sig: <type> | ( mut <type> )
  1103. *
  1104. */
  1105. function parseGlobal() {
  1106. var name = t.identifier(getUniqueName("global"));
  1107. var type; // Keep informations in case of a shorthand import
  1108. var importing = null;
  1109. maybeIgnoreComment();
  1110. if (token.type === _tokenizer.tokens.identifier) {
  1111. name = identifierFromToken(token);
  1112. eatToken();
  1113. } else {
  1114. name = t.withRaw(name, ""); // preserve anonymous
  1115. }
  1116. /**
  1117. * maybe export
  1118. */
  1119. if (lookaheadAndCheck(_tokenizer.tokens.openParen, _tokenizer.keywords.export)) {
  1120. eatToken(); // (
  1121. eatToken(); // export
  1122. var exportName = token.value;
  1123. eatTokenOfType(_tokenizer.tokens.string);
  1124. state.registredExportedElements.push({
  1125. exportType: "Global",
  1126. name: exportName,
  1127. id: name
  1128. });
  1129. eatTokenOfType(_tokenizer.tokens.closeParen);
  1130. }
  1131. /**
  1132. * maybe import
  1133. */
  1134. if (lookaheadAndCheck(_tokenizer.tokens.openParen, _tokenizer.keywords.import)) {
  1135. eatToken(); // (
  1136. eatToken(); // import
  1137. var moduleName = token.value;
  1138. eatTokenOfType(_tokenizer.tokens.string);
  1139. var _name3 = token.value;
  1140. eatTokenOfType(_tokenizer.tokens.string);
  1141. importing = {
  1142. module: moduleName,
  1143. name: _name3,
  1144. descr: undefined
  1145. };
  1146. eatTokenOfType(_tokenizer.tokens.closeParen);
  1147. }
  1148. /**
  1149. * global_sig
  1150. */
  1151. if (token.type === _tokenizer.tokens.valtype) {
  1152. type = t.globalType(token.value, "const");
  1153. eatToken();
  1154. } else if (token.type === _tokenizer.tokens.openParen) {
  1155. eatToken(); // (
  1156. if (isKeyword(token, _tokenizer.keywords.mut) === false) {
  1157. throw function () {
  1158. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Unsupported global type, expected mut" + ", given " + tokenToString(token));
  1159. }();
  1160. }
  1161. eatToken(); // mut
  1162. type = t.globalType(token.value, "var");
  1163. eatToken();
  1164. eatTokenOfType(_tokenizer.tokens.closeParen);
  1165. }
  1166. if (type === undefined) {
  1167. throw function () {
  1168. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Could not determine global type" + ", given " + tokenToString(token));
  1169. }();
  1170. }
  1171. maybeIgnoreComment();
  1172. var init = [];
  1173. if (importing != null) {
  1174. importing.descr = type;
  1175. init.push(t.moduleImport(importing.module, importing.name, importing.descr));
  1176. }
  1177. /**
  1178. * instr*
  1179. */
  1180. while (token.type === _tokenizer.tokens.openParen) {
  1181. eatToken();
  1182. init.push(parseFuncInstr());
  1183. eatTokenOfType(_tokenizer.tokens.closeParen);
  1184. }
  1185. return t.global(type, init, name);
  1186. }
  1187. /**
  1188. * Parses a function param
  1189. *
  1190. * WAST:
  1191. *
  1192. * param :: ( param <type>* ) | ( param <name> <type> )
  1193. */
  1194. function parseFuncParam() {
  1195. var params = [];
  1196. var id;
  1197. var valtype;
  1198. if (token.type === _tokenizer.tokens.identifier) {
  1199. id = token.value;
  1200. eatToken();
  1201. }
  1202. if (token.type === _tokenizer.tokens.valtype) {
  1203. valtype = token.value;
  1204. eatToken();
  1205. params.push({
  1206. id: id,
  1207. valtype: valtype
  1208. });
  1209. /**
  1210. * Shorthand notation for multiple anonymous parameters
  1211. * @see https://webassembly.github.io/spec/core/text/types.html#function-types
  1212. * @see https://github.com/xtuc/webassemblyjs/issues/6
  1213. */
  1214. if (id === undefined) {
  1215. while (token.type === _tokenizer.tokens.valtype) {
  1216. valtype = token.value;
  1217. eatToken();
  1218. params.push({
  1219. id: undefined,
  1220. valtype: valtype
  1221. });
  1222. }
  1223. }
  1224. } else {// ignore
  1225. }
  1226. return params;
  1227. }
  1228. /**
  1229. * Parses an element segments instruction
  1230. *
  1231. * WAST:
  1232. *
  1233. * elem: ( elem <var>? (offset <instr>* ) <var>* )
  1234. * ( elem <var>? <expr> <var>* )
  1235. *
  1236. * var: <nat> | <name>
  1237. */
  1238. function parseElem() {
  1239. var tableIndex = t.indexLiteral(0);
  1240. var offset = [];
  1241. var funcs = [];
  1242. if (token.type === _tokenizer.tokens.identifier) {
  1243. tableIndex = identifierFromToken(token);
  1244. eatToken();
  1245. }
  1246. if (token.type === _tokenizer.tokens.number) {
  1247. tableIndex = t.indexLiteral(token.value);
  1248. eatToken();
  1249. }
  1250. while (token.type !== _tokenizer.tokens.closeParen) {
  1251. if (lookaheadAndCheck(_tokenizer.tokens.openParen, _tokenizer.keywords.offset)) {
  1252. eatToken(); // (
  1253. eatToken(); // offset
  1254. while (token.type !== _tokenizer.tokens.closeParen) {
  1255. eatTokenOfType(_tokenizer.tokens.openParen);
  1256. offset.push(parseFuncInstr());
  1257. eatTokenOfType(_tokenizer.tokens.closeParen);
  1258. }
  1259. eatTokenOfType(_tokenizer.tokens.closeParen);
  1260. } else if (token.type === _tokenizer.tokens.identifier) {
  1261. funcs.push(t.identifier(token.value));
  1262. eatToken();
  1263. } else if (token.type === _tokenizer.tokens.number) {
  1264. funcs.push(t.indexLiteral(token.value));
  1265. eatToken();
  1266. } else if (token.type === _tokenizer.tokens.openParen) {
  1267. eatToken(); // (
  1268. offset.push(parseFuncInstr());
  1269. eatTokenOfType(_tokenizer.tokens.closeParen);
  1270. } else {
  1271. throw function () {
  1272. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Unsupported token in elem" + ", given " + tokenToString(token));
  1273. }();
  1274. }
  1275. }
  1276. return t.elem(tableIndex, offset, funcs);
  1277. }
  1278. /**
  1279. * Parses the start instruction in a module
  1280. *
  1281. * WAST:
  1282. *
  1283. * start: ( start <var> )
  1284. * var: <nat> | <name>
  1285. *
  1286. * WAT:
  1287. * start ::= ‘(’ ‘start’ x:funcidx ‘)’
  1288. */
  1289. function parseStart() {
  1290. if (token.type === _tokenizer.tokens.identifier) {
  1291. var index = identifierFromToken(token);
  1292. eatToken();
  1293. return t.start(index);
  1294. }
  1295. if (token.type === _tokenizer.tokens.number) {
  1296. var _index2 = t.indexLiteral(token.value);
  1297. eatToken();
  1298. return t.start(_index2);
  1299. }
  1300. throw new Error("Unknown start, token: " + tokenToString(token));
  1301. }
  1302. if (token.type === _tokenizer.tokens.openParen) {
  1303. eatToken();
  1304. var startLoc = getStartLoc();
  1305. if (isKeyword(token, _tokenizer.keywords.export)) {
  1306. eatToken();
  1307. var node = parseExport();
  1308. var _endLoc2 = getEndLoc();
  1309. return t.withLoc(node, _endLoc2, startLoc);
  1310. }
  1311. if (isKeyword(token, _tokenizer.keywords.loop)) {
  1312. eatToken();
  1313. var _node = parseLoop();
  1314. var _endLoc3 = getEndLoc();
  1315. return t.withLoc(_node, _endLoc3, startLoc);
  1316. }
  1317. if (isKeyword(token, _tokenizer.keywords.func)) {
  1318. eatToken();
  1319. var _node2 = parseFunc();
  1320. var _endLoc4 = getEndLoc();
  1321. maybeIgnoreComment();
  1322. eatTokenOfType(_tokenizer.tokens.closeParen);
  1323. return t.withLoc(_node2, _endLoc4, startLoc);
  1324. }
  1325. if (isKeyword(token, _tokenizer.keywords.module)) {
  1326. eatToken();
  1327. var _node3 = parseModule();
  1328. var _endLoc5 = getEndLoc();
  1329. return t.withLoc(_node3, _endLoc5, startLoc);
  1330. }
  1331. if (isKeyword(token, _tokenizer.keywords.import)) {
  1332. eatToken();
  1333. var _node4 = parseImport();
  1334. var _endLoc6 = getEndLoc();
  1335. eatTokenOfType(_tokenizer.tokens.closeParen);
  1336. return t.withLoc(_node4, _endLoc6, startLoc);
  1337. }
  1338. if (isKeyword(token, _tokenizer.keywords.block)) {
  1339. eatToken();
  1340. var _node5 = parseBlock();
  1341. var _endLoc7 = getEndLoc();
  1342. eatTokenOfType(_tokenizer.tokens.closeParen);
  1343. return t.withLoc(_node5, _endLoc7, startLoc);
  1344. }
  1345. if (isKeyword(token, _tokenizer.keywords.memory)) {
  1346. eatToken();
  1347. var _node6 = parseMemory();
  1348. var _endLoc8 = getEndLoc();
  1349. eatTokenOfType(_tokenizer.tokens.closeParen);
  1350. return t.withLoc(_node6, _endLoc8, startLoc);
  1351. }
  1352. if (isKeyword(token, _tokenizer.keywords.data)) {
  1353. eatToken();
  1354. var _node7 = parseData();
  1355. var _endLoc9 = getEndLoc();
  1356. eatTokenOfType(_tokenizer.tokens.closeParen);
  1357. return t.withLoc(_node7, _endLoc9, startLoc);
  1358. }
  1359. if (isKeyword(token, _tokenizer.keywords.table)) {
  1360. eatToken();
  1361. var _node8 = parseTable();
  1362. var _endLoc10 = getEndLoc();
  1363. eatTokenOfType(_tokenizer.tokens.closeParen);
  1364. return t.withLoc(_node8, _endLoc10, startLoc);
  1365. }
  1366. if (isKeyword(token, _tokenizer.keywords.global)) {
  1367. eatToken();
  1368. var _node9 = parseGlobal();
  1369. var _endLoc11 = getEndLoc();
  1370. eatTokenOfType(_tokenizer.tokens.closeParen);
  1371. return t.withLoc(_node9, _endLoc11, startLoc);
  1372. }
  1373. if (isKeyword(token, _tokenizer.keywords.type)) {
  1374. eatToken();
  1375. var _node10 = parseType();
  1376. var _endLoc12 = getEndLoc();
  1377. eatTokenOfType(_tokenizer.tokens.closeParen);
  1378. return t.withLoc(_node10, _endLoc12, startLoc);
  1379. }
  1380. if (isKeyword(token, _tokenizer.keywords.start)) {
  1381. eatToken();
  1382. var _node11 = parseStart();
  1383. var _endLoc13 = getEndLoc();
  1384. eatTokenOfType(_tokenizer.tokens.closeParen);
  1385. return t.withLoc(_node11, _endLoc13, startLoc);
  1386. }
  1387. if (isKeyword(token, _tokenizer.keywords.elem)) {
  1388. eatToken();
  1389. var _node12 = parseElem();
  1390. var _endLoc14 = getEndLoc();
  1391. eatTokenOfType(_tokenizer.tokens.closeParen);
  1392. return t.withLoc(_node12, _endLoc14, startLoc);
  1393. }
  1394. var instruction = parseFuncInstr();
  1395. var endLoc = getEndLoc();
  1396. maybeIgnoreComment();
  1397. if (_typeof(instruction) === "object") {
  1398. if (typeof token !== "undefined") {
  1399. eatTokenOfType(_tokenizer.tokens.closeParen);
  1400. }
  1401. return t.withLoc(instruction, endLoc, startLoc);
  1402. }
  1403. }
  1404. if (token.type === _tokenizer.tokens.comment) {
  1405. var _startLoc = getStartLoc();
  1406. var builder = token.opts.type === "leading" ? t.leadingComment : t.blockComment;
  1407. var _node13 = builder(token.value);
  1408. eatToken(); // comment
  1409. var _endLoc15 = getEndLoc();
  1410. return t.withLoc(_node13, _endLoc15, _startLoc);
  1411. }
  1412. throw function () {
  1413. return new Error("\n" + (0, _helperCodeFrame.codeFrameFromSource)(source, token.loc) + "\n" + "Unknown token" + ", given " + tokenToString(token));
  1414. }();
  1415. }
  1416. var body = [];
  1417. while (current < tokensList.length) {
  1418. body.push(walk());
  1419. }
  1420. return t.program(body);
  1421. }