grammar.js 48 KB

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