Projekt

Obecné

Profil

Stáhnout (47.8 KB) Statistiky
| Větev: | Revize:
1
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); }
2

    
3
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); } }
4

    
5
import { codeFrameFromSource } from "@webassemblyjs/helper-code-frame";
6
import * as t from "@webassemblyjs/ast";
7
import { parse32I } from "./number-literals";
8
import { parseString } from "./string-literals";
9
import { tokens, keywords } from "./tokenizer";
10

    
11
function hasPlugin(name) {
12
  if (name !== "wast") throw new Error("unknow plugin");
13
  return true;
14
}
15

    
16
function isKeyword(token, id) {
17
  return token.type === tokens.keyword && token.value === id;
18
}
19

    
20
function tokenToString(token) {
21
  if (token.type === "keyword") {
22
    return "keyword (".concat(token.value, ")");
23
  }
24

    
25
  return token.type;
26
}
27

    
28
function identifierFromToken(token) {
29
  var _token$loc = token.loc,
30
      end = _token$loc.end,
31
      start = _token$loc.start;
32
  return t.withLoc(t.identifier(token.value), end, start);
33
}
34

    
35
export 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

    
43
  function walk() {
44
    var token = tokensList[current];
45

    
46
    function eatToken() {
47
      token = tokensList[++current];
48
    }
49

    
50
    function getEndLoc() {
51
      var currentToken = token;
52

    
53
      if (typeof currentToken === "undefined") {
54
        var lastToken = tokensList[tokensList.length - 1];
55
        currentToken = lastToken;
56
      }
57

    
58
      return currentToken.loc.end;
59
    }
60

    
61
    function getStartLoc() {
62
      return token.loc.start;
63
    }
64

    
65
    function eatTokenOfType(type) {
66
      if (token.type !== type) {
67
        throw new Error("\n" + codeFrameFromSource(source, token.loc) + "Assertion error: expected token of type " + type + ", given " + tokenToString(token));
68
      }
69

    
70
      eatToken();
71
    }
72

    
73
    function parseExportIndex(token) {
74
      if (token.type === tokens.identifier) {
75
        var index = identifierFromToken(token);
76
        eatToken();
77
        return index;
78
      } else if (token.type === tokens.number) {
79
        var _index = t.numberLiteralFromRaw(token.value);
80

    
81
        eatToken();
82
        return _index;
83
      } else {
84
        throw function () {
85
          return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "unknown export index" + ", given " + tokenToString(token));
86
        }();
87
      }
88
    }
89

    
90
    function lookaheadAndCheck() {
91
      var len = arguments.length;
92

    
93
      for (var i = 0; i < len; i++) {
94
        var tokenAhead = tokensList[current + i];
95
        var expectedToken = i < 0 || arguments.length <= i ? undefined : arguments[i];
96

    
97
        if (tokenAhead.type === "keyword") {
98
          if (isKeyword(tokenAhead, expectedToken) === false) {
99
            return false;
100
          }
101
        } else if (expectedToken !== tokenAhead.type) {
102
          return false;
103
        }
104
      }
105

    
106
      return true;
107
    } // TODO(sven): there is probably a better way to do this
108
    // can refactor it if it get out of hands
109

    
110

    
111
    function maybeIgnoreComment() {
112
      if (typeof token === "undefined") {
113
        // Ignore
114
        return;
115
      }
116

    
117
      while (token.type === tokens.comment) {
118
        eatToken();
119

    
120
        if (typeof token === "undefined") {
121
          // Hit the end
122
          break;
123
        }
124
      }
125
    }
126
    /**
127
     * Parses a memory instruction
128
     *
129
     * WAST:
130
     *
131
     * memory:  ( memory <name>? <memory_sig> )
132
     *          ( memory <name>? ( export <string> ) <...> )
133
     *          ( memory <name>? ( import <string> <string> ) <memory_sig> )
134
     *          ( memory <name>? ( export <string> )* ( data <string>* )
135
     * memory_sig: <nat> <nat>?
136
     *
137
     */
138

    
139

    
140
    function parseMemory() {
141
      var id = t.identifier(getUniqueName("memory"));
142
      var limits = t.limit(0);
143

    
144
      if (token.type === tokens.string || token.type === tokens.identifier) {
145
        id = t.identifier(token.value);
146
        eatToken();
147
      } else {
148
        id = t.withRaw(id, ""); // preserve anonymous
149
      }
150
      /**
151
       * Maybe data
152
       */
153

    
154

    
155
      if (lookaheadAndCheck(tokens.openParen, keywords.data)) {
156
        eatToken(); // (
157

    
158
        eatToken(); // data
159
        // TODO(sven): do something with the data collected here
160

    
161
        var stringInitializer = token.value;
162
        eatTokenOfType(tokens.string); // Update limits accordingly
163

    
164
        limits = t.limit(stringInitializer.length);
165
        eatTokenOfType(tokens.closeParen);
166
      }
167
      /**
168
       * Maybe export
169
       */
170

    
171

    
172
      if (lookaheadAndCheck(tokens.openParen, keywords.export)) {
173
        eatToken(); // (
174

    
175
        eatToken(); // export
176

    
177
        if (token.type !== tokens.string) {
178
          throw function () {
179
            return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Expected string in export" + ", given " + tokenToString(token));
180
          }();
181
        }
182

    
183
        var _name = token.value;
184
        eatToken();
185
        state.registredExportedElements.push({
186
          exportType: "Memory",
187
          name: _name,
188
          id: id
189
        });
190
        eatTokenOfType(tokens.closeParen);
191
      }
192
      /**
193
       * Memory signature
194
       */
195

    
196

    
197
      if (token.type === tokens.number) {
198
        limits = t.limit(parse32I(token.value));
199
        eatToken();
200

    
201
        if (token.type === tokens.number) {
202
          limits.max = parse32I(token.value);
203
          eatToken();
204
        }
205
      }
206

    
207
      return t.memory(limits, id);
208
    }
209
    /**
210
     * Parses a data section
211
     * https://webassembly.github.io/spec/core/text/modules.html#data-segments
212
     *
213
     * WAST:
214
     *
215
     * data:  ( data <index>? <offset> <string> )
216
     */
217

    
218

    
219
    function parseData() {
220
      // optional memory index
221
      var memidx = 0;
222

    
223
      if (token.type === tokens.number) {
224
        memidx = token.value;
225
        eatTokenOfType(tokens.number); // .
226
      }
227

    
228
      eatTokenOfType(tokens.openParen);
229
      var offset;
230

    
231
      if (token.type === tokens.valtype) {
232
        eatTokenOfType(tokens.valtype); // i32
233

    
234
        eatTokenOfType(tokens.dot); // .
235

    
236
        if (token.value !== "const") {
237
          throw new Error("constant expression required");
238
        }
239

    
240
        eatTokenOfType(tokens.name); // const
241

    
242
        var numberLiteral = t.numberLiteralFromRaw(token.value, "i32");
243
        offset = t.objectInstruction("const", "i32", [numberLiteral]);
244
        eatToken();
245
        eatTokenOfType(tokens.closeParen);
246
      } else {
247
        eatTokenOfType(tokens.name); // get_global
248

    
249
        var _numberLiteral = t.numberLiteralFromRaw(token.value, "i32");
250

    
251
        offset = t.instruction("get_global", [_numberLiteral]);
252
        eatToken();
253
        eatTokenOfType(tokens.closeParen);
254
      }
255

    
256
      var byteArray = parseString(token.value);
257
      eatToken(); // "string"
258

    
259
      return t.data(t.memIndexLiteral(memidx), offset, t.byteArray(byteArray));
260
    }
