}; // 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" + codeFrameFromSource(source, token.loc) + "Assertion error: expected token of type " + type + ", given " + tokenToString(token));
}
eatToken();
}
function parseExportIndex(token) {
if (token.type === tokens.identifier) {
var index = identifierFromToken(token);
eatToken();
return index;
} else if (token.type === tokens.number) {
var _index = t.numberLiteralFromRaw(token.value);
eatToken();
return _index;
} else {
throw function () {
return new Error("\n" + 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
if (lookaheadAndCheck(tokens.name) === true || lookaheadAndCheck(tokens.valtype) === true || token.type === "keyword" // is any keyword
) {
consequent.push(parseFuncInstr());
} else {
throw function () {
return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unexpected token in consequent body of type" + ", given " + tokenToString(token));
}();
}
eatTokenOfType(tokens.closeParen);
}
eatTokenOfType(tokens.closeParen);
continue;
}
/**
* Alternate
*/
if (isKeyword(token, keywords.else)) {
eatToken(); // else
while (token.type === tokens.openParen) {
eatToken(); // Instruction
if (lookaheadAndCheck(tokens.name) === true || lookaheadAndCheck(tokens.valtype) === true || token.type === "keyword" // is any keyword
) {
alternate.push(parseFuncInstr());
} else {
throw function () {
return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unexpected token in alternate body of type" + ", given " + tokenToString(token));
}();
}
eatTokenOfType(tokens.closeParen);
}
eatTokenOfType(tokens.closeParen);
continue;
}
/**
* Test instruction
*/
if (lookaheadAndCheck(tokens.name) === true || lookaheadAndCheck(tokens.valtype) === true || token.type === "keyword" // is any keyword
) {
testInstrs.push(parseFuncInstr());
eatTokenOfType(tokens.closeParen);
continue;
}
throw function () {
return new Error("\n" + codeFrameFromSource(source, token.loc) + "\n" + "Unexpected token in if body" + ", given " + tokenToString(token));
* Else a instruction with a keyword (loop or block)
*/
eatToken(); // keyword
return parseLoop();
} else if (isKeyword(token, keywords.block)) {
eatToken(); // keyword
return parseBlock();
} else if (isKeyword(token, keywords.call_indirect)) {
eatToken(); // keyword
return parseCallIndirect();
} else if (isKeyword(token, keywords.call)) {
eatToken(); // keyword
var index;
if (token.type === tokens.identifier) {
index = identifierFromToken(token);
eatToken();
} else if (token.type === tokens.number) {
index = t.indexLiteral(token.value);
eatToken();
}
var instrArgs = []; // Nested instruction
while (token.type === tokens.openParen) {
eatToken();
instrArgs.push(parseFuncInstr());
eatTokenOfType(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, keywords.if)) {
eatToken(); // Keyword
return parseIf();
} else if (isKeyword(token, 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" + codeFrameFromSource(source, token.loc) + "\n" + "Unexpected instruction in function body" + ", given " + tokenToString(token));