diff options
author | Thomas Lively <tlively@google.com> | 2024-05-29 11:32:26 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-29 11:32:26 -0700 |
commit | d844d2e77b402d562ade8cf8fd96759b587bf09d (patch) | |
tree | 0bb0dedf7efb8b90e43340292a2c8f4f7fb063a0 /src/emscripten-optimizer | |
parent | f622b8e47c69dcbdf2666c795fb3658dc4da52af (diff) | |
download | binaryen-d844d2e77b402d562ade8cf8fd96759b587bf09d.tar.gz binaryen-d844d2e77b402d562ade8cf8fd96759b587bf09d.tar.bz2 binaryen-d844d2e77b402d562ade8cf8fd96759b587bf09d.zip |
Remove obsolete parser code (#6607)
Remove `SExpressionParser`, `SExpressionWasmBuilder`, and `cashew::Parser`.
Simplify gen-s-parser.py. Remove the --new-wat-parser and
--deprecated-wat-parser flags.
Diffstat (limited to 'src/emscripten-optimizer')
-rw-r--r-- | src/emscripten-optimizer/parser.cpp | 4 | ||||
-rw-r--r-- | src/emscripten-optimizer/parser.h | 984 |
2 files changed, 0 insertions, 988 deletions
diff --git a/src/emscripten-optimizer/parser.cpp b/src/emscripten-optimizer/parser.cpp index 533043232..c5ecfd177 100644 --- a/src/emscripten-optimizer/parser.cpp +++ b/src/emscripten-optimizer/parser.cpp @@ -112,10 +112,6 @@ IString STORE("store"); IString GETTER("get"); IString SETTER("set"); -IStringSet - keywords("var const function if else do while for break continue return " - "switch case default throw try catch finally true false null new"); - const char *OPERATOR_INITS = "+-*/%<>&^|~=!,?:.", *SEPARATORS = "([;{}"; int MAX_OPERATOR_SIZE = 3; diff --git a/src/emscripten-optimizer/parser.h b/src/emscripten-optimizer/parser.h index f1d472863..cc5032fea 100644 --- a/src/emscripten-optimizer/parser.h +++ b/src/emscripten-optimizer/parser.h @@ -162,8 +162,6 @@ extern IString STORE; extern IString GETTER; extern IString SETTER; -extern IStringSet keywords; - extern const char *OPERATOR_INITS, *SEPARATORS; extern int MAX_OPERATOR_SIZE, LOWEST_PREC; @@ -186,988 +184,6 @@ extern std::vector<OperatorClass> operatorClasses; extern bool isIdentInit(char x); extern bool isIdentPart(char x); -// parser - -template<class NodeRef, class Builder> class Parser { - - static bool isSpace(char x) { - return x == 32 || x == 9 || x == 10 || x == 13; - } /* space, tab, linefeed/newline, or return */ - static void skipSpace(char*& curr) { - while (*curr) { - if (isSpace(*curr)) { - curr++; - continue; - } - if (curr[0] == '/' && curr[1] == '/') { - curr += 2; - while (*curr && *curr != '\n') { - curr++; - } - if (*curr) { - curr++; - } - continue; - } - if (curr[0] == '/' && curr[1] == '*') { - curr += 2; - while (*curr && (curr[0] != '*' || curr[1] != '/')) { - curr++; - } - curr += 2; - continue; - } - return; - } - } - - static bool isDigit(char x) { return x >= '0' && x <= '9'; } - - static bool hasChar(const char* list, char x) { - while (*list) { - if (*list++ == x) { - return true; - } - } - return false; - } - - // An atomic fragment of something. Stops at a natural boundary. - enum FragType { - KEYWORD = 0, - OPERATOR = 1, - IDENT = 2, - STRING = 3, // without quotes - INT = 4, - DOUBLE = 5, - SEPARATOR = 6 - }; - - struct Frag { - // MSVC does not allow unrestricted unions: - // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf -#ifndef _MSC_VER - union { -#endif - IString str; - double num; -#ifndef _MSC_VER - }; -#endif - int size; - FragType type; - - bool isNumber() const { return type == INT || type == DOUBLE; } - - explicit Frag(char* src) { - char* start = src; - if (isIdentInit(*src)) { - // read an identifier or a keyword - src++; - while (isIdentPart(*src)) { - src++; - } - if (*src == 0) { - str = IString(start); - } else { - char temp = *src; - *src = 0; - str = IString(start, false); - *src = temp; - } - type = keywords.has(str) ? KEYWORD : IDENT; - } else if (isDigit(*src) || (src[0] == '.' && isDigit(src[1]))) { - if (src[0] == '0' && (src[1] == 'x' || src[1] == 'X')) { - // Explicitly parse hex numbers of form "0x...", because strtod - // supports hex number strings only in C++11, and Visual Studio 2013 - // does not yet support that functionality. - src += 2; - num = 0; - while (1) { - if (*src >= '0' && *src <= '9') { - num *= 16; - num += *src - '0'; - } else if (*src >= 'a' && *src <= 'f') { - num *= 16; - num += *src - 'a' + 10; - } else if (*src >= 'A' && *src <= 'F') { - num *= 16; - num += *src - 'A' + 10; - } else { - break; - } - src++; - } - } else { - num = strtod(start, &src); - } - // asm.js must have a '.' for double values. however, we also tolerate - // uglify's tendency to emit without a '.' (and fix it later with a +). - // for valid asm.js input, the '.' should be enough, and for uglify - // in the emscripten optimizer pipeline, we use simple_ast where - // INT/DOUBLE is quite the same at this point anyhow - type = (std::find(start, src, '.') == src && - (wasm::isSInteger32(num) || wasm::isUInteger32(num))) - ? INT - : DOUBLE; - assert(src > start); - } else if (hasChar(OPERATOR_INITS, *src)) { - switch (*src) { - case '!': - str = src[1] == '=' ? NE : L_NOT; - break; - case '%': - str = MOD; - break; - case '&': - str = AND; - break; - case '*': - str = MUL; - break; - case '+': - str = PLUS; - break; - case ',': - str = COMMA; - break; - case '-': - str = MINUS; - break; - case '.': - str = PERIOD; - break; - case '/': - str = DIV; - break; - case ':': - str = COLON; - break; - case '<': - str = src[1] == '<' ? LSHIFT : (src[1] == '=' ? LE : LT); - break; - case '=': - str = src[1] == '=' ? EQ : SET; - break; - case '>': - str = src[1] == '>' ? (src[2] == '>' ? TRSHIFT : RSHIFT) - : (src[1] == '=' ? GE : GT); - break; - case '?': - str = QUESTION; - break; - case '^': - str = XOR; - break; - case '|': - str = OR; - break; - case '~': - str = B_NOT; - break; - default: - abort(); - } - size = str.size(); -#ifndef NDEBUG - char temp = start[size]; - start[size] = 0; - assert(str.str == start); - start[size] = temp; -#endif - type = OPERATOR; - return; - } else if (hasChar(SEPARATORS, *src)) { - type = SEPARATOR; - char temp = src[1]; - src[1] = 0; - str = IString(src, false); - src[1] = temp; - src++; - } else if (*src == '"' || *src == '\'') { - char* end = strchr(src + 1, *src); - *end = 0; - str = IString(src + 1); - src = end + 1; - type = STRING; - } else { - dump("frag parsing", src); - abort(); - } - size = src - start; - } - }; - - struct ExpressionElement { - bool isNode; - // MSVC does not allow unrestricted unions: - // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf -#ifndef _MSC_VER - union { -#endif - NodeRef node; - IString op; -#ifndef _MSC_VER - }; -#endif - ExpressionElement(NodeRef n) : isNode(true), node(n) {} - ExpressionElement(IString o) : isNode(false), op(o) {} - - NodeRef getNode() { - assert(isNode); - return node; - } - IString getOp() { - assert(!isNode); - return op; - } - }; - - // This is a list of the current stack of node-operator-node-operator-etc. - // this works by each parseExpression call appending to the vector; then - // recursing out, and the toplevel sorts it all - using ExpressionParts = std::vector<ExpressionElement>; - std::vector<ExpressionParts> expressionPartsStack; - - // Parses an element in a list of such elements, e.g. list of statements in a - // block, or list of parameters in a call - NodeRef parseElement(char*& src, const char* seps = ";") { - // dump("parseElement", src); - skipSpace(src); - Frag frag(src); - src += frag.size; - switch (frag.type) { - case KEYWORD: { - return parseAfterKeyword(frag, src, seps); - } - case IDENT: { - return parseAfterIdent(frag, src, seps); - } - case STRING: - case INT: - case DOUBLE: { - return parseExpression(parseFrag(frag), src, seps); - } - case SEPARATOR: { - if (frag.str == OPEN_PAREN) { - return parseExpression(parseAfterParen(src), src, seps); - } - if (frag.str == OPEN_BRACE) { - return parseExpression(parseAfterBrace(src), src, seps); - } - if (frag.str == OPEN_CURLY) { - return parseExpression(parseAfterCurly(src), src, seps); - } - abort(); - } - case OPERATOR: { - return parseExpression(frag.str, src, seps); - } - default: - /* dump("parseElement", src); printf("bad frag type: %d\n",frag.type); - */ - abort(); - } - return nullptr; - } - - NodeRef parseFrag(Frag& frag) { - switch (frag.type) { - case IDENT: - return Builder::makeName(frag.str); - case STRING: - return Builder::makeString(frag.str); - case INT: - return Builder::makeInt(uint32_t(frag.num)); - case DOUBLE: - return Builder::makeDouble(frag.num); - default: - abort(); - } - return nullptr; - } - - NodeRef parseAfterKeyword(Frag& frag, char*& src, const char* seps) { - skipSpace(src); - if (frag.str == FUNCTION) { - return parseFunction(src, seps); - } else if (frag.str == VAR) { - return parseVar(src, seps, false); - } else if (frag.str == CONST) { - return parseVar(src, seps, true); - } else if (frag.str == RETURN) { - return parseReturn(src, seps); - } else if (frag.str == IF) { - return parseIf(src, seps); - } else if (frag.str == DO) { - return parseDo(src, seps); - } else if (frag.str == WHILE) { - return parseWhile(src, seps); - } else if (frag.str == BREAK) { - return parseBreak(src, seps); - } else if (frag.str == CONTINUE) { - return parseContinue(src, seps); - } else if (frag.str == SWITCH) { - return parseSwitch(src, seps); - } else if (frag.str == NEW) { - return parseNew(src, seps); - } else if (frag.str == FOR) { - return parseFor(src, seps); - } - dump(frag.str.str, src); - abort(); - return nullptr; - } - - NodeRef parseFunction(char*& src, const char* seps) { - Frag name(src); - if (name.type == IDENT) { - src += name.size; - } else { - assert(name.type == SEPARATOR && name.str[0] == '('); - name.str = IString(); - } - NodeRef ret = Builder::makeFunction(name.str); - skipSpace(src); - assert(*src == '('); - src++; - while (1) { - skipSpace(src); - if (*src == ')') { - break; - } - Frag arg(src); - assert(arg.type == IDENT); - src += arg.size; - Builder::appendArgumentToFunction(ret, arg.str); - skipSpace(src); - if (*src == ')') { - break; - } - if (*src == ',') { - src++; - continue; - } - abort(); - } - src++; - Builder::setBlockContent(ret, parseBracketedBlock(src)); - // TODO: parse expression? - return ret; - } - - NodeRef parseVar(char*& src, const char* seps, bool is_const) { - NodeRef ret = Builder::makeVar(is_const); - while (1) { - skipSpace(src); - if (*src == ';') { - break; - } - Frag name(src); - assert(name.type == IDENT); - NodeRef value; - src += name.size; - skipSpace(src); - if (*src == '=') { - src++; - skipSpace(src); - value = parseElement(src, ";,"); - } - Builder::appendToVar(ret, name.str, value); - skipSpace(src); - if (*src == ';') { - break; - } - if (*src == ',') { - src++; - continue; - } - abort(); - } - src++; - return ret; - } - - NodeRef parseReturn(char*& src, const char* seps) { - skipSpace(src); - NodeRef value = !hasChar(seps, *src) ? parseElement(src, seps) : nullptr; - skipSpace(src); - assert(hasChar(seps, *src)); - if (*src == ';') { - src++; - } - return Builder::makeReturn(value); - } - - NodeRef parseIf(char*& src, const char* seps) { - NodeRef condition = parseParenned(src); - NodeRef ifTrue = parseMaybeBracketed(src, seps); - skipSpace(src); - NodeRef ifFalse; - if (!hasChar(seps, *src)) { - Frag next(src); - if (next.type == KEYWORD && next.str == ELSE) { - src += next.size; - ifFalse = parseMaybeBracketed(src, seps); - } - } - return Builder::makeIf(condition, ifTrue, ifFalse); - } - - NodeRef parseDo(char*& src, const char* seps) { - NodeRef body = parseMaybeBracketed(src, seps); - skipSpace(src); - Frag next(src); - assert(next.type == KEYWORD && next.str == WHILE); - src += next.size; - NodeRef condition = parseParenned(src); - return Builder::makeDo(body, condition); - } - - NodeRef parseWhile(char*& src, const char* seps) { - NodeRef condition = parseParenned(src); - NodeRef body = parseMaybeBracketed(src, seps); - return Builder::makeWhile(condition, body); - } - - NodeRef parseFor(char*& src, const char* seps) { - skipSpace(src); - assert(*src == '('); - src++; - NodeRef init = parseElement(src, ";"); - skipSpace(src); - assert(*src == ';'); - src++; - NodeRef condition = parseElement(src, ";"); - skipSpace(src); - assert(*src == ';'); - src++; - NodeRef inc = parseElement(src, ")"); - skipSpace(src); - assert(*src == ')'); - src++; - NodeRef body = parseMaybeBracketed(src, seps); - return Builder::makeFor(init, condition, inc, body); - } - - NodeRef parseBreak(char*& src, const char* seps) { - skipSpace(src); - Frag next(src); - if (next.type == IDENT) { - src += next.size; - } - return Builder::makeBreak(next.type == IDENT ? next.str : IString()); - } - - NodeRef parseContinue(char*& src, const char* seps) { - skipSpace(src); - Frag next(src); - if (next.type == IDENT) { - src += next.size; - } - return Builder::makeContinue(next.type == IDENT ? next.str : IString()); - } - - NodeRef parseSwitch(char*& src, const char* seps) { - NodeRef ret = Builder::makeSwitch(parseParenned(src)); - skipSpace(src); - assert(*src == '{'); - src++; - while (1) { - // find all cases and possibly a default - skipSpace(src); - if (*src == '}') { - break; - } - Frag next(src); - if (next.type == KEYWORD) { - if (next.str == CASE) { - src += next.size; - skipSpace(src); - NodeRef arg; - Frag value(src); - if (value.isNumber()) { - arg = parseFrag(value); - src += value.size; - } else if (value.type == OPERATOR) { - // negative number - assert(value.str == MINUS); - src += value.size; - skipSpace(src); - Frag value2(src); - assert(value2.isNumber()); - arg = Builder::makePrefix(MINUS, parseFrag(value2)); - src += value2.size; - } else { - // identifier and function call - assert(value.type == IDENT); - src += value.size; - skipSpace(src); - arg = parseCall(parseFrag(value), src); - } - Builder::appendCaseToSwitch(ret, arg); - skipSpace(src); - assert(*src == ':'); - src++; - continue; - } else if (next.str == DEFAULT) { - src += next.size; - Builder::appendDefaultToSwitch(ret); - skipSpace(src); - assert(*src == ':'); - src++; - continue; - } - // otherwise, may be some keyword that happens to start a block (e.g. - // case 1: _return_ 5) - } - // not case X: or default: or }, so must be some code - skipSpace(src); - bool explicitBlock = *src == '{'; - NodeRef subBlock = explicitBlock ? parseBracketedBlock(src) - : parseBlock(src, ";}", CASE, DEFAULT); - Builder::appendCodeToSwitch(ret, subBlock, explicitBlock); - } - skipSpace(src); - assert(*src == '}'); - src++; - return ret; - } - - NodeRef parseNew(char*& src, const char* seps) { - return Builder::makeNew(parseElement(src, seps)); - } - - NodeRef parseAfterIdent(Frag& frag, char*& src, const char* seps) { - skipSpace(src); - if (*src == '(') { - return parseExpression(parseCall(parseFrag(frag), src), src, seps); - } - if (*src == '[') { - return parseExpression(parseIndexing(parseFrag(frag), src), src, seps); - } - if (*src == ':' && expressionPartsStack.back().size() == 0) { - src++; - skipSpace(src); - NodeRef inner; - if (*src == '{') { - // context lets us know this is not an object, but a block - inner = parseBracketedBlock(src); - } else { - inner = parseElement(src, seps); - } - return Builder::makeLabel(frag.str, inner); - } - if (*src == '.') { - return parseExpression(parseDotting(parseFrag(frag), src), src, seps); - } - return parseExpression(parseFrag(frag), src, seps); - } - - NodeRef parseCall(NodeRef target, char*& src) { - expressionPartsStack.resize(expressionPartsStack.size() + 1); - assert(*src == '('); - src++; - NodeRef ret = Builder::makeCall(target); - while (1) { - skipSpace(src); - if (*src == ')') { - break; - } - Builder::appendToCall(ret, parseElement(src, ",)")); - skipSpace(src); - if (*src == ')') { - break; - } - if (*src == ',') { - src++; - continue; - } - abort(); - } - src++; - assert(expressionPartsStack.back().size() == 0); - expressionPartsStack.pop_back(); - return ret; - } - - NodeRef parseIndexing(NodeRef target, char*& src) { - expressionPartsStack.resize(expressionPartsStack.size() + 1); - assert(*src == '['); - src++; - NodeRef ret = Builder::makeIndexing(target, parseElement(src, "]")); - skipSpace(src); - assert(*src == ']'); - src++; - assert(expressionPartsStack.back().size() == 0); - expressionPartsStack.pop_back(); - return ret; - } - - NodeRef parseDotting(NodeRef target, char*& src) { - assert(*src == '.'); - src++; - Frag key(src); - assert(key.type == IDENT); - src += key.size; - return Builder::makeDot(target, key.str); - } - - NodeRef parseAfterParen(char*& src) { - expressionPartsStack.resize(expressionPartsStack.size() + 1); - skipSpace(src); - NodeRef ret = parseElement(src, ")"); - skipSpace(src); - assert(*src == ')'); - src++; - assert(expressionPartsStack.back().size() == 0); - expressionPartsStack.pop_back(); - return ret; - } - - NodeRef parseAfterBrace(char*& src) { - expressionPartsStack.resize(expressionPartsStack.size() + 1); - NodeRef ret = Builder::makeArray(); - while (1) { - skipSpace(src); - assert(*src); - if (*src == ']') { - break; - } - NodeRef element = parseElement(src, ",]"); - Builder::appendToArray(ret, element); - skipSpace(src); - if (*src == ']') { - break; - } - if (*src == ',') { - src++; - continue; - } - abort(); - } - src++; - return ret; - } - - NodeRef parseAfterCurly(char*& src) { - expressionPartsStack.resize(expressionPartsStack.size() + 1); - NodeRef ret = Builder::makeObject(); - while (1) { - skipSpace(src); - assert(*src); - if (*src == '}') { - break; - } - Frag key(src); - assert(key.type == IDENT || key.type == STRING); - src += key.size; - skipSpace(src); - assert(*src == ':'); - src++; - NodeRef value = parseElement(src, ",}"); - Builder::appendToObject(ret, key.str, value); - skipSpace(src); - if (*src == '}') { - break; - } - if (*src == ',') { - src++; - continue; - } - abort(); - } - src++; - return ret; - } - - void dumpParts(ExpressionParts& parts, int i) { - printf("expressionparts: %d (at %d)\n", parts.size(), i); - printf("| "); - for (int i = 0; i < parts.size(); i++) { - if (parts[i].isNode) { - parts[i].getNode()->stringify(std::cout); - printf(" "); - } else { - printf(" _%s_ ", parts[i].getOp().str); - } - } - printf("|\n"); - } - - NodeRef makeBinary(NodeRef left, IString op, NodeRef right) { - if (op == PERIOD) { - return Builder::makeDot(left, right); - } else { - return Builder::makeBinary(left, op, right); - } - } - - NodeRef - parseExpression(ExpressionElement initial, char*& src, const char* seps) { - // dump("parseExpression", src); - ExpressionParts& parts = expressionPartsStack.back(); - skipSpace(src); - if (*src == 0 || hasChar(seps, *src)) { - if (parts.size() > 0) { - parts.push_back(initial); // cherry on top of the cake - } - return initial.getNode(); - } - bool top = parts.size() == 0; - if (initial.isNode) { - Frag next(src); - if (next.type == OPERATOR) { - parts.push_back(initial); - src += next.size; - parts.push_back(next.str); - } else { - if (*src == '(') { - initial = parseCall(initial.getNode(), src); - } else if (*src == '[') { - initial = parseIndexing(initial.getNode(), src); - } else { - dump("bad parseExpression state", src); - abort(); - } - return parseExpression(initial, src, seps); - } - } else { - parts.push_back(initial); - } - NodeRef last = parseElement(src, seps); - if (!top) { - return last; - } - { - // |parts| may have been invalidated by that call - ExpressionParts& parts = expressionPartsStack.back(); - // we are the toplevel. sort it all out - // collapse right to left, highest priority first - // dumpParts(parts, 0); - for (auto& ops : operatorClasses) { - if (ops.rtl) { - // right to left - for (int i = parts.size() - 1; i >= 0; i--) { - if (parts[i].isNode) { - continue; - } - IString op = parts[i].getOp(); - if (!ops.ops.has(op)) { - continue; - } - if (ops.type == OperatorClass::Binary && i > 0 && - i < (int)parts.size() - 1) { - parts[i] = - makeBinary(parts[i - 1].getNode(), op, parts[i + 1].getNode()); - parts.erase(parts.begin() + i + 1); - parts.erase(parts.begin() + i - 1); - } else if (ops.type == OperatorClass::Prefix && - i < (int)parts.size() - 1) { - if (i > 0 && parts[i - 1].isNode) { - // cannot apply prefix operator if it would join two nodes - continue; - } - parts[i] = Builder::makePrefix(op, parts[i + 1].getNode()); - parts.erase(parts.begin() + i + 1); - } else if (ops.type == OperatorClass::Tertiary) { - // we must be at X ? Y : Z - // ^ - // dumpParts(parts, i); - if (op != COLON) { - continue; - } - assert(i < (int)parts.size() - 1 && i >= 3); - if (parts[i - 2].getOp() != QUESTION) { - continue; // e.g. x ? y ? 1 : 0 : 2 - } - parts[i - 3] = Builder::makeConditional(parts[i - 3].getNode(), - parts[i - 1].getNode(), - parts[i + 1].getNode()); - parts.erase(parts.begin() + i - 2, parts.begin() + i + 2); - // basically a reset, due to things like x ? y ? 1 : 0 : 2 - i = parts.size(); - } // TODO: postfix - } - } else { - // left to right - for (int i = 0; i < (int)parts.size(); i++) { - if (parts[i].isNode) { - continue; - } - IString op = parts[i].getOp(); - if (!ops.ops.has(op)) { - continue; - } - if (ops.type == OperatorClass::Binary && i > 0 && - i < (int)parts.size() - 1) { - parts[i] = - makeBinary(parts[i - 1].getNode(), op, parts[i + 1].getNode()); - parts.erase(parts.begin() + i + 1); - parts.erase(parts.begin() + i - 1); - i--; - } else if (ops.type == OperatorClass::Prefix && - i < (int)parts.size() - 1) { - if (i > 0 && parts[i - 1].isNode) { - // cannot apply prefix operator if it would join two nodes - continue; - } - parts[i] = Builder::makePrefix(op, parts[i + 1].getNode()); - parts.erase(parts.begin() + i + 1); - // allow a previous prefix operator to cascade - i = std::max(i - 2, 0); - } // TODO: tertiary, postfix - } - } - } - assert(parts.size() == 1); - NodeRef ret = parts[0].getNode(); - parts.clear(); - return ret; - } - } - - // Parses a block of code (e.g. a bunch of statements inside {,}, or the top - // level of o file) - NodeRef parseBlock(char*& src, - const char* seps = ";", - IString keywordSep1 = IString(), - IString keywordSep2 = IString()) { - NodeRef block = Builder::makeBlock(); - // dump("parseBlock", src); - while (1) { - skipSpace(src); - if (*src == 0) { - break; - } - if (*src == ';') { - src++; // skip a statement in this block - continue; - } - if (hasChar(seps, *src)) { - break; - } - if (!!keywordSep1) { - Frag next(src); - if (next.type == KEYWORD && next.str == keywordSep1) { - break; - } - } - if (!!keywordSep2) { - Frag next(src); - if (next.type == KEYWORD && next.str == keywordSep2) { - break; - } - } - NodeRef element = parseElementOrStatement(src, seps); - Builder::appendToBlock(block, element); - } - return block; - } - - NodeRef parseBracketedBlock(char*& src) { - skipSpace(src); - assert(*src == '{'); - src++; - // the two are not symmetrical, ; is just internally separating, } is the - // final one - parseBlock knows all this - NodeRef block = parseBlock(src, ";}"); - assert(*src == '}'); - src++; - return block; - } - - NodeRef parseElementOrStatement(char*& src, const char* seps) { - skipSpace(src); - if (*src == ';') { - src++; - // we don't need the brackets here, but oh well - return Builder::makeBlock(); - } - if (*src == '{') { // detect a trivial {} in a statement context - char* before = src; - src++; - skipSpace(src); - if (*src == '}') { - src++; - // we don't need the brackets here, but oh well - return Builder::makeBlock(); - } - src = before; - } - NodeRef ret = parseElement(src, seps); - skipSpace(src); - if (*src == ';') { - ret = Builder::makeStatement(ret); - src++; - } - return ret; - } - - NodeRef parseMaybeBracketed(char*& src, const char* seps) { - skipSpace(src); - return *src == '{' ? parseBracketedBlock(src) - : parseElementOrStatement(src, seps); - } - - NodeRef parseParenned(char*& src) { - skipSpace(src); - assert(*src == '('); - src++; - NodeRef ret = parseElement(src, ")"); - skipSpace(src); - assert(*src == ')'); - src++; - return ret; - } - - // Debugging - - char* allSource = nullptr; - int allSize = 0; - - static void dump(const char* where, char* curr) { - /* - printf("%s:\n=============\n", where); - for (int i = 0; i < allSize; i++) - printf("%c", allSource[i] ? allSource[i] : - '?'); - printf("\n"); - for (int i = 0; i < (curr - allSource); i++) printf(" "); - printf("^\n=============\n"); - */ - fprintf(stderr, "%s:\n==========\n", where); - int newlinesLeft = 2; - int charsLeft = 200; - while (*curr) { - if (*curr == '\n') { - newlinesLeft--; - if (newlinesLeft == 0) { - break; - } - } - charsLeft--; - if (charsLeft == 0) { - break; - } - fprintf(stderr, "%c", *curr++); - } - fprintf(stderr, "\n\n"); - } - -public: - Parser() { expressionPartsStack.resize(1); } - - // Highest-level parsing, as of a JavaScript script file. - NodeRef parseToplevel(char* src) { - allSource = src; - allSize = strlen(src); - NodeRef toplevel = Builder::makeToplevel(); - Builder::setBlockContent(toplevel, parseBlock(src)); - return toplevel; - } -}; - } // namespace cashew #endif // wasm_parser_h |