261
    /**
262
     * Parses a table instruction
263
     *
264
     * WAST:
265
     *
266
     * table:   ( table <name>? <table_type> )
267
     *          ( table <name>? ( export <string> ) <...> )
268
     *          ( table <name>? ( import <string> <string> ) <table_type> )
269
     *          ( table <name>? ( export <string> )* <elem_type> ( elem <var>* ) )
270
     *
271
     * table_type:  <nat> <nat>? <elem_type>
272
     * elem_type: anyfunc
273
     *
274
     * elem:    ( elem <var>? (offset <instr>* ) <var>* )
275
     *          ( elem <var>? <expr> <var>* )
276
     */
277

    
278

    
279
    function parseTable() {
280
      var name = t.identifier(getUniqueName("table"));
281
      var limit = t.limit(0);
282
      var elemIndices = [];
283
      var elemType = "anyfunc";
284

    
285
      if (token.type === tokens.string || token.type === tokens.identifier) {
286
        name = identifierFromToken(token);
287
        eatToken();
288
      } else {
289
        name = t.withRaw(name, ""); // preserve anonymous
290
      }
291

    
292
      while (token.type !== tokens.closeParen) {
293
        /**
294
         * Maybe export
295
         */
296
        if (lookaheadAndCheck(tokens.openParen, keywords.elem)) {
297
          eatToken(); // (
298

    
299
          eatToken(); // elem
300

    
301
          while (token.type === tokens.identifier) {
302
            elemIndices.push(t.identifier(token.value));
303
            eatToken();
304
          }
305

    
306
          eatTokenOfType(tokens.closeParen);
307
        } else if (lookaheadAndCheck(tokens.openParen, keywords.export)) {
308
          eatToken(); // (
309

    
310
          eatToken(); // export
311

    
312
          if (token.type !== tokens.string) {
313
            throw function () {
314
              return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Expected string in export" + ", given " + tokenToString(token));
315
            }();
316
          }
317

    
318
          var exportName = token.value;
319
          eatToken();
320
          state.registredExportedElements.push({
321
            exportType: "Table",
322
            name: exportName,
323
            id: name
324
          });
325
          eatTokenOfType(tokens.closeParen);
326
        } else if (isKeyword(token, keywords.anyfunc)) {
327
          // It's the default value, we can ignore it
328
          eatToken(); // anyfunc
329
        } else if (token.type === tokens.number) {
330
          /**
331
           * Table type
332
           */
333
          var min = parseInt(token.value);
334
          eatToken();
335

    
336
          if (token.type === tokens.number) {
337
            var max = parseInt(token.value);
338
            eatToken();
339
            limit = t.limit(min, max);
340
          } else {
341
            limit = t.limit(min);
342
          }
343

    
344
          eatToken();
345
        } else {
346
          throw function () {
347
            return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unexpected token" + ", given " + tokenToString(token));
348
          }();
349
        }
350
      }
351

    
352
      if (elemIndices.length > 0) {
353
        return t.table(elemType, limit, name, elemIndices);
354
      } else {
355
        return t.table(elemType, limit, name);
356
      }
357
    }
358
    /**
359
     * Parses an import statement
360
     *
361
     * WAST:
362
     *
363
     * import:  ( import <string> <string> <imkind> )
364
     * imkind:  ( func <name>? <func_sig> )
365
     *          ( global <name>? <global_sig> )
366
     *          ( table <name>? <table_sig> )
367
     *          ( memory <name>? <memory_sig> )
368
     *
369
     * global_sig: <type> | ( mut <type> )
370
     */
371

    
372

    
373
    function parseImport() {
374
      if (token.type !== tokens.string) {
375
        throw new Error("Expected a string, " + token.type + " given.");
376
      }
377

    
378
      var moduleName = token.value;
379
      eatToken();
380

    
381
      if (token.type !== tokens.string) {
382
        throw new Error("Expected a string, " + token.type + " given.");
383
      }
384

    
385
      var name = token.value;
386
      eatToken();
387
      eatTokenOfType(tokens.openParen);
388
      var descr;
389

    
390
      if (isKeyword(token, keywords.func)) {
391
        eatToken(); // keyword
392

    
393
        var fnParams = [];
394
        var fnResult = [];
395
        var typeRef;
396
        var fnName = t.identifier(getUniqueName("func"));
397

    
398
        if (token.type === tokens.identifier) {
399
          fnName = identifierFromToken(token);
400
          eatToken();
401
        }
402

    
403
        while (token.type === tokens.openParen) {
404
          eatToken();
405

    
406
          if (lookaheadAndCheck(keywords.type) === true) {
407
            eatToken();
408
            typeRef = parseTypeReference();
409
          } else if (lookaheadAndCheck(keywords.param) === true) {
410
            eatToken();
411
            fnParams.push.apply(fnParams, _toConsumableArray(parseFuncParam()));
412
          } else if (lookaheadAndCheck(keywords.result) === true) {
413
            eatToken();
414
            fnResult.push.apply(fnResult, _toConsumableArray(parseFuncResult()));
415
          } else {
416
            throw function () {
417
              return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unexpected token in import of type" + ", given " + tokenToString(token));
418
            }();
419
          }
420

    
421
          eatTokenOfType(tokens.closeParen);
422
        }
423

    
424
        if (typeof fnName === "undefined") {
425
          throw new Error("Imported function must have a name");
426
        }
427

    
428
        descr = t.funcImportDescr(fnName, typeRef !== undefined ? typeRef : t.signature(fnParams, fnResult));
429
      } else if (isKeyword(token, keywords.global)) {
430
        eatToken(); // keyword
431

    
432
        if (token.type === tokens.openParen) {
433
          eatToken(); // (
434

    
435
          eatTokenOfType(tokens.keyword); // mut keyword
436

    
437
          var valtype = token.value;
438
          eatToken();
439
          descr = t.globalType(valtype, "var");
440
          eatTokenOfType(tokens.closeParen);
441
        } else {
442
          var _valtype = token.value;
443
          eatTokenOfType(tokens.valtype);
444
          descr = t.globalType(_valtype, "const");
445
        }
446
      } else if (isKeyword(token, keywords.memory) === true) {
447
        eatToken(); // Keyword
448

    
449
        descr = parseMemory();
450
      } else if (isKeyword(token, keywords.table) === true) {
451
        eatToken(); // Keyword
452

    
453
        descr = parseTable();
454
      } else {
455
        throw new Error("Unsupported import type: " + tokenToString(token));
456
      }
457

    
458
      eatTokenOfType(tokens.closeParen);
459
      return t.moduleImport(moduleName, name, descr);
460
    }
