2023-12-18 13:12:25 +08:00
"use strict" ;
Object . defineProperty ( exports , "__esModule" , {
value : true
} ) ;
exports . parse = parse ;
var _helperCodeFrame = require ( "@webassemblyjs/helper-code-frame" ) ;
var t = _interopRequireWildcard ( require ( "@webassemblyjs/ast" ) ) ;
var _numberLiterals = require ( "./number-literals" ) ;
var _stringLiterals = require ( "./string-literals" ) ;
var _tokenizer = require ( "./tokenizer" ) ;
function _interopRequireWildcard ( obj ) { if ( obj && obj . _ _esModule ) { return obj ; } else { var newObj = { } ; if ( obj != null ) { for ( var key in obj ) { if ( Object . prototype . hasOwnProperty . call ( obj , key ) ) { var desc = Object . defineProperty && Object . getOwnPropertyDescriptor ? Object . getOwnPropertyDescriptor ( obj , key ) : { } ; if ( desc . get || desc . set ) { Object . defineProperty ( newObj , key , desc ) ; } else { newObj [ key ] = obj [ key ] ; } } } } newObj . default = obj ; return newObj ; } }
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 ) ; }
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 ) ; } }
function hasPlugin ( name ) {
if ( name !== "wast" ) throw new Error ( "unknow plugin" ) ;
return true ;
}
function isKeyword ( token , id ) {
return token . type === _tokenizer . tokens . keyword && token . value === id ;
}
function tokenToString ( token ) {
if ( token . type === "keyword" ) {
return "keyword (" . concat ( token . value , ")" ) ;
}
return token . type ;
}
function identifierFromToken ( token ) {
var _token$loc = token . loc ,
end = _token$loc . end ,
start = _token$loc . start ;
return t . withLoc ( t . identifier ( token . value ) , end , start ) ;
}
function parse ( tokensList , source ) {
var current = 0 ;
var getUniqueName = t . getUniqueNameGenerator ( ) ;
var state = {
registredExportedElements : [ ]
} ; // But this time we're going to use recursion instead of a `while` loop. So we
// define a `walk` function.
function walk ( ) {
var token = tokensList [ current ] ;
function eatToken ( ) {
token = tokensList [ ++ current ] ;
}
function getEndLoc ( ) {
var currentToken = token ;
if ( typeof currentToken === "undefined" ) {
var lastToken = tokensList [ tokensList . length - 1 ] ;
currentToken = lastToken ;
}
return currentToken . loc . end ;
}
function getStartLoc ( ) {
return token . loc . start ;
}
function eatTokenOfType ( type ) {
if ( token . type !== type ) {
throw new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "Assertion error: expected token of type " + type + ", given " + tokenToString ( token ) ) ;
}
eatToken ( ) ;
}
function parseExportIndex ( token ) {
if ( token . type === _tokenizer . tokens . identifier ) {
var index = identifierFromToken ( token ) ;
eatToken ( ) ;
return index ;
} else if ( token . type === _tokenizer . tokens . number ) {
var _index = t . numberLiteralFromRaw ( token . value ) ;
eatToken ( ) ;
return _index ;
} else {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "unknown export index" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
}
function lookaheadAndCheck ( ) {
var len = arguments . length ;
for ( var i = 0 ; i < len ; i ++ ) {
var tokenAhead = tokensList [ current + i ] ;
var expectedToken = i < 0 || arguments . length <= i ? undefined : arguments [ i ] ;
if ( tokenAhead . type === "keyword" ) {
if ( isKeyword ( tokenAhead , expectedToken ) === false ) {
return false ;
}
} else if ( expectedToken !== tokenAhead . type ) {
return false ;
}
}
return true ;
} // TODO(sven): there is probably a better way to do this
// can refactor it if it get out of hands
function maybeIgnoreComment ( ) {
if ( typeof token === "undefined" ) {
// Ignore
return ;
}
while ( token . type === _tokenizer . tokens . comment ) {
eatToken ( ) ;
if ( typeof token === "undefined" ) {
// Hit the end
break ;
}
}
}
/ * *
* Parses a memory instruction
*
* WAST :
*
* memory : ( memory < name > ? < memory _sig > )
* ( memory < name > ? ( export < string > ) < ... > )
* ( memory < name > ? ( import < string > < string > ) < memory _sig > )
* ( memory < name > ? ( export < string > ) * ( data < string > * )
* memory _sig : < nat > < nat > ?
*
* /
function parseMemory ( ) {
var id = t . identifier ( getUniqueName ( "memory" ) ) ;
var limits = t . limit ( 0 ) ;
if ( token . type === _tokenizer . tokens . string || token . type === _tokenizer . tokens . identifier ) {
id = t . identifier ( token . value ) ;
eatToken ( ) ;
} else {
id = t . withRaw ( id , "" ) ; // preserve anonymous
}
/ * *
* Maybe data
* /
if ( lookaheadAndCheck ( _tokenizer . tokens . openParen , _tokenizer . keywords . data ) ) {
eatToken ( ) ; // (
eatToken ( ) ; // data
// TODO(sven): do something with the data collected here
var stringInitializer = token . value ;
eatTokenOfType ( _tokenizer . tokens . string ) ; // Update limits accordingly
limits = t . limit ( stringInitializer . length ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
/ * *
* Maybe export
* /
if ( lookaheadAndCheck ( _tokenizer . tokens . openParen , _tokenizer . keywords . export ) ) {
eatToken ( ) ; // (
eatToken ( ) ; // export
if ( token . type !== _tokenizer . tokens . string ) {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Expected string in export" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
var _name = token . value ;
eatToken ( ) ;
state . registredExportedElements . push ( {
exportType : "Memory" ,
name : _name ,
id : id
} ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
/ * *
* Memory signature
* /
if ( token . type === _tokenizer . tokens . number ) {
limits = t . limit ( ( 0 , _numberLiterals . parse32I ) ( token . value ) ) ;
eatToken ( ) ;
if ( token . type === _tokenizer . tokens . number ) {
limits . max = ( 0 , _numberLiterals . parse32I ) ( token . value ) ;
eatToken ( ) ;
}
}
return t . memory ( limits , id ) ;
}
/ * *
* Parses a data section
* https : //webassembly.github.io/spec/core/text/modules.html#data-segments
*
* WAST :
*
* data : ( data < index > ? < offset > < string > )
* /
function parseData ( ) {
// optional memory index
var memidx = 0 ;
if ( token . type === _tokenizer . tokens . number ) {
memidx = token . value ;
eatTokenOfType ( _tokenizer . tokens . number ) ; // .
}
eatTokenOfType ( _tokenizer . tokens . openParen ) ;
var offset ;
if ( token . type === _tokenizer . tokens . valtype ) {
eatTokenOfType ( _tokenizer . tokens . valtype ) ; // i32
eatTokenOfType ( _tokenizer . tokens . dot ) ; // .
if ( token . value !== "const" ) {
throw new Error ( "constant expression required" ) ;
}
eatTokenOfType ( _tokenizer . tokens . name ) ; // const
var numberLiteral = t . numberLiteralFromRaw ( token . value , "i32" ) ;
offset = t . objectInstruction ( "const" , "i32" , [ numberLiteral ] ) ;
eatToken ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
} else {
eatTokenOfType ( _tokenizer . tokens . name ) ; // get_global
var _numberLiteral = t . numberLiteralFromRaw ( token . value , "i32" ) ;
offset = t . instruction ( "get_global" , [ _numberLiteral ] ) ;
eatToken ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
var byteArray = ( 0 , _stringLiterals . parseString ) ( token . value ) ;
eatToken ( ) ; // "string"
return t . data ( t . memIndexLiteral ( memidx ) , offset , t . byteArray ( byteArray ) ) ;
}
/ * *
* Parses a table instruction
*
* WAST :
*
* table : ( table < name > ? < table _type > )
* ( table < name > ? ( export < string > ) < ... > )
* ( table < name > ? ( import < string > < string > ) < table _type > )
* ( table < name > ? ( export < string > ) * < elem _type > ( elem < var > * ) )
*
* table _type : < nat > < nat > ? < elem _type >
* elem _type : anyfunc
*
* elem : ( elem < var > ? ( offset < instr > * ) < var > * )
* ( elem < var > ? < expr > < var > * )
* /
function parseTable ( ) {
var name = t . identifier ( getUniqueName ( "table" ) ) ;
var limit = t . limit ( 0 ) ;
var elemIndices = [ ] ;
var elemType = "anyfunc" ;
if ( token . type === _tokenizer . tokens . string || token . type === _tokenizer . tokens . identifier ) {
name = identifierFromToken ( token ) ;
eatToken ( ) ;
} else {
name = t . withRaw ( name , "" ) ; // preserve anonymous
}
while ( token . type !== _tokenizer . tokens . closeParen ) {
/ * *
* Maybe export
* /
if ( lookaheadAndCheck ( _tokenizer . tokens . openParen , _tokenizer . keywords . elem ) ) {
eatToken ( ) ; // (
eatToken ( ) ; // elem
while ( token . type === _tokenizer . tokens . identifier ) {
elemIndices . push ( t . identifier ( token . value ) ) ;
eatToken ( ) ;
}
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
} else if ( lookaheadAndCheck ( _tokenizer . tokens . openParen , _tokenizer . keywords . export ) ) {
eatToken ( ) ; // (
eatToken ( ) ; // export
if ( token . type !== _tokenizer . tokens . string ) {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Expected string in export" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
var exportName = token . value ;
eatToken ( ) ;
state . registredExportedElements . push ( {
exportType : "Table" ,
name : exportName ,
id : name
} ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
} else if ( isKeyword ( token , _tokenizer . keywords . anyfunc ) ) {
// It's the default value, we can ignore it
eatToken ( ) ; // anyfunc
} else if ( token . type === _tokenizer . tokens . number ) {
/ * *
* Table type
* /
var min = parseInt ( token . value ) ;
eatToken ( ) ;
if ( token . type === _tokenizer . tokens . number ) {
var max = parseInt ( token . value ) ;
eatToken ( ) ;
limit = t . limit ( min , max ) ;
} else {
limit = t . limit ( min ) ;
}
eatToken ( ) ;
} else {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Unexpected token" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
}
if ( elemIndices . length > 0 ) {
return t . table ( elemType , limit , name , elemIndices ) ;
} else {
return t . table ( elemType , limit , name ) ;
}
}
/ * *
* Parses an import statement
*
* WAST :
*
* import : ( import < string > < string > < imkind > )
* imkind : ( func < name > ? < func _sig > )
* ( global < name > ? < global _sig > )
* ( table < name > ? < table _sig > )
* ( memory < name > ? < memory _sig > )
*
* global _sig : < type > | ( mut < type > )
* /
function parseImport ( ) {
if ( token . type !== _tokenizer . tokens . string ) {
throw new Error ( "Expected a string, " + token . type + " given." ) ;
}
var moduleName = token . value ;
eatToken ( ) ;
if ( token . type !== _tokenizer . tokens . string ) {
throw new Error ( "Expected a string, " + token . type + " given." ) ;
}
var name = token . value ;
eatToken ( ) ;
eatTokenOfType ( _tokenizer . tokens . openParen ) ;
var descr ;
if ( isKeyword ( token , _tokenizer . keywords . func ) ) {
eatToken ( ) ; // keyword
var fnParams = [ ] ;
var fnResult = [ ] ;
2024-01-16 21:26:16 +08:00
var typeRef ;
2023-12-18 13:12:25 +08:00
var fnName = t . identifier ( getUniqueName ( "func" ) ) ;
if ( token . type === _tokenizer . tokens . identifier ) {
fnName = identifierFromToken ( token ) ;
eatToken ( ) ;
}
while ( token . type === _tokenizer . tokens . openParen ) {
eatToken ( ) ;
2024-01-16 21:26:16 +08:00
if ( lookaheadAndCheck ( _tokenizer . keywords . type ) === true ) {
eatToken ( ) ;
typeRef = parseTypeReference ( ) ;
} else if ( lookaheadAndCheck ( _tokenizer . keywords . param ) === true ) {
2023-12-18 13:12:25 +08:00
eatToken ( ) ;
fnParams . push . apply ( fnParams , _toConsumableArray ( parseFuncParam ( ) ) ) ;
} else if ( lookaheadAndCheck ( _tokenizer . keywords . result ) === true ) {
eatToken ( ) ;
fnResult . push . apply ( fnResult , _toConsumableArray ( parseFuncResult ( ) ) ) ;
} else {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Unexpected token in import of type" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
if ( typeof fnName === "undefined" ) {
throw new Error ( "Imported function must have a name" ) ;
}
2024-01-16 21:26:16 +08:00
descr = t . funcImportDescr ( fnName , typeRef !== undefined ? typeRef : t . signature ( fnParams , fnResult ) ) ;
2023-12-18 13:12:25 +08:00
} else if ( isKeyword ( token , _tokenizer . keywords . global ) ) {
eatToken ( ) ; // keyword
if ( token . type === _tokenizer . tokens . openParen ) {
eatToken ( ) ; // (
eatTokenOfType ( _tokenizer . tokens . keyword ) ; // mut keyword
var valtype = token . value ;
eatToken ( ) ;
descr = t . globalType ( valtype , "var" ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
} else {
var _valtype = token . value ;
eatTokenOfType ( _tokenizer . tokens . valtype ) ;
descr = t . globalType ( _valtype , "const" ) ;
}
} else if ( isKeyword ( token , _tokenizer . keywords . memory ) === true ) {
eatToken ( ) ; // Keyword
descr = parseMemory ( ) ;
} else if ( isKeyword ( token , _tokenizer . keywords . table ) === true ) {
eatToken ( ) ; // Keyword
descr = parseTable ( ) ;
} else {
throw new Error ( "Unsupported import type: " + tokenToString ( token ) ) ;
}
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
return t . moduleImport ( moduleName , name , descr ) ;
}
/ * *
* Parses a block instruction
*
* WAST :
*
* expr : ( block < name > ? < block _sig > < instr > * )
* instr : block < name > ? < block _sig > < instr > * end < name > ?
* block _sig : ( result < type > * ) *
*
* /
function parseBlock ( ) {
var label = t . identifier ( getUniqueName ( "block" ) ) ;
var blockResult = null ;
var instr = [ ] ;
if ( token . type === _tokenizer . tokens . identifier ) {
label = identifierFromToken ( token ) ;
eatToken ( ) ;
} else {
label = t . withRaw ( label , "" ) ; // preserve anonymous
}
while ( token . type === _tokenizer . tokens . openParen ) {
eatToken ( ) ;
if ( lookaheadAndCheck ( _tokenizer . keywords . result ) === true ) {
eatToken ( ) ;
blockResult = token . value ;
eatToken ( ) ;
} else if ( lookaheadAndCheck ( _tokenizer . tokens . name ) === true || lookaheadAndCheck ( _tokenizer . tokens . valtype ) === true || token . type === "keyword" // is any keyword
) {
// Instruction
instr . push ( parseFuncInstr ( ) ) ;
} else {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Unexpected token in block body of type" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
maybeIgnoreComment ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
return t . blockInstruction ( label , instr , blockResult ) ;
}
/ * *
* Parses a if instruction
*
* WAST :
*
* expr :
* ( if < name > ? < block _sig > ( then < instr > * ) ( else < instr > * ) ? )
* ( if < name > ? < block _sig > < expr > + ( then < instr > * ) ( else < instr > * ) ? )
*
* instr :
* if < name > ? < block _sig > < instr > * end < name > ?
* if < name > ? < block _sig > < instr > * else < name > ? < instr > * end < name > ?
*
* block _sig : ( result < type > * ) *
*
* /
function parseIf ( ) {
var blockResult = null ;
var label = t . identifier ( getUniqueName ( "if" ) ) ;
var testInstrs = [ ] ;
var consequent = [ ] ;
var alternate = [ ] ;
if ( token . type === _tokenizer . tokens . identifier ) {
label = identifierFromToken ( token ) ;
eatToken ( ) ;
} else {
label = t . withRaw ( label , "" ) ; // preserve anonymous
}
while ( token . type === _tokenizer . tokens . openParen ) {
eatToken ( ) ; // (
/ * *
* Block signature
* /
if ( isKeyword ( token , _tokenizer . keywords . result ) === true ) {
eatToken ( ) ;
blockResult = token . value ;
eatTokenOfType ( _tokenizer . tokens . valtype ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
continue ;
}
/ * *
* Then
* /
if ( isKeyword ( token , _tokenizer . keywords . then ) === true ) {
eatToken ( ) ; // then
while ( token . type === _tokenizer . tokens . openParen ) {
eatToken ( ) ; // Instruction
if ( lookaheadAndCheck ( _tokenizer . tokens . name ) === true || lookaheadAndCheck ( _tokenizer . tokens . valtype ) === true || token . type === "keyword" // is any keyword
) {
consequent . push ( parseFuncInstr ( ) ) ;
} else {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Unexpected token in consequent body of type" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
continue ;
}
/ * *
* Alternate
* /
if ( isKeyword ( token , _tokenizer . keywords . else ) ) {
eatToken ( ) ; // else
while ( token . type === _tokenizer . tokens . openParen ) {
eatToken ( ) ; // Instruction
if ( lookaheadAndCheck ( _tokenizer . tokens . name ) === true || lookaheadAndCheck ( _tokenizer . tokens . valtype ) === true || token . type === "keyword" // is any keyword
) {
alternate . push ( parseFuncInstr ( ) ) ;
} else {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Unexpected token in alternate body of type" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
continue ;
}
/ * *
* Test instruction
* /
if ( lookaheadAndCheck ( _tokenizer . tokens . name ) === true || lookaheadAndCheck ( _tokenizer . tokens . valtype ) === true || token . type === "keyword" // is any keyword
) {
testInstrs . push ( parseFuncInstr ( ) ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
continue ;
}
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Unexpected token in if body" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
return t . ifInstruction ( label , testInstrs , blockResult , consequent , alternate ) ;
}
/ * *
* Parses a loop instruction
*
* WAT :
*
* blockinstr : : 'loop' I : label rt : resulttype ( in : instr * ) 'end' id ?
*
* WAST :
*
* instr : : loop < name > ? < block _sig > < instr > * end < name > ?
* expr : : ( loop < name > ? < block _sig > < instr > * )
* block _sig : : ( result < type > * ) *
*
* /
function parseLoop ( ) {
var label = t . identifier ( getUniqueName ( "loop" ) ) ;
var blockResult ;
var instr = [ ] ;
if ( token . type === _tokenizer . tokens . identifier ) {
label = identifierFromToken ( token ) ;
eatToken ( ) ;
} else {
label = t . withRaw ( label , "" ) ; // preserve anonymous
}
while ( token . type === _tokenizer . tokens . openParen ) {
eatToken ( ) ;
if ( lookaheadAndCheck ( _tokenizer . keywords . result ) === true ) {
eatToken ( ) ;
blockResult = token . value ;
eatToken ( ) ;
} else if ( lookaheadAndCheck ( _tokenizer . tokens . name ) === true || lookaheadAndCheck ( _tokenizer . tokens . valtype ) === true || token . type === "keyword" // is any keyword
) {
// Instruction
instr . push ( parseFuncInstr ( ) ) ;
} else {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Unexpected token in loop body" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
return t . loopInstruction ( label , blockResult , instr ) ;
}
function parseCallIndirect ( ) {
var typeRef ;
var params = [ ] ;
var results = [ ] ;
var instrs = [ ] ;
while ( token . type !== _tokenizer . tokens . closeParen ) {
if ( lookaheadAndCheck ( _tokenizer . tokens . openParen , _tokenizer . keywords . type ) ) {
eatToken ( ) ; // (
eatToken ( ) ; // type
typeRef = parseTypeReference ( ) ;
} else if ( lookaheadAndCheck ( _tokenizer . tokens . openParen , _tokenizer . keywords . param ) ) {
eatToken ( ) ; // (
eatToken ( ) ; // param
/ * *
* Params can be empty :
* ( params ) `
* /
if ( token . type !== _tokenizer . tokens . closeParen ) {
params . push . apply ( params , _toConsumableArray ( parseFuncParam ( ) ) ) ;
}
} else if ( lookaheadAndCheck ( _tokenizer . tokens . openParen , _tokenizer . keywords . result ) ) {
eatToken ( ) ; // (
eatToken ( ) ; // result
/ * *
* Results can be empty :
* ( result ) `
* /
if ( token . type !== _tokenizer . tokens . closeParen ) {
results . push . apply ( results , _toConsumableArray ( parseFuncResult ( ) ) ) ;
}
} else {
eatTokenOfType ( _tokenizer . tokens . openParen ) ;
instrs . push ( parseFuncInstr ( ) ) ;
}
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
return t . callIndirectInstruction ( typeRef !== undefined ? typeRef : t . signature ( params , results ) , instrs ) ;
}
/ * *
* Parses an export instruction
*
* WAT :
*
* export : ( export < string > < exkind > )
* exkind : ( func < var > )
* ( global < var > )
* ( table < var > )
* ( memory < var > )
* var : < nat > | < name >
*
* /
function parseExport ( ) {
if ( token . type !== _tokenizer . tokens . string ) {
throw new Error ( "Expected string after export, got: " + token . type ) ;
}
var name = token . value ;
eatToken ( ) ;
var moduleExportDescr = parseModuleExportDescr ( ) ;
return t . moduleExport ( name , moduleExportDescr ) ;
}
function parseModuleExportDescr ( ) {
var startLoc = getStartLoc ( ) ;
var type = "" ;
var index ;
eatTokenOfType ( _tokenizer . tokens . openParen ) ;
while ( token . type !== _tokenizer . tokens . closeParen ) {
if ( isKeyword ( token , _tokenizer . keywords . func ) ) {
type = "Func" ;
eatToken ( ) ;
index = parseExportIndex ( token ) ;
} else if ( isKeyword ( token , _tokenizer . keywords . table ) ) {
type = "Table" ;
eatToken ( ) ;
index = parseExportIndex ( token ) ;
} else if ( isKeyword ( token , _tokenizer . keywords . global ) ) {
type = "Global" ;
eatToken ( ) ;
index = parseExportIndex ( token ) ;
} else if ( isKeyword ( token , _tokenizer . keywords . memory ) ) {
type = "Memory" ;
eatToken ( ) ;
index = parseExportIndex ( token ) ;
}
eatToken ( ) ;
}
if ( type === "" ) {
throw new Error ( "Unknown export type" ) ;
}
if ( index === undefined ) {
throw new Error ( "Exported function must have a name" ) ;
}
var node = t . moduleExportDescr ( type , index ) ;
var endLoc = getEndLoc ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
return t . withLoc ( node , endLoc , startLoc ) ;
}
function parseModule ( ) {
var name = null ;
var isBinary = false ;
var isQuote = false ;
var moduleFields = [ ] ;
if ( token . type === _tokenizer . tokens . identifier ) {
name = token . value ;
eatToken ( ) ;
}
if ( hasPlugin ( "wast" ) && token . type === _tokenizer . tokens . name && token . value === "binary" ) {
eatToken ( ) ;
isBinary = true ;
}
if ( hasPlugin ( "wast" ) && token . type === _tokenizer . tokens . name && token . value === "quote" ) {
eatToken ( ) ;
isQuote = true ;
}
if ( isBinary === true ) {
var blob = [ ] ;
while ( token . type === _tokenizer . tokens . string ) {
blob . push ( token . value ) ;
eatToken ( ) ;
maybeIgnoreComment ( ) ;
}
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
return t . binaryModule ( name , blob ) ;
}
if ( isQuote === true ) {
var string = [ ] ;
while ( token . type === _tokenizer . tokens . string ) {
string . push ( token . value ) ;
eatToken ( ) ;
}
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
return t . quoteModule ( name , string ) ;
}
while ( token . type !== _tokenizer . tokens . closeParen ) {
moduleFields . push ( walk ( ) ) ;
if ( state . registredExportedElements . length > 0 ) {
state . registredExportedElements . forEach ( function ( decl ) {
moduleFields . push ( t . moduleExport ( decl . name , t . moduleExportDescr ( decl . exportType , decl . id ) ) ) ;
} ) ;
state . registredExportedElements = [ ] ;
}
token = tokensList [ current ] ;
}
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
return t . module ( name , moduleFields ) ;
}
/ * *
* Parses the arguments of an instruction
* /
function parseFuncInstrArguments ( signature ) {
var args = [ ] ;
var namedArgs = { } ;
var signaturePtr = 0 ;
while ( token . type === _tokenizer . tokens . name || isKeyword ( token , _tokenizer . keywords . offset ) ) {
var key = token . value ;
eatToken ( ) ;
eatTokenOfType ( _tokenizer . tokens . equal ) ;
var value = void 0 ;
if ( token . type === _tokenizer . tokens . number ) {
value = t . numberLiteralFromRaw ( token . value ) ;
} else {
throw new Error ( "Unexpected type for argument: " + token . type ) ;
}
namedArgs [ key ] = value ;
eatToken ( ) ;
} // $FlowIgnore
var signatureLength = signature . vector ? Infinity : signature . length ;
while ( token . type !== _tokenizer . tokens . closeParen && ( // $FlowIgnore
token . type === _tokenizer . tokens . openParen || signaturePtr < signatureLength ) ) {
if ( token . type === _tokenizer . tokens . identifier ) {
args . push ( t . identifier ( token . value ) ) ;
eatToken ( ) ;
} else if ( token . type === _tokenizer . tokens . valtype ) {
// Handle locals
args . push ( t . valtypeLiteral ( token . value ) ) ;
eatToken ( ) ;
} else if ( token . type === _tokenizer . tokens . string ) {
args . push ( t . stringLiteral ( token . value ) ) ;
eatToken ( ) ;
} else if ( token . type === _tokenizer . tokens . number ) {
args . push ( // TODO(sven): refactor the type signature handling
// https://github.com/xtuc/webassemblyjs/pull/129 is a good start
t . numberLiteralFromRaw ( token . value , // $FlowIgnore
signature [ signaturePtr ] || "f64" ) ) ; // $FlowIgnore
if ( ! signature . vector ) {
++ signaturePtr ;
}
eatToken ( ) ;
} else if ( token . type === _tokenizer . tokens . openParen ) {
/ * *
* Maybe some nested instructions
* /
eatToken ( ) ; // Instruction
if ( lookaheadAndCheck ( _tokenizer . tokens . name ) === true || lookaheadAndCheck ( _tokenizer . tokens . valtype ) === true || token . type === "keyword" // is any keyword
) {
// $FlowIgnore
args . push ( parseFuncInstr ( ) ) ;
} else {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Unexpected token in nested instruction" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
if ( token . type === _tokenizer . tokens . closeParen ) {
eatToken ( ) ;
}
} else {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Unexpected token in instruction argument" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
}
return {
args : args ,
namedArgs : namedArgs
} ;
}
/ * *
* Parses an instruction
*
* WAT :
*
* instr : : plaininst
* blockinstr
*
* blockinstr : : 'block' I : label rt : resulttype ( in : instr * ) 'end' id ?
* 'loop' I : label rt : resulttype ( in : instr * ) 'end' id ?
* 'if' I : label rt : resulttype ( in : instr * ) 'else' id ? ( in2 : intr * ) 'end' id ?
*
* plaininst : : 'unreachable'
* 'nop'
* 'br' l : labelidx
* 'br_if' l : labelidx
* 'br_table' l * : vec ( labelidx ) ln : labelidx
* 'return'
* 'call' x : funcidx
* 'call_indirect' x , I : typeuse
*
* WAST :
*
* instr :
* < expr >
* < op >
* block < name > ? < block _sig > < instr > * end < name > ?
* loop < name > ? < block _sig > < instr > * end < name > ?
* if < name > ? < block _sig > < instr > * end < name > ?
* if < name > ? < block _sig > < instr > * else < name > ? < instr > * end < name > ?
*
* expr :
* ( < op > )
* ( < op > < expr > + )
* ( block < name > ? < block _sig > < instr > * )
* ( loop < name > ? < block _sig > < instr > * )
* ( if < name > ? < block _sig > ( then < instr > * ) ( else < instr > * ) ? )
* ( if < name > ? < block _sig > < expr > + ( then < instr > * ) ( else < instr > * ) ? )
*
* op :
* unreachable
* nop
* br < var >
* br _if < var >
* br _table < var > +
* return
* call < var >
* call _indirect < func _sig >
* drop
* select
* get _local < var >
* set _local < var >
* tee _local < var >
* get _global < var >
* set _global < var >
* < type > . load ( ( 8 | 16 | 32 ) _ < sign > ) ? < offset > ? < align > ?
* < type > . store ( 8 | 16 | 32 ) ? < offset > ? < align > ?
* current _memory
* grow _memory
* < type > . const < value >
* < type > . < unop >
* < type > . < binop >
* < type > . < testop >
* < type > . < relop >
* < type > . < cvtop > / < t y p e >
*
* func _type : ( type < var > ) ? < param > * < result > *
* /
function parseFuncInstr ( ) {
var startLoc = getStartLoc ( ) ;
maybeIgnoreComment ( ) ;
/ * *
* A simple instruction
* /
if ( token . type === _tokenizer . tokens . name || token . type === _tokenizer . tokens . valtype ) {
var _name2 = token . value ;
var object ;
eatToken ( ) ;
if ( token . type === _tokenizer . tokens . dot ) {
object = _name2 ;
eatToken ( ) ;
if ( token . type !== _tokenizer . tokens . name ) {
throw new TypeError ( "Unknown token: " + token . type + ", name expected" ) ;
}
_name2 = token . value ;
eatToken ( ) ;
}
if ( token . type === _tokenizer . tokens . closeParen ) {
var _endLoc = token . loc . end ;
if ( typeof object === "undefined" ) {
return t . withLoc ( t . instruction ( _name2 ) , _endLoc , startLoc ) ;
} else {
return t . withLoc ( t . objectInstruction ( _name2 , object , [ ] ) , _endLoc , startLoc ) ;
}
}
var signature = t . signatureForOpcode ( object || "" , _name2 ) ;
var _parseFuncInstrArgume = parseFuncInstrArguments ( signature ) ,
_args = _parseFuncInstrArgume . args ,
_namedArgs = _parseFuncInstrArgume . namedArgs ;
var endLoc = token . loc . end ;
if ( typeof object === "undefined" ) {
return t . withLoc ( t . instruction ( _name2 , _args , _namedArgs ) , endLoc , startLoc ) ;
} else {
return t . withLoc ( t . objectInstruction ( _name2 , object , _args , _namedArgs ) , endLoc , startLoc ) ;
}
} else if ( isKeyword ( token , _tokenizer . keywords . loop ) ) {
/ * *
* Else a instruction with a keyword ( loop or block )
* /
eatToken ( ) ; // keyword
return parseLoop ( ) ;
} else if ( isKeyword ( token , _tokenizer . keywords . block ) ) {
eatToken ( ) ; // keyword
return parseBlock ( ) ;
} else if ( isKeyword ( token , _tokenizer . keywords . call _indirect ) ) {
eatToken ( ) ; // keyword
return parseCallIndirect ( ) ;
} else if ( isKeyword ( token , _tokenizer . keywords . call ) ) {
eatToken ( ) ; // keyword
var index ;
if ( token . type === _tokenizer . tokens . identifier ) {
index = identifierFromToken ( token ) ;
eatToken ( ) ;
} else if ( token . type === _tokenizer . tokens . number ) {
index = t . indexLiteral ( token . value ) ;
eatToken ( ) ;
}
var instrArgs = [ ] ; // Nested instruction
while ( token . type === _tokenizer . tokens . openParen ) {
eatToken ( ) ;
instrArgs . push ( parseFuncInstr ( ) ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
if ( typeof index === "undefined" ) {
throw new Error ( "Missing argument in call instruciton" ) ;
}
if ( instrArgs . length > 0 ) {
return t . callInstruction ( index , instrArgs ) ;
} else {
return t . callInstruction ( index ) ;
}
} else if ( isKeyword ( token , _tokenizer . keywords . if ) ) {
eatToken ( ) ; // Keyword
return parseIf ( ) ;
} else if ( isKeyword ( token , _tokenizer . keywords . module ) && hasPlugin ( "wast" ) ) {
eatToken ( ) ; // In WAST you can have a module as an instruction's argument
// we will cast it into a instruction to not break the flow
// $FlowIgnore
var module = parseModule ( ) ;
return module ;
} else {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Unexpected instruction in function body" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
}
/ *
* Parses a function
*
* WAT :
*
* functype : : ( 'func' t1 : vec ( param ) t2 : vec ( result ) )
* param : : ( 'param' id ? t : valtype )
* result : : ( 'result' t : valtype )
*
* WAST :
*
* func : : ( func < name > ? < func _sig > < local > * < instr > * )
* ( func < name > ? ( export < string > ) < ... > )
* ( func < name > ? ( import < string > < string > ) < func _sig > )
* func _sig : : ( type < var > ) ? < param > * < result > *
* param : : ( param < type > * ) | ( param < name > < type > )
* result : : ( result < type > * )
* local : : ( local < type > * ) | ( local < name > < type > )
*
* /
function parseFunc ( ) {
var fnName = t . identifier ( getUniqueName ( "func" ) ) ;
var typeRef ;
var fnBody = [ ] ;
var fnParams = [ ] ;
var fnResult = [ ] ; // name
if ( token . type === _tokenizer . tokens . identifier ) {
fnName = identifierFromToken ( token ) ;
eatToken ( ) ;
} else {
fnName = t . withRaw ( fnName , "" ) ; // preserve anonymous
}
maybeIgnoreComment ( ) ;
while ( token . type === _tokenizer . tokens . openParen || token . type === _tokenizer . tokens . name || token . type === _tokenizer . tokens . valtype ) {
// Instructions without parens
if ( token . type === _tokenizer . tokens . name || token . type === _tokenizer . tokens . valtype ) {
fnBody . push ( parseFuncInstr ( ) ) ;
continue ;
}
eatToken ( ) ;
if ( lookaheadAndCheck ( _tokenizer . keywords . param ) === true ) {
eatToken ( ) ;
fnParams . push . apply ( fnParams , _toConsumableArray ( parseFuncParam ( ) ) ) ;
} else if ( lookaheadAndCheck ( _tokenizer . keywords . result ) === true ) {
eatToken ( ) ;
fnResult . push . apply ( fnResult , _toConsumableArray ( parseFuncResult ( ) ) ) ;
} else if ( lookaheadAndCheck ( _tokenizer . keywords . export ) === true ) {
eatToken ( ) ;
parseFuncExport ( fnName ) ;
} else if ( lookaheadAndCheck ( _tokenizer . keywords . type ) === true ) {
eatToken ( ) ;
typeRef = parseTypeReference ( ) ;
} else if ( lookaheadAndCheck ( _tokenizer . tokens . name ) === true || lookaheadAndCheck ( _tokenizer . tokens . valtype ) === true || token . type === "keyword" // is any keyword
) {
// Instruction
fnBody . push ( parseFuncInstr ( ) ) ;
} else {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Unexpected token in func body" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
return t . func ( fnName , typeRef !== undefined ? typeRef : t . signature ( fnParams , fnResult ) , fnBody ) ;
}
/ * *
* Parses shorthand export in func
*
* export : : ( export < string > )
* /
function parseFuncExport ( funcId ) {
if ( token . type !== _tokenizer . tokens . string ) {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Function export expected a string" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
var name = token . value ;
eatToken ( ) ;
/ * *
* Func export shorthand , we trait it as a syntaxic sugar .
* A export ModuleField will be added later .
*
* We give the anonymous function a generated name and export it .
* /
var id = t . identifier ( funcId . value ) ;
state . registredExportedElements . push ( {
exportType : "Func" ,
name : name ,
id : id
} ) ;
}
/ * *
* Parses a type instruction
*
* WAST :
*
* typedef : ( type < name > ? ( func < param > * < result > * ) )
* /
function parseType ( ) {
var id ;
var params = [ ] ;
var result = [ ] ;
if ( token . type === _tokenizer . tokens . identifier ) {
id = identifierFromToken ( token ) ;
eatToken ( ) ;
}
if ( lookaheadAndCheck ( _tokenizer . tokens . openParen , _tokenizer . keywords . func ) ) {
eatToken ( ) ; // (
eatToken ( ) ; // func
if ( token . type === _tokenizer . tokens . closeParen ) {
eatToken ( ) ; // function with an empty signature, we can abort here
return t . typeInstruction ( id , t . signature ( [ ] , [ ] ) ) ;
}
if ( lookaheadAndCheck ( _tokenizer . tokens . openParen , _tokenizer . keywords . param ) ) {
eatToken ( ) ; // (
eatToken ( ) ; // param
params = parseFuncParam ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
if ( lookaheadAndCheck ( _tokenizer . tokens . openParen , _tokenizer . keywords . result ) ) {
eatToken ( ) ; // (
eatToken ( ) ; // result
result = parseFuncResult ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
return t . typeInstruction ( id , t . signature ( params , result ) ) ;
}
/ * *
* Parses a function result
*
* WAST :
*
* result : : ( result < type > * )
* /
function parseFuncResult ( ) {
var results = [ ] ;
while ( token . type !== _tokenizer . tokens . closeParen ) {
if ( token . type !== _tokenizer . tokens . valtype ) {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Unexpected token in func result" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
var valtype = token . value ;
eatToken ( ) ;
results . push ( valtype ) ;
}
return results ;
}
/ * *
* Parses a type reference
*
* /
function parseTypeReference ( ) {
var ref ;
if ( token . type === _tokenizer . tokens . identifier ) {
ref = identifierFromToken ( token ) ;
eatToken ( ) ;
} else if ( token . type === _tokenizer . tokens . number ) {
ref = t . numberLiteralFromRaw ( token . value ) ;
eatToken ( ) ;
}
return ref ;
}
/ * *
* Parses a global instruction
*
* WAST :
*
* global : ( global < name > ? < global _sig > < instr > * )
* ( global < name > ? ( export < string > ) < ... > )
* ( global < name > ? ( import < string > < string > ) < global _sig > )
*
* global _sig : < type > | ( mut < type > )
*
* /
function parseGlobal ( ) {
var name = t . identifier ( getUniqueName ( "global" ) ) ;
var type ; // Keep informations in case of a shorthand import
var importing = null ;
maybeIgnoreComment ( ) ;
if ( token . type === _tokenizer . tokens . identifier ) {
name = identifierFromToken ( token ) ;
eatToken ( ) ;
} else {
name = t . withRaw ( name , "" ) ; // preserve anonymous
}
/ * *
* maybe export
* /
if ( lookaheadAndCheck ( _tokenizer . tokens . openParen , _tokenizer . keywords . export ) ) {
eatToken ( ) ; // (
eatToken ( ) ; // export
var exportName = token . value ;
eatTokenOfType ( _tokenizer . tokens . string ) ;
state . registredExportedElements . push ( {
exportType : "Global" ,
name : exportName ,
id : name
} ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
/ * *
* maybe import
* /
if ( lookaheadAndCheck ( _tokenizer . tokens . openParen , _tokenizer . keywords . import ) ) {
eatToken ( ) ; // (
eatToken ( ) ; // import
var moduleName = token . value ;
eatTokenOfType ( _tokenizer . tokens . string ) ;
var _name3 = token . value ;
eatTokenOfType ( _tokenizer . tokens . string ) ;
importing = {
module : moduleName ,
name : _name3 ,
descr : undefined
} ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
/ * *
* global _sig
* /
if ( token . type === _tokenizer . tokens . valtype ) {
type = t . globalType ( token . value , "const" ) ;
eatToken ( ) ;
} else if ( token . type === _tokenizer . tokens . openParen ) {
eatToken ( ) ; // (
if ( isKeyword ( token , _tokenizer . keywords . mut ) === false ) {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Unsupported global type, expected mut" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
eatToken ( ) ; // mut
type = t . globalType ( token . value , "var" ) ;
eatToken ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
if ( type === undefined ) {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Could not determine global type" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
maybeIgnoreComment ( ) ;
var init = [ ] ;
if ( importing != null ) {
importing . descr = type ;
init . push ( t . moduleImport ( importing . module , importing . name , importing . descr ) ) ;
}
/ * *
* instr *
* /
while ( token . type === _tokenizer . tokens . openParen ) {
eatToken ( ) ;
init . push ( parseFuncInstr ( ) ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
return t . global ( type , init , name ) ;
}
/ * *
* Parses a function param
*
* WAST :
*
* param : : ( param < type > * ) | ( param < name > < type > )
* /
function parseFuncParam ( ) {
var params = [ ] ;
var id ;
var valtype ;
if ( token . type === _tokenizer . tokens . identifier ) {
id = token . value ;
eatToken ( ) ;
}
if ( token . type === _tokenizer . tokens . valtype ) {
valtype = token . value ;
eatToken ( ) ;
params . push ( {
id : id ,
valtype : valtype
} ) ;
/ * *
* Shorthand notation for multiple anonymous parameters
* @ see https : //webassembly.github.io/spec/core/text/types.html#function-types
* @ see https : //github.com/xtuc/webassemblyjs/issues/6
* /
if ( id === undefined ) {
while ( token . type === _tokenizer . tokens . valtype ) {
valtype = token . value ;
eatToken ( ) ;
params . push ( {
id : undefined ,
valtype : valtype
} ) ;
}
}
} else { // ignore
}
return params ;
}
/ * *
* Parses an element segments instruction
*
* WAST :
*
* elem : ( elem < var > ? ( offset < instr > * ) < var > * )
* ( elem < var > ? < expr > < var > * )
*
* var : < nat > | < name >
* /
function parseElem ( ) {
var tableIndex = t . indexLiteral ( 0 ) ;
var offset = [ ] ;
var funcs = [ ] ;
if ( token . type === _tokenizer . tokens . identifier ) {
tableIndex = identifierFromToken ( token ) ;
eatToken ( ) ;
}
if ( token . type === _tokenizer . tokens . number ) {
tableIndex = t . indexLiteral ( token . value ) ;
eatToken ( ) ;
}
while ( token . type !== _tokenizer . tokens . closeParen ) {
if ( lookaheadAndCheck ( _tokenizer . tokens . openParen , _tokenizer . keywords . offset ) ) {
eatToken ( ) ; // (
eatToken ( ) ; // offset
while ( token . type !== _tokenizer . tokens . closeParen ) {
eatTokenOfType ( _tokenizer . tokens . openParen ) ;
offset . push ( parseFuncInstr ( ) ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
} else if ( token . type === _tokenizer . tokens . identifier ) {
funcs . push ( t . identifier ( token . value ) ) ;
eatToken ( ) ;
} else if ( token . type === _tokenizer . tokens . number ) {
funcs . push ( t . indexLiteral ( token . value ) ) ;
eatToken ( ) ;
} else if ( token . type === _tokenizer . tokens . openParen ) {
eatToken ( ) ; // (
offset . push ( parseFuncInstr ( ) ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
} else {
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Unsupported token in elem" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
}
return t . elem ( tableIndex , offset , funcs ) ;
}
/ * *
* Parses the start instruction in a module
*
* WAST :
*
* start : ( start < var > )
* var : < nat > | < name >
*
* WAT :
* start : : = ‘ ( ’ ‘ start ’ x : funcidx ‘ ) ’
* /
function parseStart ( ) {
if ( token . type === _tokenizer . tokens . identifier ) {
var index = identifierFromToken ( token ) ;
eatToken ( ) ;
return t . start ( index ) ;
}
if ( token . type === _tokenizer . tokens . number ) {
var _index2 = t . indexLiteral ( token . value ) ;
eatToken ( ) ;
return t . start ( _index2 ) ;
}
throw new Error ( "Unknown start, token: " + tokenToString ( token ) ) ;
}
if ( token . type === _tokenizer . tokens . openParen ) {
eatToken ( ) ;
var startLoc = getStartLoc ( ) ;
if ( isKeyword ( token , _tokenizer . keywords . export ) ) {
eatToken ( ) ;
var node = parseExport ( ) ;
var _endLoc2 = getEndLoc ( ) ;
return t . withLoc ( node , _endLoc2 , startLoc ) ;
}
if ( isKeyword ( token , _tokenizer . keywords . loop ) ) {
eatToken ( ) ;
var _node = parseLoop ( ) ;
var _endLoc3 = getEndLoc ( ) ;
return t . withLoc ( _node , _endLoc3 , startLoc ) ;
}
if ( isKeyword ( token , _tokenizer . keywords . func ) ) {
eatToken ( ) ;
var _node2 = parseFunc ( ) ;
var _endLoc4 = getEndLoc ( ) ;
maybeIgnoreComment ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
return t . withLoc ( _node2 , _endLoc4 , startLoc ) ;
}
if ( isKeyword ( token , _tokenizer . keywords . module ) ) {
eatToken ( ) ;
var _node3 = parseModule ( ) ;
var _endLoc5 = getEndLoc ( ) ;
return t . withLoc ( _node3 , _endLoc5 , startLoc ) ;
}
if ( isKeyword ( token , _tokenizer . keywords . import ) ) {
eatToken ( ) ;
var _node4 = parseImport ( ) ;
var _endLoc6 = getEndLoc ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
return t . withLoc ( _node4 , _endLoc6 , startLoc ) ;
}
if ( isKeyword ( token , _tokenizer . keywords . block ) ) {
eatToken ( ) ;
var _node5 = parseBlock ( ) ;
var _endLoc7 = getEndLoc ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
return t . withLoc ( _node5 , _endLoc7 , startLoc ) ;
}
if ( isKeyword ( token , _tokenizer . keywords . memory ) ) {
eatToken ( ) ;
var _node6 = parseMemory ( ) ;
var _endLoc8 = getEndLoc ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
return t . withLoc ( _node6 , _endLoc8 , startLoc ) ;
}
if ( isKeyword ( token , _tokenizer . keywords . data ) ) {
eatToken ( ) ;
var _node7 = parseData ( ) ;
var _endLoc9 = getEndLoc ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
return t . withLoc ( _node7 , _endLoc9 , startLoc ) ;
}
if ( isKeyword ( token , _tokenizer . keywords . table ) ) {
eatToken ( ) ;
var _node8 = parseTable ( ) ;
var _endLoc10 = getEndLoc ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
return t . withLoc ( _node8 , _endLoc10 , startLoc ) ;
}
if ( isKeyword ( token , _tokenizer . keywords . global ) ) {
eatToken ( ) ;
var _node9 = parseGlobal ( ) ;
var _endLoc11 = getEndLoc ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
return t . withLoc ( _node9 , _endLoc11 , startLoc ) ;
}
if ( isKeyword ( token , _tokenizer . keywords . type ) ) {
eatToken ( ) ;
var _node10 = parseType ( ) ;
var _endLoc12 = getEndLoc ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
return t . withLoc ( _node10 , _endLoc12 , startLoc ) ;
}
if ( isKeyword ( token , _tokenizer . keywords . start ) ) {
eatToken ( ) ;
var _node11 = parseStart ( ) ;
var _endLoc13 = getEndLoc ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
return t . withLoc ( _node11 , _endLoc13 , startLoc ) ;
}
if ( isKeyword ( token , _tokenizer . keywords . elem ) ) {
eatToken ( ) ;
var _node12 = parseElem ( ) ;
var _endLoc14 = getEndLoc ( ) ;
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
return t . withLoc ( _node12 , _endLoc14 , startLoc ) ;
}
var instruction = parseFuncInstr ( ) ;
var endLoc = getEndLoc ( ) ;
maybeIgnoreComment ( ) ;
if ( _typeof ( instruction ) === "object" ) {
if ( typeof token !== "undefined" ) {
eatTokenOfType ( _tokenizer . tokens . closeParen ) ;
}
return t . withLoc ( instruction , endLoc , startLoc ) ;
}
}
if ( token . type === _tokenizer . tokens . comment ) {
var _startLoc = getStartLoc ( ) ;
var builder = token . opts . type === "leading" ? t . leadingComment : t . blockComment ;
var _node13 = builder ( token . value ) ;
eatToken ( ) ; // comment
var _endLoc15 = getEndLoc ( ) ;
return t . withLoc ( _node13 , _endLoc15 , _startLoc ) ;
}
throw function ( ) {
return new Error ( "\n" + ( 0 , _helperCodeFrame . codeFrameFromSource ) ( source , token . loc ) + "\n" + "Unknown token" + ", given " + tokenToString ( token ) ) ;
} ( ) ;
}
var body = [ ] ;
while ( current < tokensList . length ) {
body . push ( walk ( ) ) ;
}
return t . program ( body ) ;
}