461
    /**
462
     * Parses a block instruction
463
     *
464
     * WAST:
465
     *
466
     * expr: ( block <name>? <block_sig> <instr>* )
467
     * instr: block <name>? <block_sig> <instr>* end <name>?
468
     * block_sig : ( result <type>* )*
469
     *
470
     */
471

    
472

    
473
    function parseBlock() {
474
      var label = t.identifier(getUniqueName("block"));
475
      var blockResult = null;
476
      var instr = [];
477

    
478
      if (token.type === tokens.identifier) {
479
        label = identifierFromToken(token);
480
        eatToken();
481
      } else {
482
        label = t.withRaw(label, ""); // preserve anonymous
483
      }
484

    
485
      while (token.type === tokens.openParen) {
486
        eatToken();
487

    
488
        if (lookaheadAndCheck(keywords.result) === true) {
489
          eatToken();
490
          blockResult = token.value;
491
          eatToken();
492
        } else if (lookaheadAndCheck(tokens.name) === true || lookaheadAndCheck(tokens.valtype) === true || token.type === "keyword" // is any keyword
493
        ) {
494
            // Instruction
495
            instr.push(parseFuncInstr());
496
          } else {
497
          throw function () {
498
            return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unexpected token in block body of type" + ", given " + tokenToString(token));
499
          }();
500
        }
501

    
502
        maybeIgnoreComment();
503
        eatTokenOfType(tokens.closeParen);
504
      }
505

    
506
      return t.blockInstruction(label, instr, blockResult);
507
    }
508
    /**
509
     * Parses a if instruction
510
     *
511
     * WAST:
512
     *
513
     * expr:
514
     * ( if <name>? <block_sig> ( then <instr>* ) ( else <instr>* )? )
515
     * ( if <name>? <block_sig> <expr>+ ( then <instr>* ) ( else <instr>* )? )
516
     *
517
     * instr:
518
     * if <name>? <block_sig> <instr>* end <name>?
519
     * if <name>? <block_sig> <instr>* else <name>? <instr>* end <name>?
520
     *
521
     * block_sig : ( result <type>* )*
522
     *
523
     */
524

    
525

    
526
    function parseIf() {
527
      var blockResult = null;
528
      var label = t.identifier(getUniqueName("if"));
529
      var testInstrs = [];
530
      var consequent = [];
531
      var alternate = [];
532

    
533
      if (token.type === tokens.identifier) {
534
        label = identifierFromToken(token);
535
        eatToken();
536
      } else {
537
        label = t.withRaw(label, ""); // preserve anonymous
538
      }
539

    
540
      while (token.type === tokens.openParen) {
541
        eatToken(); // (
542

    
543
        /**
544
         * Block signature
545
         */
546

    
547
        if (isKeyword(token, keywords.result) === true) {
548
          eatToken();
549
          blockResult = token.value;
550
          eatTokenOfType(tokens.valtype);
551
          eatTokenOfType(tokens.closeParen);
552
          continue;
553
        }
554
        /**
555
         * Then
556
         */
557

    
558

    
559
        if (isKeyword(token, keywords.then) === true) {
560
          eatToken(); // then
561

    
562
          while (token.type === tokens.openParen) {
563
            eatToken(); // Instruction
564

    
565
            if (lookaheadAndCheck(tokens.name) === true || lookaheadAndCheck(tokens.valtype) === true || token.type === "keyword" // is any keyword
566
            ) {
567
                consequent.push(parseFuncInstr());
568
              } else {
569
              throw function () {
570
                return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unexpected token in consequent body of type" + ", given " + tokenToString(token));
571
              }();
572
            }
573

    
574
            eatTokenOfType(tokens.closeParen);
575
          }
576

    
577
          eatTokenOfType(tokens.closeParen);
578
          continue;
579
        }
580
        /**
581
         * Alternate
582
         */
583

    
584

    
585
        if (isKeyword(token, keywords.else)) {
586
          eatToken(); // else
587

    
588
          while (token.type === tokens.openParen) {
589
            eatToken(); // Instruction
590

    
591
            if (lookaheadAndCheck(tokens.name) === true || lookaheadAndCheck(tokens.valtype) === true || token.type === "keyword" // is any keyword
592
            ) {
593
                alternate.push(parseFuncInstr());
594
              } else {
595
              throw function () {
596
                return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unexpected token in alternate body of type" + ", given " + tokenToString(token));
597
              }();
598
            }
599

    
600
            eatTokenOfType(tokens.closeParen);
601
          }
602

    
603
          eatTokenOfType(tokens.closeParen);
604
          continue;
605
        }
606
        /**
607
         * Test instruction
608
         */
609

    
610

    
611
        if (lookaheadAndCheck(tokens.name) === true || lookaheadAndCheck(tokens.valtype) === true || token.type === "keyword" // is any keyword
612
        ) {
613
            testInstrs.push(parseFuncInstr());
614
            eatTokenOfType(tokens.closeParen);
615
            continue;
616
          }
617

    
618
        throw function () {
619
          return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unexpected token in if body" + ", given " + tokenToString(token));
620
        }();
621
      }
622

    
623
      return t.ifInstruction(label, testInstrs, blockResult, consequent, alternate);
624
    }
625
    /**
626
     * Parses a loop instruction
627
     *
628
     * WAT:
629
     *
630
     * blockinstr :: 'loop' I:label rt:resulttype (in:instr*) 'end' id?
631
     *
632
     * WAST:
633
     *
634
     * instr     :: loop <name>? <block_sig> <instr>* end <name>?
635
     * expr      :: ( loop <name>? <block_sig> <instr>* )
636
     * block_sig :: ( result <type>* )*
637
     *
638
     */
639

    
640

    
641
    function parseLoop() {
642
      var label = t.identifier(getUniqueName("loop"));
643
      var blockResult;
644
      var instr = [];
645

    
646
      if (token.type === tokens.identifier) {
647
        label = identifierFromToken(token);
648
        eatToken();
649
      } else {
650
        label = t.withRaw(label, ""); // preserve anonymous
651
      }
652

    
653
      while (token.type === tokens.openParen) {
654
        eatToken();
655

    
656
        if (lookaheadAndCheck(keywords.result) === true) {
657
          eatToken();
658
          blockResult = token.value;
659
          eatToken();
660
        } else if (lookaheadAndCheck(tokens.name) === true || lookaheadAndCheck(tokens.valtype) === true || token.type === "keyword" // is any keyword
661
        ) {
662
            // Instruction
663
            instr.push(parseFuncInstr());
664
          } else {
665
          throw function () {
666
            return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unexpected token in loop body" + ", given " + tokenToString(token));
667
          }();
668
        }
669

    
670
        eatTokenOfType(tokens.closeParen);
671
      }
672

    
673
      return t.loopInstruction(label, blockResult, instr);
674
    }
675

    
676
    function parseCallIndirect() {
677
      var typeRef;
678
      var params = [];
679
      var results = [];
680
      var instrs = [];
681

    
682
      while (token.type !== tokens.closeParen) {
683
        if (lookaheadAndCheck(tokens.openParen, keywords.type)) {
684
          eatToken(); // (
685

    
686
          eatToken(); // type
687

    
688
          typeRef = parseTypeReference();
689
        } else if (lookaheadAndCheck(tokens.openParen, keywords.param)) {
690
          eatToken(); // (
691

    
692
          eatToken(); // param
693

    
694
          /**
695
           * Params can be empty:
696
           * (params)`
697
           */
698

    
699
          if (token.type !== tokens.closeParen) {
700
            params.push.apply(params, _toConsumableArray(parseFuncParam()));
701
          }
702
        } else if (lookaheadAndCheck(tokens.openParen, keywords.result)) {
703
          eatToken(); // (
704

    
705
          eatToken(); // result
706

    
707
          /**
708
           * Results can be empty:
709
           * (result)`
710
           */
711

    
712
          if (token.type !== tokens.closeParen) {
713
            results.push.apply(results, _toConsumableArray(parseFuncResult()));
714
          }
715
        } else {
716
          eatTokenOfType(tokens.openParen);
717
          instrs.push(parseFuncInstr());
718
        }
719

    
720
        eatTokenOfType(tokens.closeParen);
721
      }
722

    
723
      return t.callIndirectInstruction(typeRef !== undefined ? typeRef : t.signature(params, results), instrs);
724
    }
725
    /**
726
     * Parses an export instruction
727
     *
728
     * WAT:
729
     *
730
     * export:  ( export <string> <exkind> )
731
     * exkind:  ( func <var> )
732
     *          ( global <var> )
733
     *          ( table <var> )
734
     *          ( memory <var> )
735
     * var:    <nat> | <name>
736
     *
737
     */
738

    
739

    
740
    function parseExport() {
741
      if (token.type !== tokens.string) {
742
        throw new Error("Expected string after export, got: " + token.type);
743
      }
744

    
745
      var name = token.value;
746
      eatToken();
747
      var moduleExportDescr = parseModuleExportDescr();
748
      return t.moduleExport(name, moduleExportDescr);
749
    }
750

    
751
    function parseModuleExportDescr() {
752
      var startLoc = getStartLoc();
753
      var type = "";
754
      var index;
755
      eatTokenOfType(tokens.openParen);
756

    
757
      while (token.type !== tokens.closeParen) {
758
        if (isKeyword(token, keywords.func)) {
759
          type = "Func";
760
          eatToken();
761
          index = parseExportIndex(token);
762
        } else if (isKeyword(token, keywords.table)) {
763
          type = "Table";
764
          eatToken();
765
          index = parseExportIndex(token);
766
        } else if (isKeyword(token, keywords.global)) {
767
          type = "Global";
768
          eatToken();
769
          index = parseExportIndex(token);
770
        } else if (isKeyword(token, keywords.memory)) {
771
          type = "Memory";
772
          eatToken();
773
          index = parseExportIndex(token);
774
        }
775

    
776
        eatToken();
777
      }
778

    
779
      if (type === "") {
780
        throw new Error("Unknown export type");
781
      }
782

    
783
      if (index === undefined) {
784
        throw new Error("Exported function must have a name");
785
      }
786

    
787
      var node = t.moduleExportDescr(type, index);
788
      var endLoc = getEndLoc();
789
      eatTokenOfType(tokens.closeParen);
790
      return t.withLoc(node, endLoc, startLoc);
791
    }
792

    
793
    function parseModule() {
794
      var name = null;
795
      var isBinary = false;
796
      var isQuote = false;
797
      var moduleFields = [];
798

    
799
      if (token.type === tokens.identifier) {
800
        name = token.value;
801
        eatToken();
802
      }
803

    
804
      if (hasPlugin("wast") && token.type === tokens.name && token.value === "binary") {
805
        eatToken();
806
        isBinary = true;
807
      }
808

    
809
      if (hasPlugin("wast") && token.type === tokens.name && token.value === "quote") {
810
        eatToken();
811
        isQuote = true;
812
      }
813

    
814
      if (isBinary === true) {
815
        var blob = [];
816

    
817
        while (token.type === tokens.string) {
818
          blob.push(token.value);
819
          eatToken();
820
          maybeIgnoreComment();
821
        }
822

    
823
        eatTokenOfType(tokens.closeParen);
824
        return t.binaryModule(name, blob);
825
      }
826

    
827
      if (isQuote === true) {
828
        var string = [];
829

    
830
        while (token.type === tokens.string) {
831
          string.push(token.value);
832
          eatToken();
833
        }
834

    
835
        eatTokenOfType(tokens.closeParen);
836
        return t.quoteModule(name, string);
837
      }
838

    
839
      while (token.type !== tokens.closeParen) {
840
        moduleFields.push(walk());
841

    
842
        if (state.registredExportedElements.length > 0) {
843
          state.registredExportedElements.forEach(function (decl) {
844
            moduleFields.push(t.moduleExport(decl.name, t.moduleExportDescr(decl.exportType, decl.id)));
845
          });
846
          state.registredExportedElements = [];
847
        }
848

    
849
        token = tokensList[current];
850
      }
851

    
852
      eatTokenOfType(tokens.closeParen);
853
      return t.module(name, moduleFields);
854
    }
855
    /**
856
     * Parses the arguments of an instruction
857
     */
858

    
859

    
860
    function parseFuncInstrArguments(signature) {
861
      var args = [];
862
      var namedArgs = {};
863
      var signaturePtr = 0;
864

    
865
      while (token.type === tokens.name || isKeyword(token, keywords.offset)) {
866
        var key = token.value;
867
        eatToken();
868
        eatTokenOfType(tokens.equal);
869
        var value = void 0;
870

    
871
        if (token.type === tokens.number) {
872
          value = t.numberLiteralFromRaw(token.value);
873
        } else {
874
          throw new Error("Unexpected type for argument: " + token.type);
875
        }
876

    
877
        namedArgs[key] = value;
878
        eatToken();
879
      } // $FlowIgnore
880

    
881

    
882
      var signatureLength = signature.vector ? Infinity : signature.length;
883

    
884
      while (token.type !== tokens.closeParen && ( // $FlowIgnore
885
      token.type === tokens.openParen || signaturePtr < signatureLength)) {
886
        if (token.type === tokens.identifier) {
887
          args.push(t.identifier(token.value));
888
          eatToken();
889
        } else if (token.type === tokens.valtype) {
890
          // Handle locals
891
          args.push(t.valtypeLiteral(token.value));
892
          eatToken();
893
        } else if (token.type === tokens.string) {
894
          args.push(t.stringLiteral(token.value));
895
          eatToken();
896
        } else if (token.type === tokens.number) {
897
          args.push( // TODO(sven): refactor the type signature handling
898
          // https://github.com/xtuc/webassemblyjs/pull/129 is a good start
899
          t.numberLiteralFromRaw(token.value, // $FlowIgnore
900
          signature[signaturePtr] || "f64")); // $FlowIgnore
901

    
902
          if (!signature.vector) {
903
            ++signaturePtr;
904
          }
905

    
906
          eatToken();
907
        } else if (token.type === tokens.openParen) {
908
          /**
909
           * Maybe some nested instructions
910
           */
911
          eatToken(); // Instruction
912

    
913
          if (lookaheadAndCheck(tokens.name) === true || lookaheadAndCheck(tokens.valtype) === true || token.type === "keyword" // is any keyword
914
          ) {
915
              // $FlowIgnore
916
              args.push(parseFuncInstr());
917
            } else {
918
            throw function () {
919
              return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unexpected token in nested instruction" + ", given " + tokenToString(token));
920
            }();
921
          }
922

    
923
          if (token.type === tokens.closeParen) {
924
            eatToken();
925
          }
926
        } else {
927
          throw function () {
928
            return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unexpected token in instruction argument" + ", given " + tokenToString(token));
929
          }();
930
        }
931
      }
932

    
933
      return {
934
        args: args,
935
        namedArgs: namedArgs
936
      };
937
    }
938
    /**
939
     * Parses an instruction
940
     *
941
     * WAT:
942
     *
943
     * instr      :: plaininst
944
     *               blockinstr
945
     *
946
     * blockinstr :: 'block' I:label rt:resulttype (in:instr*) 'end' id?
947
     *               'loop' I:label rt:resulttype (in:instr*) 'end' id?
948
     *               'if' I:label rt:resulttype (in:instr*) 'else' id? (in2:intr*) 'end' id?
949
     *
950
     * plaininst  :: 'unreachable'
951
     *               'nop'
952
     *               'br' l:labelidx
953
     *               'br_if' l:labelidx
954
     *               'br_table' l*:vec(labelidx) ln:labelidx
955
     *               'return'
956
     *               'call' x:funcidx
957
     *               'call_indirect' x, I:typeuse
958
     *
959
     * WAST:
960
     *
961
     * instr:
962
     *   <expr>
963
     *   <op>
964
     *   block <name>? <block_sig> <instr>* end <name>?
965
     *   loop <name>? <block_sig> <instr>* end <name>?
966
     *   if <name>? <block_sig> <instr>* end <name>?
967
     *   if <name>? <block_sig> <instr>* else <name>? <instr>* end <name>?
968
     *
969
     * expr:
970
     *   ( <op> )
971
     *   ( <op> <expr>+ )
972
     *   ( block <name>? <block_sig> <instr>* )
973
     *   ( loop <name>? <block_sig> <instr>* )
974
     *   ( if <name>? <block_sig> ( then <instr>* ) ( else <instr>* )? )
975
     *   ( if <name>? <block_sig> <expr>+ ( then <instr>* ) ( else <instr>* )? )
976
     *
977
     * op:
978
     *   unreachable
979
     *   nop
980
     *   br <var>
981
     *   br_if <var>
982
     *   br_table <var>+
983
     *   return
984
     *   call <var>
985
     *   call_indirect <func_sig>
986
     *   drop
987
     *   select
988
     *   get_local <var>
989
     *   set_local <var>
990
     *   tee_local <var>
991
     *   get_global <var>
992
     *   set_global <var>
993
     *   <type>.load((8|16|32)_<sign>)? <offset>? <align>?
994
     *   <type>.store(8|16|32)? <offset>? <align>?
995
     *   current_memory
996
     *   grow_memory
997
     *   <type>.const <value>
998
     *   <type>.<unop>
999
     *   <type>.<binop>
1000
     *   <type>.<testop>
1001
     *   <type>.<relop>
1002
     *   <type>.<cvtop>/<type>
1003
     *
1004
     * func_type:   ( type <var> )? <param>* <result>*
1005
     */
1006

    
1007

    
1008
    function parseFuncInstr() {
1009
      var startLoc = getStartLoc();
1010
      maybeIgnoreComment();
1011
      /**
1012
       * A simple instruction
1013
       */
1014

    
1015
      if (token.type === tokens.name || token.type === tokens.valtype) {
1016
        var _name2 = token.value;
1017
        var object;
1018
        eatToken();
1019

    
1020
        if (token.type === tokens.dot) {
1021
          object = _name2;
1022
          eatToken();
1023

    
1024
          if (token.type !== tokens.name) {
1025
            throw new TypeError("Unknown token: " + token.type + ", name expected");
1026
          }
1027

    
1028
          _name2 = token.value;
1029
          eatToken();
1030
        }
1031

    
1032
        if (token.type === tokens.closeParen) {
1033
          var _endLoc = token.loc.end;
1034

    
1035
          if (typeof object === "undefined") {
1036
            return t.withLoc(t.instruction(_name2), _endLoc, startLoc);
1037
          } else {
1038
            return t.withLoc(t.objectInstruction(_name2, object, []), _endLoc, startLoc);
1039
          }
1040
        }
1041

    
1042
        var signature = t.signatureForOpcode(object || "", _name2);
1043

    
1044
        var _parseFuncInstrArgume = parseFuncInstrArguments(signature),
1045
            _args = _parseFuncInstrArgume.args,
1046
            _namedArgs = _parseFuncInstrArgume.namedArgs;
1047

    
1048
        var endLoc = token.loc.end;
1049

    
1050
        if (typeof object === "undefined") {
1051
          return t.withLoc(t.instruction(_name2, _args, _namedArgs), endLoc, startLoc);
1052
        } else {
1053
          return t.withLoc(t.objectInstruction(_name2, object, _args, _namedArgs), endLoc, startLoc);
1054
        }
1055
      } else if (isKeyword(token, keywords.loop)) {
1056
        /**
1057
         * Else a instruction with a keyword (loop or block)
1058
         */
1059
        eatToken(); // keyword
1060

    
1061
        return parseLoop();
1062
      } else if (isKeyword(token, keywords.block)) {
1063
        eatToken(); // keyword
1064

    
1065
        return parseBlock();
1066
      } else if (isKeyword(token, keywords.call_indirect)) {
1067
        eatToken(); // keyword
1068

    
1069
        return parseCallIndirect();
1070
      } else if (isKeyword(token, keywords.call)) {
1071
        eatToken(); // keyword
1072

    
1073
        var index;
1074

    
1075
        if (token.type === tokens.identifier) {
1076
          index = identifierFromToken(token);
1077
          eatToken();
1078
        } else if (token.type === tokens.number) {
1079
          index = t.indexLiteral(token.value);
1080
          eatToken();
1081
        }
1082

    
1083
        var instrArgs = []; // Nested instruction
1084

    
1085
        while (token.type === tokens.openParen) {
1086
          eatToken();
1087
          instrArgs.push(parseFuncInstr());
1088
          eatTokenOfType(tokens.closeParen);
1089
        }
1090

    
1091
        if (typeof index === "undefined") {
1092
          throw new Error("Missing argument in call instruciton");
1093
        }
1094

    
1095
        if (instrArgs.length > 0) {
1096
          return t.callInstruction(index, instrArgs);
1097
        } else {
1098
          return t.callInstruction(index);
1099
        }
1100
      } else if (isKeyword(token, keywords.if)) {
1101
        eatToken(); // Keyword
1102

    
1103
        return parseIf();
1104
      } else if (isKeyword(token, keywords.module) && hasPlugin("wast")) {
1105
        eatToken(); // In WAST you can have a module as an instruction's argument
1106
        // we will cast it into a instruction to not break the flow
1107
        // $FlowIgnore
1108

    
1109
        var module = parseModule();
1110
        return module;
1111
      } else {
1112
        throw function () {
1113
          return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unexpected instruction in function body" + ", given " + tokenToString(token));
1114
        }();
1115
      }
1116
    }
1117
    /*
1118
     * Parses a function
1119
     *
1120
     * WAT:
1121
     *
1122
     * functype :: ( 'func' t1:vec(param) t2:vec(result) )
1123
     * param    :: ( 'param' id? t:valtype )
1124
     * result   :: ( 'result' t:valtype )
1125
     *
1126
     * WAST:
1127
     *
1128
     * func     :: ( func <name>? <func_sig> <local>* <instr>* )
1129
     *             ( func <name>? ( export <string> ) <...> )
1130
     *             ( func <name>? ( import <string> <string> ) <func_sig> )
1131
     * func_sig :: ( type <var> )? <param>* <result>*
1132
     * param    :: ( param <type>* ) | ( param <name> <type> )
1133
     * result   :: ( result <type>* )
1134
     * local    :: ( local <type>* ) | ( local <name> <type> )
1135
     *
1136
     */
1137

    
1138

    
1139
    function parseFunc() {
1140
      var fnName = t.identifier(getUniqueName("func"));
1141
      var typeRef;
1142
      var fnBody = [];
1143
      var fnParams = [];
1144
      var fnResult = []; // name
1145

    
1146
      if (token.type === tokens.identifier) {
1147
        fnName = identifierFromToken(token);
1148
        eatToken();
1149
      } else {
1150
        fnName = t.withRaw(fnName, ""); // preserve anonymous
1151
      }
1152

    
1153
      maybeIgnoreComment();
1154

    
1155
      while (token.type === tokens.openParen || token.type === tokens.name || token.type === tokens.valtype) {
1156
        // Instructions without parens
1157
        if (token.type === tokens.name || token.type === tokens.valtype) {
1158
          fnBody.push(parseFuncInstr());
1159
          continue;
1160
        }
1161

    
1162
        eatToken();
1163

    
1164
        if (lookaheadAndCheck(keywords.param) === true) {
1165
          eatToken();
1166
          fnParams.push.apply(fnParams, _toConsumableArray(parseFuncParam()));
1167
        } else if (lookaheadAndCheck(keywords.result) === true) {
1168
          eatToken();
1169
          fnResult.push.apply(fnResult, _toConsumableArray(parseFuncResult()));
1170
        } else if (lookaheadAndCheck(keywords.export) === true) {
1171
          eatToken();
1172
          parseFuncExport(fnName);
1173
        } else if (lookaheadAndCheck(keywords.type) === true) {
1174
          eatToken();
1175
          typeRef = parseTypeReference();
1176
        } else if (lookaheadAndCheck(tokens.name) === true || lookaheadAndCheck(tokens.valtype) === true || token.type === "keyword" // is any keyword
1177
        ) {
1178
            // Instruction
1179
            fnBody.push(parseFuncInstr());
1180
          } else {
1181
          throw function () {
1182
            return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unexpected token in func body" + ", given " + tokenToString(token));
1183
          }();
1184
        }
1185

    
1186
        eatTokenOfType(tokens.closeParen);
1187
      }
1188

    
1189
      return t.func(fnName, typeRef !== undefined ? typeRef : t.signature(fnParams, fnResult), fnBody);
1190
    }
1191
    /**
1192
     * Parses shorthand export in func
1193
     *
1194
     * export :: ( export <string> )
1195
     */
1196

    
1197

    
1198
    function parseFuncExport(funcId) {
1199
      if (token.type !== tokens.string) {
1200
        throw function () {
1201
          return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Function export expected a string" + ", given " + tokenToString(token));
1202
        }();
1203
      }
1204

    
1205
      var name = token.value;
1206
      eatToken();
1207
      /**
1208
       * Func export shorthand, we trait it as a syntaxic sugar.
1209
       * A export ModuleField will be added later.
1210
       *
1211
       * We give the anonymous function a generated name and export it.
1212
       */
1213

    
1214
      var id = t.identifier(funcId.value);
1215
      state.registredExportedElements.push({
1216
        exportType: "Func",
1217
        name: name,
1218
        id: id
1219
      });
1220
    }
1221
    /**
1222
     * Parses a type instruction
1223
     *
1224
     * WAST:
1225
     *
1226
     * typedef: ( type <name>? ( func <param>* <result>* ) )
1227
     */
1228

    
1229

    
1230
    function parseType() {
1231
      var id;
1232
      var params = [];
1233
      var result = [];
1234

    
1235
      if (token.type === tokens.identifier) {
1236
        id = identifierFromToken(token);
1237
        eatToken();
1238
      }
1239

    
1240
      if (lookaheadAndCheck(tokens.openParen, keywords.func)) {
1241
        eatToken(); // (
1242

    
1243
        eatToken(); // func
1244

    
1245
        if (token.type === tokens.closeParen) {
1246
          eatToken(); // function with an empty signature, we can abort here
1247

    
1248
          return t.typeInstruction(id, t.signature([], []));
1249
        }
1250

    
1251
        if (lookaheadAndCheck(tokens.openParen, keywords.param)) {
1252
          eatToken(); // (
1253

    
1254
          eatToken(); // param
1255

    
1256
          params = parseFuncParam();
1257
          eatTokenOfType(tokens.closeParen);
1258
        }
1259

    
1260
        if (lookaheadAndCheck(tokens.openParen, keywords.result)) {
1261
          eatToken(); // (
1262

    
1263
          eatToken(); // result
1264

    
1265
          result = parseFuncResult();
1266
          eatTokenOfType(tokens.closeParen);
1267
        }
1268

    
1269
        eatTokenOfType(tokens.closeParen);
1270
      }
1271

    
1272
      return t.typeInstruction(id, t.signature(params, result));
1273
    }
1274
    /**
1275
     * Parses a function result
1276
     *
1277
     * WAST:
1278
     *
1279
     * result :: ( result <type>* )
1280
     */
1281

    
1282

    
1283
    function parseFuncResult() {
1284
      var results = [];
1285

    
1286
      while (token.type !== tokens.closeParen) {
1287
        if (token.type !== tokens.valtype) {
1288
          throw function () {
1289
            return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unexpected token in func result" + ", given " + tokenToString(token));
1290
          }();
1291
        }
1292

    
1293
        var valtype = token.value;
1294
        eatToken();
1295
        results.push(valtype);
1296
      }
1297

    
1298
      return results;
1299
    }
1300
    /**
1301
     * Parses a type reference
1302
     *
1303
     */
1304

    
1305

    
1306
    function parseTypeReference() {
1307
      var ref;
1308

    
1309
      if (token.type === tokens.identifier) {
1310
        ref = identifierFromToken(token);
1311
        eatToken();
1312
      } else if (token.type === tokens.number) {
1313
        ref = t.numberLiteralFromRaw(token.value);
1314
        eatToken();
1315
      }
1316

    
1317
      return ref;
1318
    }
1319
    /**
1320
     * Parses a global instruction
1321
     *
1322
     * WAST:
1323
     *
1324
     * global:  ( global <name>? <global_sig> <instr>* )
1325
     *          ( global <name>? ( export <string> ) <...> )
1326
     *          ( global <name>? ( import <string> <string> ) <global_sig> )
1327
     *
1328
     * global_sig: <type> | ( mut <type> )
1329
     *
1330
     */
1331

    
1332

    
1333
    function parseGlobal() {
1334
      var name = t.identifier(getUniqueName("global"));
1335
      var type; // Keep informations in case of a shorthand import
1336

    
1337
      var importing = null;
1338
      maybeIgnoreComment();
1339

    
1340
      if (token.type === tokens.identifier) {
1341
        name = identifierFromToken(token);
1342
        eatToken();
1343
      } else {
1344
        name = t.withRaw(name, ""); // preserve anonymous
1345
      }
1346
      /**
1347
       * maybe export
1348
       */
1349

    
1350

    
1351
      if (lookaheadAndCheck(tokens.openParen, keywords.export)) {
1352
        eatToken(); // (
1353

    
1354
        eatToken(); // export
1355

    
1356
        var exportName = token.value;
1357
        eatTokenOfType(tokens.string);
1358
        state.registredExportedElements.push({
1359
          exportType: "Global",
1360
          name: exportName,
1361
          id: name
1362
        });
1363
        eatTokenOfType(tokens.closeParen);
1364
      }
1365
      /**
1366
       * maybe import
1367
       */
1368

    
1369

    
1370
      if (lookaheadAndCheck(tokens.openParen, keywords.import)) {
1371
        eatToken(); // (
1372

    
1373
        eatToken(); // import
1374

    
1375
        var moduleName = token.value;
1376
        eatTokenOfType(tokens.string);
1377
        var _name3 = token.value;
1378
        eatTokenOfType(tokens.string);
1379
        importing = {
1380
          module: moduleName,
1381
          name: _name3,
1382
          descr: undefined
1383
        };
1384
        eatTokenOfType(tokens.closeParen);
1385
      }
1386
      /**
1387
       * global_sig
1388
       */
1389

    
1390

    
1391
      if (token.type === tokens.valtype) {
1392
        type = t.globalType(token.value, "const");
1393
        eatToken();
1394
      } else if (token.type === tokens.openParen) {
1395
        eatToken(); // (
1396

    
1397
        if (isKeyword(token, keywords.mut) === false) {
1398
          throw function () {
1399
            return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unsupported global type, expected mut" + ", given " + tokenToString(token));
1400
          }();
1401
        }
1402

    
1403
        eatToken(); // mut
1404

    
1405
        type = t.globalType(token.value, "var");
1406
        eatToken();
1407
        eatTokenOfType(tokens.closeParen);
1408
      }
1409

    
1410
      if (type === undefined) {
1411
        throw function () {
1412
          return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Could not determine global type" + ", given " + tokenToString(token));
1413
        }();
1414
      }
1415

    
1416
      maybeIgnoreComment();
1417
      var init = [];
1418

    
1419
      if (importing != null) {
1420
        importing.descr = type;
1421
        init.push(t.moduleImport(importing.module, importing.name, importing.descr));
1422
      }
1423
      /**
1424
       * instr*
1425
       */
1426

    
1427

    
1428
      while (token.type === tokens.openParen) {
1429
        eatToken();
1430
        init.push(parseFuncInstr());
1431
        eatTokenOfType(tokens.closeParen);
1432
      }
1433

    
1434
      return t.global(type, init, name);
1435
    }
1436
    /**
1437
     * Parses a function param
1438
     *
1439
     * WAST:
1440
     *
1441
     * param    :: ( param <type>* ) | ( param <name> <type> )
1442
     */
1443

    
1444

    
1445
    function parseFuncParam() {
1446
      var params = [];
1447
      var id;
1448
      var valtype;
1449

    
1450
      if (token.type === tokens.identifier) {
1451
        id = token.value;
1452
        eatToken();
1453
      }
1454

    
1455
      if (token.type === tokens.valtype) {
1456
        valtype = token.value;
1457
        eatToken();
1458
        params.push({
1459
          id: id,
1460
          valtype: valtype
1461
        });
1462
        /**
1463
         * Shorthand notation for multiple anonymous parameters
1464
         * @see https://webassembly.github.io/spec/core/text/types.html#function-types
1465
         * @see https://github.com/xtuc/webassemblyjs/issues/6
1466
         */
1467

    
1468
        if (id === undefined) {
1469
          while (token.type === tokens.valtype) {
1470
            valtype = token.value;
1471
            eatToken();
1472
            params.push({
1473
              id: undefined,
1474
              valtype: valtype
1475
            });
1476
          }
1477
        }
1478
      } else {// ignore
1479
      }
1480

    
1481
      return params;
1482
    }
1483
    /**
1484
     * Parses an element segments instruction
1485
     *
1486
     * WAST:
1487
     *
1488
     * elem:    ( elem <var>? (offset <instr>* ) <var>* )
1489
     *          ( elem <var>? <expr> <var>* )
1490
     *
1491
     * var:    <nat> | <name>
1492
     */
1493

    
1494

    
1495
    function parseElem() {
1496
      var tableIndex = t.indexLiteral(0);
1497
      var offset = [];
1498
      var funcs = [];
1499

    
1500
      if (token.type === tokens.identifier) {
1501
        tableIndex = identifierFromToken(token);
1502
        eatToken();
1503
      }
1504

    
1505
      if (token.type === tokens.number) {
1506
        tableIndex = t.indexLiteral(token.value);
1507
        eatToken();
1508
      }
1509

    
1510
      while (token.type !== tokens.closeParen) {
1511
        if (lookaheadAndCheck(tokens.openParen, keywords.offset)) {
1512
          eatToken(); // (
1513

    
1514
          eatToken(); // offset
1515

    
1516
          while (token.type !== tokens.closeParen) {
1517
            eatTokenOfType(tokens.openParen);
1518
            offset.push(parseFuncInstr());
1519
            eatTokenOfType(tokens.closeParen);
1520
          }
1521

    
1522
          eatTokenOfType(tokens.closeParen);
1523
        } else if (token.type === tokens.identifier) {
1524
          funcs.push(t.identifier(token.value));
1525
          eatToken();
1526
        } else if (token.type === tokens.number) {
1527
          funcs.push(t.indexLiteral(token.value));
1528
          eatToken();
1529
        } else if (token.type === tokens.openParen) {
1530
          eatToken(); // (
1531

    
1532
          offset.push(parseFuncInstr());
1533
          eatTokenOfType(tokens.closeParen);
1534
        } else {
1535
          throw function () {
1536
            return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unsupported token in elem" + ", given " + tokenToString(token));
1537
          }();
1538
        }
1539
      }
1540

    
1541
      return t.elem(tableIndex, offset, funcs);
1542
    }
1543
    /**
1544
     * Parses the start instruction in a module
1545
     *
1546
     * WAST:
1547
     *
1548
     * start:   ( start <var> )
1549
     * var:    <nat> | <name>
1550
     *
1551
     * WAT:
1552
     * start ::= ‘(’ ‘start’  x:funcidx ‘)’
1553
     */
1554

    
1555

    
1556
    function parseStart() {
1557
      if (token.type === tokens.identifier) {
1558
        var index = identifierFromToken(token);
1559
        eatToken();
1560
        return t.start(index);
1561
      }
1562

    
1563
      if (token.type === tokens.number) {
1564
        var _index2 = t.indexLiteral(token.value);
1565

    
1566
        eatToken();
1567
        return t.start(_index2);
1568
      }
1569

    
1570
      throw new Error("Unknown start, token: " + tokenToString(token));
1571
    }
1572

    
1573
    if (token.type === tokens.openParen) {
1574
      eatToken();
1575
      var startLoc = getStartLoc();
1576

    
1577
      if (isKeyword(token, keywords.export)) {
1578
        eatToken();
1579
        var node = parseExport();
1580

    
1581
        var _endLoc2 = getEndLoc();
1582

    
1583
        return t.withLoc(node, _endLoc2, startLoc);
1584
      }
1585

    
1586
      if (isKeyword(token, keywords.loop)) {
1587
        eatToken();
1588

    
1589
        var _node = parseLoop();
1590

    
1591
        var _endLoc3 = getEndLoc();
1592

    
1593
        return t.withLoc(_node, _endLoc3, startLoc);
1594
      }
1595

    
1596
      if (isKeyword(token, keywords.func)) {
1597
        eatToken();
1598

    
1599
        var _node2 = parseFunc();
1600

    
1601
        var _endLoc4 = getEndLoc();
1602

    
1603
        maybeIgnoreComment();
1604
        eatTokenOfType(tokens.closeParen);
1605
        return t.withLoc(_node2, _endLoc4, startLoc);
1606
      }
1607

    
1608
      if (isKeyword(token, keywords.module)) {
1609
        eatToken();
1610

    
1611
        var _node3 = parseModule();
1612

    
1613
        var _endLoc5 = getEndLoc();
1614

    
1615
        return t.withLoc(_node3, _endLoc5, startLoc);
1616
      }
1617

    
1618
      if (isKeyword(token, keywords.import)) {
1619
        eatToken();
1620

    
1621
        var _node4 = parseImport();
1622

    
1623
        var _endLoc6 = getEndLoc();
1624

    
1625
        eatTokenOfType(tokens.closeParen);
1626
        return t.withLoc(_node4, _endLoc6, startLoc);
1627
      }
1628

    
1629
      if (isKeyword(token, keywords.block)) {
1630
        eatToken();
1631

    
1632
        var _node5 = parseBlock();
1633

    
1634
        var _endLoc7 = getEndLoc();
1635

    
1636
        eatTokenOfType(tokens.closeParen);
1637
        return t.withLoc(_node5, _endLoc7, startLoc);
1638
      }
1639

    
1640
      if (isKeyword(token, keywords.memory)) {
1641
        eatToken();
1642

    
1643
        var _node6 = parseMemory();
1644

    
1645
        var _endLoc8 = getEndLoc();
1646

    
1647
        eatTokenOfType(tokens.closeParen);
1648
        return t.withLoc(_node6, _endLoc8, startLoc);
1649
      }
1650

    
1651
      if (isKeyword(token, keywords.data)) {
1652
        eatToken();
1653

    
1654
        var _node7 = parseData();
1655

    
1656
        var _endLoc9 = getEndLoc();
1657

    
1658
        eatTokenOfType(tokens.closeParen);
1659
        return t.withLoc(_node7, _endLoc9, startLoc);
1660
      }
1661

    
1662
      if (isKeyword(token, keywords.table)) {
1663
        eatToken();
1664

    
1665
        var _node8 = parseTable();
1666

    
1667
        var _endLoc10 = getEndLoc();
1668

    
1669
        eatTokenOfType(tokens.closeParen);
1670
        return t.withLoc(_node8, _endLoc10, startLoc);
1671
      }
1672

    
1673
      if (isKeyword(token, keywords.global)) {
1674
        eatToken();
1675

    
1676
        var _node9 = parseGlobal();
1677

    
1678
        var _endLoc11 = getEndLoc();
1679

    
1680
        eatTokenOfType(tokens.closeParen);
1681
        return t.withLoc(_node9, _endLoc11, startLoc);
1682
      }
1683

    
1684
      if (isKeyword(token, keywords.type)) {
1685
        eatToken();
1686

    
1687
        var _node10 = parseType();
1688

    
1689
        var _endLoc12 = getEndLoc();
1690

    
1691
        eatTokenOfType(tokens.closeParen);
1692
        return t.withLoc(_node10, _endLoc12, startLoc);
1693
      }
1694

    
1695
      if (isKeyword(token, keywords.start)) {
1696
        eatToken();
1697

    
1698
        var _node11 = parseStart();
1699

    
1700
        var _endLoc13 = getEndLoc();
1701

    
1702
        eatTokenOfType(tokens.closeParen);
1703
        return t.withLoc(_node11, _endLoc13, startLoc);
1704
      }
1705

    
1706
      if (isKeyword(token, keywords.elem)) {
1707
        eatToken();
1708

    
1709
        var _node12 = parseElem();
1710

    
1711
        var _endLoc14 = getEndLoc();
1712

    
1713
        eatTokenOfType(tokens.closeParen);
1714
        return t.withLoc(_node12, _endLoc14, startLoc);
1715
      }
1716

    
1717
      var instruction = parseFuncInstr();
1718
      var endLoc = getEndLoc();
1719
      maybeIgnoreComment();
1720

    
1721
      if (_typeof(instruction) === "object") {
1722
        if (typeof token !== "undefined") {
1723
          eatTokenOfType(tokens.closeParen);
1724
        }
1725

    
1726
        return t.withLoc(instruction, endLoc, startLoc);
1727
      }
1728
    }
1729

    
1730
    if (token.type === tokens.comment) {
1731
      var _startLoc = getStartLoc();
1732

    
1733
      var builder = token.opts.type === "leading" ? t.leadingComment : t.blockComment;
1734

    
1735
      var _node13 = builder(token.value);
1736

    
1737
      eatToken(); // comment
1738

    
1739
      var _endLoc15 = getEndLoc();
1740

    
1741
      return t.withLoc(_node13, _endLoc15, _startLoc);
1742
    }
1743

    
1744
    throw function () {
1745
      return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unknown token" + ", given " + tokenToString(token));
1746
    }();
1747
  }
1748

    
1749
  var body = [];
1750

    
1751
  while (current < tokensList.length) {
1752
    body.push(walk());
1753
  }
1754

    
1755
  return t.program(body);
1756
}
(1-1/5)