diff options
author | Alon Zakai <azakai@google.com> | 2019-04-26 16:59:41 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-26 16:59:41 -0700 |
commit | db9124f1de0478dcac525009b6f1589b44a7edd8 (patch) | |
tree | fa26395a0f6cca53cf5cb6e10189f989c5bfa847 /src/emscripten-optimizer | |
parent | 87636dccd404a340d75acb1d96301581343f29ca (diff) | |
download | binaryen-db9124f1de0478dcac525009b6f1589b44a7edd8.tar.gz binaryen-db9124f1de0478dcac525009b6f1589b44a7edd8.tar.bz2 binaryen-db9124f1de0478dcac525009b6f1589b44a7edd8.zip |
Apply format changes from #2048 (#2059)
Mass change to apply clang-format to everything. We are applying this in a PR by me so the (git) blame is all mine ;) but @aheejin did all the work to get clang-format set up and all the manual work to tidy up some things to make the output nicer in #2048
Diffstat (limited to 'src/emscripten-optimizer')
-rw-r--r-- | src/emscripten-optimizer/istring.h | 109 | ||||
-rw-r--r-- | src/emscripten-optimizer/optimizer-shared.cpp | 234 | ||||
-rw-r--r-- | src/emscripten-optimizer/optimizer.h | 47 | ||||
-rw-r--r-- | src/emscripten-optimizer/parser.cpp | 211 | ||||
-rw-r--r-- | src/emscripten-optimizer/parser.h | 607 | ||||
-rw-r--r-- | src/emscripten-optimizer/simple_ast.cpp | 52 | ||||
-rw-r--r-- | src/emscripten-optimizer/simple_ast.h | 773 | ||||
-rw-r--r-- | src/emscripten-optimizer/snprintf.h | 34 |
8 files changed, 1209 insertions, 858 deletions
diff --git a/src/emscripten-optimizer/istring.h b/src/emscripten-optimizer/istring.h index 5c3b094c3..320a3e590 100644 --- a/src/emscripten-optimizer/istring.h +++ b/src/emscripten-optimizer/istring.h @@ -14,20 +14,21 @@ * limitations under the License. */ -// Interned String type, 100% interned on creation. Comparisons are always just a pointer comparison +// Interned String type, 100% interned on creation. Comparisons are always just +// a pointer comparison #ifndef wasm_istring_h #define wasm_istring_h -#include <unordered_set> -#include <unordered_map> #include <set> +#include <unordered_map> +#include <unordered_set> -#include <string.h> +#include <assert.h> #include <stdint.h> -#include <stdlib.h> #include <stdio.h> -#include <assert.h> +#include <stdlib.h> +#include <string.h> #include "support/threads.h" #include "support/utilities.h" @@ -35,9 +36,10 @@ namespace cashew { struct IString { - const char *str = nullptr; + const char* str = nullptr; - static size_t hash_c(const char *str) { // see http://www.cse.yorku.ca/~oz/hash.html + static size_t + hash_c(const char* str) { // see http://www.cse.yorku.ca/~oz/hash.html unsigned int hash = 5381; int c; while ((c = *str++)) { @@ -46,27 +48,27 @@ struct IString { return (size_t)hash; } - class CStringHash : public std::hash<const char *> { + class CStringHash : public std::hash<const char*> { public: - size_t operator()(const char *str) const { - return IString::hash_c(str); - } + size_t operator()(const char* str) const { return IString::hash_c(str); } }; - class CStringEqual : public std::equal_to<const char *> { + class CStringEqual : public std::equal_to<const char*> { public: - bool operator()(const char *x, const char *y) const { + bool operator()(const char* x, const char* y) const { return strcmp(x, y) == 0; } }; IString() = default; - IString(const char *s, bool reuse=true) { // if reuse=true, then input is assumed to remain alive; not copied + // if reuse=true, then input is assumed to remain alive; not copied + IString(const char* s, bool reuse = true) { assert(s); set(s, reuse); } - void set(const char *s, bool reuse=true) { - typedef std::unordered_set<const char *, CStringHash, CStringEqual> StringSet; + void set(const char* s, bool reuse = true) { + typedef std::unordered_set<const char*, CStringHash, CStringEqual> + StringSet; // one global store of strings per thread, we must not access this // in parallel thread_local static StringSet strings; @@ -79,8 +81,8 @@ struct IString { // exactly once static std::mutex mutex; std::unique_lock<std::mutex> lock(mutex); - // a single global set contains the actual strings, so we allocate each one - // exactly once. + // a single global set contains the actual strings, so we allocate each + // one exactly once. static StringSet globalStrings; auto globalExisting = globalStrings.find(s); if (globalExisting == globalStrings.end()) { @@ -103,56 +105,51 @@ struct IString { str = s; } - void set(const IString &s) { - str = s.str; - } + void set(const IString& s) { str = s.str; } - void clear() { - str = nullptr; - } + void clear() { str = nullptr; } bool operator==(const IString& other) const { - //assert((str == other.str) == !strcmp(str, other.str)); + // assert((str == other.str) == !strcmp(str, other.str)); return str == other.str; // fast! } bool operator!=(const IString& other) const { - //assert((str == other.str) == !strcmp(str, other.str)); + // assert((str == other.str) == !strcmp(str, other.str)); return str != other.str; // fast! } bool operator<(const IString& other) const { return strcmp(str ? str : "", other.str ? other.str : "") < 0; } - char operator[](int x) const { - return str[x]; - } + char operator[](int x) const { return str[x]; } bool operator!() const { // no string, or empty string return !str || str[0] == 0; } - const char *c_str() const { return str; } - bool equals(const char *other) const { return !strcmp(str, other); } + const char* c_str() const { return str; } + bool equals(const char* other) const { return !strcmp(str, other); } - bool is() const { return str != nullptr; } + bool is() const { return str != nullptr; } bool isNull() const { return str == nullptr; } - const char* stripPrefix(const char *prefix) const { - const char *ptr = str; + const char* stripPrefix(const char* prefix) const { + const char* ptr = str; while (true) { - if (*prefix == 0) return ptr; - if (*ptr == 0) return nullptr; - if (*ptr++ != *prefix++) return nullptr; + if (*prefix == 0) + return ptr; + if (*ptr == 0) + return nullptr; + if (*ptr++ != *prefix++) + return nullptr; } } - bool startsWith(const char *prefix) const { + bool startsWith(const char* prefix) const { return stripPrefix(prefix) != nullptr; } - size_t size() const { - return str ? strlen(str) : 0; - } + size_t size() const { return str ? strlen(str) : 0; } }; } // namespace cashew @@ -161,13 +158,16 @@ struct IString { namespace std { -template<> struct hash<cashew::IString> : public unary_function<cashew::IString, size_t> { +template<> +struct hash<cashew::IString> : public unary_function<cashew::IString, size_t> { size_t operator()(const cashew::IString& str) const { return std::hash<size_t>{}(size_t(str.str)); } }; -template<> struct equal_to<cashew::IString> : public binary_function<cashew::IString, cashew::IString, bool> { +template<> +struct equal_to<cashew::IString> + : public binary_function<cashew::IString, cashew::IString, bool> { bool operator()(const cashew::IString& x, const cashew::IString& y) const { return x == y; } @@ -181,32 +181,31 @@ namespace cashew { class IStringSet : public std::unordered_set<IString> { std::vector<char> data; + public: IStringSet() = default; - IStringSet(const char *init) { // comma-delimited list + IStringSet(const char* init) { // comma-delimited list int size = strlen(init) + 1; data.resize(size); - char *curr = &data[0]; + char* curr = &data[0]; strncpy(curr, init, size); while (1) { - char *end = strchr(curr, ' '); - if (end) *end = 0; + char* end = strchr(curr, ' '); + if (end) + *end = 0; insert(curr); - if (!end) break; + if (!end) + break; curr = end + 1; } } - bool has(const IString& str) { - return count(str) > 0; - } + bool has(const IString& str) { return count(str) > 0; } }; class IOrderedStringSet : public std::set<IString> { public: - bool has(const IString& str) { - return count(str) > 0; - } + bool has(const IString& str) { return count(str) > 0; } }; } // namespace cashew diff --git a/src/emscripten-optimizer/optimizer-shared.cpp b/src/emscripten-optimizer/optimizer-shared.cpp index 81f7949ba..3ac3ca7ea 100644 --- a/src/emscripten-optimizer/optimizer-shared.cpp +++ b/src/emscripten-optimizer/optimizer-shared.cpp @@ -23,14 +23,14 @@ using namespace cashew; IString ASM_FLOAT_ZERO; -IString SIMD_INT8X16_CHECK("SIMD_Int8x16_check"), - SIMD_INT16X8_CHECK("SIMD_Int16x8_check"), - SIMD_INT32X4_CHECK("SIMD_Int32x4_check"), - SIMD_FLOAT32X4_CHECK("SIMD_Float32x4_check"), - SIMD_FLOAT64X2_CHECK("SIMD_Float64x2_check"), - TEMP_RET0("tempRet0"); +IString SIMD_INT8X16_CHECK("SIMD_Int8x16_check"); +IString SIMD_INT16X8_CHECK("SIMD_Int16x8_check"); +IString SIMD_INT32X4_CHECK("SIMD_Int32x4_check"); +IString SIMD_FLOAT32X4_CHECK("SIMD_Float32x4_check"); +IString SIMD_FLOAT64X2_CHECK("SIMD_Float64x2_check"); +IString TEMP_RET0("tempRet0"); -int parseInt(const char *str) { +int parseInt(const char* str) { int ret = *str - '0'; while (*(++str)) { ret *= 10; @@ -39,7 +39,7 @@ int parseInt(const char *str) { return ret; } -HeapInfo parseHeap(const char *name) { +HeapInfo parseHeap(const char* name) { HeapInfo ret; if (name[0] != 'H' || name[1] != 'E' || name[2] != 'A' || name[3] != 'P') { ret.valid = false; @@ -53,33 +53,49 @@ HeapInfo parseHeap(const char *name) { return ret; } -AsmType detectType(Ref node, AsmData *asmData, bool inVarDef, IString minifiedFround, bool allowI64) { +AsmType detectType(Ref node, + AsmData* asmData, + bool inVarDef, + IString minifiedFround, + bool allowI64) { if (node->isString()) { if (asmData) { AsmType ret = asmData->getType(node->getCString()); - if (ret != ASM_NONE) return ret; + if (ret != ASM_NONE) + return ret; } if (!inVarDef) { - if (node == INF || node == NaN) return ASM_DOUBLE; - if (node == TEMP_RET0) return ASM_INT; + if (node == INF || node == NaN) + return ASM_DOUBLE; + if (node == TEMP_RET0) + return ASM_INT; return ASM_NONE; } - // We are in a variable definition, where Math_fround(0) optimized into a global constant becomes f0 = Math_fround(0) - if (ASM_FLOAT_ZERO.isNull()) ASM_FLOAT_ZERO = node->getIString(); - else assert(node == ASM_FLOAT_ZERO); + // We are in a variable definition, where Math_fround(0) optimized into a + // global constant becomes f0 = Math_fround(0) + if (ASM_FLOAT_ZERO.isNull()) + ASM_FLOAT_ZERO = node->getIString(); + else + assert(node == ASM_FLOAT_ZERO); return ASM_FLOAT; } if (node->isNumber()) { - if (!wasm::isInteger(node->getNumber())) return ASM_DOUBLE; + if (!wasm::isInteger(node->getNumber())) + return ASM_DOUBLE; return ASM_INT; } switch (node[0]->getCString()[0]) { case 'u': { if (node[0] == UNARY_PREFIX) { switch (node[1]->getCString()[0]) { - case '+': return ASM_DOUBLE; - case '-': return detectType(node[2], asmData, inVarDef, minifiedFround, allowI64); - case '!': case '~': return ASM_INT; + case '+': + return ASM_DOUBLE; + case '-': + return detectType( + node[2], asmData, inVarDef, minifiedFround, allowI64); + case '!': + case '~': + return ASM_INT; } break; } @@ -89,13 +105,20 @@ AsmType detectType(Ref node, AsmData *asmData, bool inVarDef, IString minifiedFr if (node[0] == CALL) { if (node[1]->isString()) { IString name = node[1]->getIString(); - if (name == MATH_FROUND || name == minifiedFround) return ASM_FLOAT; - else if (allowI64 && (name == INT64 || name == INT64_CONST)) return ASM_INT64; - else if (name == SIMD_FLOAT32X4 || name == SIMD_FLOAT32X4_CHECK) return ASM_FLOAT32X4; - else if (name == SIMD_FLOAT64X2 || name == SIMD_FLOAT64X2_CHECK) return ASM_FLOAT64X2; - else if (name == SIMD_INT8X16 || name == SIMD_INT8X16_CHECK) return ASM_INT8X16; - else if (name == SIMD_INT16X8 || name == SIMD_INT16X8_CHECK) return ASM_INT16X8; - else if (name == SIMD_INT32X4 || name == SIMD_INT32X4_CHECK) return ASM_INT32X4; + if (name == MATH_FROUND || name == minifiedFround) + return ASM_FLOAT; + else if (allowI64 && (name == INT64 || name == INT64_CONST)) + return ASM_INT64; + else if (name == SIMD_FLOAT32X4 || name == SIMD_FLOAT32X4_CHECK) + return ASM_FLOAT32X4; + else if (name == SIMD_FLOAT64X2 || name == SIMD_FLOAT64X2_CHECK) + return ASM_FLOAT64X2; + else if (name == SIMD_INT8X16 || name == SIMD_INT8X16_CHECK) + return ASM_INT8X16; + else if (name == SIMD_INT16X8 || name == SIMD_INT16X8_CHECK) + return ASM_INT16X8; + else if (name == SIMD_INT32X4 || name == SIMD_INT32X4_CHECK) + return ASM_INT32X4; } return ASM_NONE; } else if (node[0] == CONDITIONAL) { @@ -106,10 +129,20 @@ AsmType detectType(Ref node, AsmData *asmData, bool inVarDef, IString minifiedFr case 'b': { if (node[0] == BINARY) { switch (node[1]->getCString()[0]) { - case '+': case '-': - case '*': case '/': case '%': return detectType(node[2], asmData, inVarDef, minifiedFround, allowI64); - case '|': case '&': case '^': case '<': case '>': // handles <<, >>, >>=, <=, >= - case '=': case '!': { // handles ==, != + case '+': + case '-': + case '*': + case '/': + case '%': + return detectType( + node[2], asmData, inVarDef, minifiedFround, allowI64); + case '|': + case '&': + case '^': + case '<': + case '>': // handles <<, >>, >>=, <=, >= + case '=': + case '!': { // handles ==, != return ASM_INT; } } @@ -122,14 +155,15 @@ AsmType detectType(Ref node, AsmData *asmData, bool inVarDef, IString minifiedFr } else if (node[0] == SUB) { assert(node[1]->isString()); HeapInfo info = parseHeap(node[1][1]->getCString()); - if (info.valid) return ASM_NONE; + if (info.valid) + return ASM_NONE; return info.floaty ? ASM_DOUBLE : ASM_INT; // XXX ASM_FLOAT? } break; } } - //dump("horrible", node); - //assert(0); + // dump("horrible", node); + // assert(0); return ASM_NONE; } @@ -145,9 +179,12 @@ AsmSign detectSign(Ref node, IString minifiedFround) { } if (node->isNumber()) { double value = node->getNumber(); - if (value < 0) return ASM_SIGNED; - if (value > uint32_t(-1) || fmod(value, 1) != 0) return ASM_NONSIGNED; - if (wasm::isSInteger32(value)) return ASM_FLEXIBLE; + if (value < 0) + return ASM_SIGNED; + if (value > uint32_t(-1) || fmod(value, 1) != 0) + return ASM_NONSIGNED; + if (wasm::isSInteger32(value)) + return ASM_FLEXIBLE; return ASM_UNSIGNED; } IString type = node[0]->getIString(); @@ -155,25 +192,44 @@ AsmSign detectSign(Ref node, IString minifiedFround) { IString op = node[1]->getIString(); switch (op.str[0]) { case '>': { - if (op == TRSHIFT) return ASM_UNSIGNED; + if (op == TRSHIFT) + return ASM_UNSIGNED; } // fallthrough - case '|': case '&': case '^': case '<': case '=': case '!': return ASM_SIGNED; - case '+': case '-': return ASM_FLEXIBLE; - case '*': case '/': case '%': return ASM_NONSIGNED; // without a coercion, these are double - default: abort_on(node); + case '|': + case '&': + case '^': + case '<': + case '=': + case '!': + return ASM_SIGNED; + case '+': + case '-': + return ASM_FLEXIBLE; + case '*': + case '/': + case '%': + return ASM_NONSIGNED; // without a coercion, these are double + default: + abort_on(node); } } else if (type == UNARY_PREFIX) { IString op = node[1]->getIString(); switch (op.str[0]) { - case '-': return ASM_FLEXIBLE; - case '+': return ASM_NONSIGNED; // XXX double - case '~': return ASM_SIGNED; - default: abort_on(node); + case '-': + return ASM_FLEXIBLE; + case '+': + return ASM_NONSIGNED; // XXX double + case '~': + return ASM_SIGNED; + default: + abort_on(node); } } else if (type == CONDITIONAL) { return detectSign(node[2], minifiedFround); } else if (type == CALL) { - if (node[1]->isString() && (node[1] == MATH_FROUND || node[1] == minifiedFround)) return ASM_NONSIGNED; + if (node[1]->isString() && + (node[1] == MATH_FROUND || node[1] == minifiedFround)) + return ASM_NONSIGNED; } else if (type == SEQ) { return detectSign(node[2], minifiedFround); } @@ -183,8 +239,12 @@ AsmSign detectSign(Ref node, IString minifiedFround) { Ref makeAsmCoercedZero(AsmType type) { switch (type) { - case ASM_INT: return ValueBuilder::makeNum(0); break; - case ASM_DOUBLE: return ValueBuilder::makeUnary(PLUS, ValueBuilder::makeNum(0)); break; + case ASM_INT: + return ValueBuilder::makeNum(0); + break; + case ASM_DOUBLE: + return ValueBuilder::makeUnary(PLUS, ValueBuilder::makeNum(0)); + break; case ASM_FLOAT: { if (!ASM_FLOAT_ZERO.isNull()) { return ValueBuilder::makeName(ASM_FLOAT_ZERO); @@ -194,46 +254,92 @@ Ref makeAsmCoercedZero(AsmType type) { break; } case ASM_FLOAT32X4: { - return ValueBuilder::makeCall(SIMD_FLOAT32X4, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0)); + return ValueBuilder::makeCall(SIMD_FLOAT32X4, + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0)); break; } case ASM_FLOAT64X2: { - return ValueBuilder::makeCall(SIMD_FLOAT64X2, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0)); + return ValueBuilder::makeCall( + SIMD_FLOAT64X2, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0)); break; } case ASM_INT8X16: { - return ValueBuilder::makeCall(SIMD_INT8X16, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0)); + return ValueBuilder::makeCall(SIMD_INT8X16, + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0)); break; } case ASM_INT16X8: { - return ValueBuilder::makeCall(SIMD_INT16X8, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0)); + return ValueBuilder::makeCall(SIMD_INT16X8, + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0)); break; } case ASM_INT32X4: { - return ValueBuilder::makeCall(SIMD_INT32X4, ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0), ValueBuilder::makeNum(0)); + return ValueBuilder::makeCall(SIMD_INT32X4, + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0), + ValueBuilder::makeNum(0)); break; } - default: assert(0); + default: + assert(0); } abort(); } Ref makeAsmCoercion(Ref node, AsmType type) { switch (type) { - case ASM_INT: return ValueBuilder::makeBinary(node, OR, ValueBuilder::makeNum(0)); - case ASM_DOUBLE: return ValueBuilder::makeUnary(PLUS, node); - case ASM_FLOAT: return ValueBuilder::makeCall(MATH_FROUND, node); - case ASM_FLOAT32X4: return ValueBuilder::makeCall(SIMD_FLOAT32X4_CHECK, node); - case ASM_FLOAT64X2: return ValueBuilder::makeCall(SIMD_FLOAT64X2_CHECK, node); - case ASM_INT8X16: return ValueBuilder::makeCall(SIMD_INT8X16_CHECK, node); - case ASM_INT16X8: return ValueBuilder::makeCall(SIMD_INT16X8_CHECK, node); - case ASM_INT32X4: return ValueBuilder::makeCall(SIMD_INT32X4_CHECK, node); + case ASM_INT: + return ValueBuilder::makeBinary(node, OR, ValueBuilder::makeNum(0)); + case ASM_DOUBLE: + return ValueBuilder::makeUnary(PLUS, node); + case ASM_FLOAT: + return ValueBuilder::makeCall(MATH_FROUND, node); + case ASM_FLOAT32X4: + return ValueBuilder::makeCall(SIMD_FLOAT32X4_CHECK, node); + case ASM_FLOAT64X2: + return ValueBuilder::makeCall(SIMD_FLOAT64X2_CHECK, node); + case ASM_INT8X16: + return ValueBuilder::makeCall(SIMD_INT8X16_CHECK, node); + case ASM_INT16X8: + return ValueBuilder::makeCall(SIMD_INT16X8_CHECK, node); + case ASM_INT32X4: + return ValueBuilder::makeCall(SIMD_INT32X4_CHECK, node); case ASM_NONE: - default: return node; // non-validating code, emit nothing XXX this is dangerous, we should only allow this when we know we are not validating + default: + // non-validating code, emit nothing XXX this is dangerous, we should only + // allow this when we know we are not validating + return node; } } Ref makeSigning(Ref node, AsmSign sign) { assert(sign == ASM_SIGNED || sign == ASM_UNSIGNED); - return ValueBuilder::makeBinary(node, sign == ASM_SIGNED ? OR : TRSHIFT, ValueBuilder::makeNum(0)); + return ValueBuilder::makeBinary( + node, sign == ASM_SIGNED ? OR : TRSHIFT, ValueBuilder::makeNum(0)); } diff --git a/src/emscripten-optimizer/optimizer.h b/src/emscripten-optimizer/optimizer.h index f6b3aa536..36a9322fd 100644 --- a/src/emscripten-optimizer/optimizer.h +++ b/src/emscripten-optimizer/optimizer.h @@ -19,11 +19,7 @@ #include "simple_ast.h" -extern bool preciseF32, - receiveJSON, - emitJSON, - minifyWhitespace, - last; +extern bool preciseF32, receiveJSON, emitJSON, minifyWhitespace, last; extern cashew::Ref extraInfo; @@ -39,12 +35,16 @@ enum AsmType { ASM_INT16X8, ASM_INT32X4, ASM_INT64, // non-asm.js - ASM_NONE // number of types + ASM_NONE // number of types }; struct AsmData; -AsmType detectType(cashew::Ref node, AsmData *asmData=nullptr, bool inVarDef=false, cashew::IString minifiedFround=cashew::IString(), bool allowI64=false); +AsmType detectType(cashew::Ref node, + AsmData* asmData = nullptr, + bool inVarDef = false, + cashew::IString minifiedFround = cashew::IString(), + bool allowI64 = false); struct AsmData { struct Local { @@ -57,23 +57,22 @@ struct AsmData { Locals locals; std::vector<cashew::IString> params; // in order - std::vector<cashew::IString> vars; // in order + std::vector<cashew::IString> vars; // in order AsmType ret; cashew::Ref func; AsmType getType(const cashew::IString& name) { auto ret = locals.find(name); - if (ret != locals.end()) return ret->second.type; + if (ret != locals.end()) + return ret->second.type; return ASM_NONE; } void setType(const cashew::IString& name, AsmType type) { locals[name].type = type; } - bool isLocal(const cashew::IString& name) { - return locals.count(name) > 0; - } + bool isLocal(const cashew::IString& name) { return locals.count(name) > 0; } bool isParam(const cashew::IString& name) { return isLocal(name) && locals[name].param; } @@ -81,8 +80,11 @@ struct AsmData { return isLocal(name) && !locals[name].param; } - AsmData() = default; // if you want to fill in the data yourself - AsmData(cashew::Ref f); // if you want to read data from f, and modify it as you go (parallel to denormalize) + // if you want to fill in the data yourself + AsmData() = default; + // if you want to read data from f, and modify it as you go (parallel to + // denormalize) + AsmData(cashew::Ref f); void denormalize(); @@ -108,13 +110,13 @@ struct AsmData { extern cashew::IString ASM_FLOAT_ZERO; -extern cashew::IString SIMD_INT8X16_CHECK, - SIMD_INT16X8_CHECK, - SIMD_INT32X4_CHECK, - SIMD_FLOAT32X4_CHECK, - SIMD_FLOAT64X2_CHECK; +extern cashew::IString SIMD_INT8X16_CHECK; +extern cashew::IString SIMD_INT16X8_CHECK; +extern cashew::IString SIMD_INT32X4_CHECK; +extern cashew::IString SIMD_FLOAT32X4_CHECK; +extern cashew::IString SIMD_FLOAT64X2_CHECK; -int parseInt(const char *str); +int parseInt(const char* str); struct HeapInfo { bool valid, unsign, floaty; @@ -122,10 +124,11 @@ struct HeapInfo { AsmType type; }; -HeapInfo parseHeap(const char *name); +HeapInfo parseHeap(const char* name); enum AsmSign { - ASM_FLEXIBLE = 0, // small constants can be signed or unsigned, variables are also flexible + // small constants can be signed or unsigned, variables are also flexible + ASM_FLEXIBLE = 0, ASM_SIGNED = 1, ASM_UNSIGNED = 2, ASM_NONSIGNED = 3, diff --git a/src/emscripten-optimizer/parser.cpp b/src/emscripten-optimizer/parser.cpp index 035817090..72740908e 100644 --- a/src/emscripten-optimizer/parser.cpp +++ b/src/emscripten-optimizer/parser.cpp @@ -20,117 +20,119 @@ namespace cashew { // common strings -IString TOPLEVEL("toplevel"), - DEFUN("defun"), - BLOCK("block"), - VAR("var"), - CONST("const"), - CONDITIONAL("conditional"), - BINARY("binary"), - RETURN("return"), - IF("if"), - ELSE("else"), - WHILE("while"), - DO("do"), - FOR("for"), - SEQ("seq"), - SUB("sub"), - CALL("call"), - LABEL("label"), - BREAK("break"), - CONTINUE("continue"), - SWITCH("switch"), - STRING("string"), - TRY("try"), - INF("inf"), - NaN("nan"), - LLVM_CTTZ_I32("_llvm_cttz_i32"), - UDIVMODDI4("___udivmoddi4"), - UNARY_PREFIX("unary-prefix"), - UNARY_POSTFIX("unary-postfix"), - MATH_FROUND("Math_fround"), - MATH_CLZ32("Math_clz32"), - INT64("i64"), - INT64_CONST("i64_const"), - SIMD_FLOAT32X4("SIMD_Float32x4"), - SIMD_FLOAT64X2("SIMD_Float64x2"), - SIMD_INT8X16("SIMD_Int8x16"), - SIMD_INT16X8("SIMD_Int16x8"), - SIMD_INT32X4("SIMD_Int32x4"), - PLUS("+"), - MINUS("-"), - OR("|"), - AND("&"), - XOR("^"), - L_NOT("!"), - B_NOT("~"), - LT("<"), - GE(">="), - LE("<="), - GT(">"), - EQ("=="), - NE("!="), - DIV("/"), - MOD("%"), - MUL("*"), - RSHIFT(">>"), - LSHIFT("<<"), - TRSHIFT(">>>"), - HEAP8("HEAP8"), - HEAP16("HEAP16"), - HEAP32("HEAP32"), - HEAPF32("HEAPF32"), - HEAPU8("HEAPU8"), - HEAPU16("HEAPU16"), - HEAPU32("HEAPU32"), - HEAPF64("HEAPF64"), - F0("f0"), - EMPTY(""), - FUNCTION("function"), - OPEN_PAREN("("), - OPEN_BRACE("["), - OPEN_CURLY("{"), - CLOSE_CURLY("}"), - COMMA(","), - QUESTION("?"), - COLON(":"), - CASE("case"), - DEFAULT("default"), - DOT("dot"), - PERIOD("."), - NEW("new"), - ARRAY("array"), - OBJECT("object"), - THROW("throw"), - 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 = "([;{}"; +IString TOPLEVEL("toplevel"); +IString DEFUN("defun"); +IString BLOCK("block"); +IString VAR("var"); +IString CONST("const"); +IString CONDITIONAL("conditional"); +IString BINARY("binary"); +IString RETURN("return"); +IString IF("if"); +IString ELSE("else"); +IString WHILE("while"); +IString DO("do"); +IString FOR("for"); +IString SEQ("seq"); +IString SUB("sub"); +IString CALL("call"); +IString LABEL("label"); +IString BREAK("break"); +IString CONTINUE("continue"); +IString SWITCH("switch"); +IString STRING("string"); +IString TRY("try"); +IString INF("inf"); +IString NaN("nan"); +IString LLVM_CTTZ_I32("_llvm_cttz_i32"); +IString UDIVMODDI4("___udivmoddi4"); +IString UNARY_PREFIX("unary-prefix"); +IString UNARY_POSTFIX("unary-postfix"); +IString MATH_FROUND("Math_fround"); +IString MATH_CLZ32("Math_clz32"); +IString INT64("i64"); +IString INT64_CONST("i64_const"); +IString SIMD_FLOAT32X4("SIMD_Float32x4"); +IString SIMD_FLOAT64X2("SIMD_Float64x2"); +IString SIMD_INT8X16("SIMD_Int8x16"); +IString SIMD_INT16X8("SIMD_Int16x8"); +IString SIMD_INT32X4("SIMD_Int32x4"); +IString PLUS("+"); +IString MINUS("-"); +IString OR("|"); +IString AND("&"); +IString XOR("^"); +IString L_NOT("!"); +IString B_NOT("~"); +IString LT("<"); +IString GE(">="); +IString LE("<="); +IString GT(">"); +IString EQ("=="); +IString NE("!="); +IString DIV("/"); +IString MOD("%"); +IString MUL("*"); +IString RSHIFT(">>"); +IString LSHIFT("<<"); +IString TRSHIFT(">>>"); +IString HEAP8("HEAP8"); +IString HEAP16("HEAP16"); +IString HEAP32("HEAP32"); +IString HEAPF32("HEAPF32"); +IString HEAPU8("HEAPU8"); +IString HEAPU16("HEAPU16"); +IString HEAPU32("HEAPU32"); +IString HEAPF64("HEAPF64"); +IString F0("f0"); +IString EMPTY(""); +IString FUNCTION("function"); +IString OPEN_PAREN("("); +IString OPEN_BRACE("["); +IString OPEN_CURLY("{"); +IString CLOSE_CURLY("}"); +IString COMMA(","); +IString QUESTION("?"); +IString COLON(":"); +IString CASE("case"); +IString DEFAULT("default"); +IString DOT("dot"); +IString PERIOD("."); +IString NEW("new"); +IString ARRAY("array"); +IString OBJECT("object"); +IString THROW("throw"); +IString 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; std::vector<OperatorClass> operatorClasses; -static std::vector<std::unordered_map<IString, int>> precedences; // op, type => prec +static std::vector<std::unordered_map<IString, int>> + precedences; // op, type => prec struct Init { Init() { // operators, rtl, type - operatorClasses.emplace_back(".", false, OperatorClass::Binary); - operatorClasses.emplace_back("! ~ + -", true, OperatorClass::Prefix); - operatorClasses.emplace_back("* / %", false, OperatorClass::Binary); - operatorClasses.emplace_back("+ -", false, OperatorClass::Binary); + operatorClasses.emplace_back(".", false, OperatorClass::Binary); + operatorClasses.emplace_back("! ~ + -", true, OperatorClass::Prefix); + operatorClasses.emplace_back("* / %", false, OperatorClass::Binary); + operatorClasses.emplace_back("+ -", false, OperatorClass::Binary); operatorClasses.emplace_back("<< >> >>>", false, OperatorClass::Binary); operatorClasses.emplace_back("< <= > >=", false, OperatorClass::Binary); - operatorClasses.emplace_back("== !=", false, OperatorClass::Binary); - operatorClasses.emplace_back("&", false, OperatorClass::Binary); - operatorClasses.emplace_back("^", false, OperatorClass::Binary); - operatorClasses.emplace_back("|", false, OperatorClass::Binary); - operatorClasses.emplace_back("? :", true, OperatorClass::Tertiary); - operatorClasses.emplace_back("=", true, OperatorClass::Binary); - operatorClasses.emplace_back(",", true, OperatorClass::Binary); + operatorClasses.emplace_back("== !=", false, OperatorClass::Binary); + operatorClasses.emplace_back("&", false, OperatorClass::Binary); + operatorClasses.emplace_back("^", false, OperatorClass::Binary); + operatorClasses.emplace_back("|", false, OperatorClass::Binary); + operatorClasses.emplace_back("? :", true, OperatorClass::Tertiary); + operatorClasses.emplace_back("=", true, OperatorClass::Binary); + operatorClasses.emplace_back(",", true, OperatorClass::Binary); precedences.resize(OperatorClass::Tertiary + 1); @@ -148,11 +150,12 @@ int OperatorClass::getPrecedence(Type type, IString op) { return precedences[type][op]; } -bool OperatorClass::getRtl(int prec) { - return operatorClasses[prec].rtl; -} +bool OperatorClass::getRtl(int prec) { return operatorClasses[prec].rtl; } -bool isIdentInit(char x) { return (x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || x == '_' || x == '$'; } +bool isIdentInit(char x) { + return (x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || x == '_' || + x == '$'; +} bool isIdentPart(char x) { return isIdentInit(x) || (x >= '0' && x <= '9'); } } // namespace cashew diff --git a/src/emscripten-optimizer/parser.h b/src/emscripten-optimizer/parser.h index 78ed27933..d180ea12c 100644 --- a/src/emscripten-optimizer/parser.h +++ b/src/emscripten-optimizer/parser.h @@ -14,10 +14,12 @@ * limitations under the License. */ -// Pure parsing. Calls methods on a Builder (template argument) to actually construct the AST +// Pure parsing. Calls methods on a Builder (template argument) to actually +// construct the AST // -// XXX All parsing methods assume they take ownership of the input string. This lets them reuse -// parts of it. You will segfault if the input string cannot be reused and written to. +// XXX All parsing methods assume they take ownership of the input string. This +// lets them reuse parts of it. You will segfault if the input string cannot +// be reused and written to. #ifndef wasm_parser_h #define wasm_parser_h @@ -35,89 +37,89 @@ namespace cashew { // common strings -extern IString TOPLEVEL, - DEFUN, - BLOCK, - VAR, - CONST, - CONDITIONAL, - BINARY, - RETURN, - IF, - ELSE, - WHILE, - DO, - FOR, - SEQ, - SUB, - CALL, - LABEL, - BREAK, - CONTINUE, - SWITCH, - STRING, - TRY, - INF, - NaN, - LLVM_CTTZ_I32, - UDIVMODDI4, - UNARY_PREFIX, - UNARY_POSTFIX, - MATH_FROUND, - MATH_CLZ32, - INT64, - INT64_CONST, - SIMD_FLOAT32X4, - SIMD_FLOAT64X2, - SIMD_INT8X16, - SIMD_INT16X8, - SIMD_INT32X4, - PLUS, - MINUS, - OR, - AND, - XOR, - L_NOT, - B_NOT, - LT, - GE, - LE, - GT, - EQ, - NE, - DIV, - MOD, - MUL, - RSHIFT, - LSHIFT, - TRSHIFT, - HEAP8, - HEAP16, - HEAP32, - HEAPF32, - HEAPU8, - HEAPU16, - HEAPU32, - HEAPF64, - F0, - EMPTY, - FUNCTION, - OPEN_PAREN, - OPEN_BRACE, - OPEN_CURLY, - CLOSE_CURLY, - COMMA, - QUESTION, - COLON, - CASE, - DEFAULT, - DOT, - PERIOD, - NEW, - ARRAY, - OBJECT, - THROW, - SET; +extern IString TOPLEVEL; +extern IString DEFUN; +extern IString BLOCK; +extern IString VAR; +extern IString CONST; +extern IString CONDITIONAL; +extern IString BINARY; +extern IString RETURN; +extern IString IF; +extern IString ELSE; +extern IString WHILE; +extern IString DO; +extern IString FOR; +extern IString SEQ; +extern IString SUB; +extern IString CALL; +extern IString LABEL; +extern IString BREAK; +extern IString CONTINUE; +extern IString SWITCH; +extern IString STRING; +extern IString TRY; +extern IString INF; +extern IString NaN; +extern IString LLVM_CTTZ_I32; +extern IString UDIVMODDI4; +extern IString UNARY_PREFIX; +extern IString UNARY_POSTFIX; +extern IString MATH_FROUND; +extern IString MATH_CLZ32; +extern IString INT64; +extern IString INT64_CONST; +extern IString SIMD_FLOAT32X4; +extern IString SIMD_FLOAT64X2; +extern IString SIMD_INT8X16; +extern IString SIMD_INT16X8; +extern IString SIMD_INT32X4; +extern IString PLUS; +extern IString MINUS; +extern IString OR; +extern IString AND; +extern IString XOR; +extern IString L_NOT; +extern IString B_NOT; +extern IString LT; +extern IString GE; +extern IString LE; +extern IString GT; +extern IString EQ; +extern IString NE; +extern IString DIV; +extern IString MOD; +extern IString MUL; +extern IString RSHIFT; +extern IString LSHIFT; +extern IString TRSHIFT; +extern IString HEAP8; +extern IString HEAP16; +extern IString HEAP32; +extern IString HEAPF32; +extern IString HEAPU8; +extern IString HEAPU16; +extern IString HEAPU32; +extern IString HEAPF64; +extern IString F0; +extern IString EMPTY; +extern IString FUNCTION; +extern IString OPEN_PAREN; +extern IString OPEN_BRACE; +extern IString OPEN_CURLY; +extern IString CLOSE_CURLY; +extern IString COMMA; +extern IString QUESTION; +extern IString COLON; +extern IString CASE; +extern IString DEFAULT; +extern IString DOT; +extern IString PERIOD; +extern IString NEW; +extern IString ARRAY; +extern IString OBJECT; +extern IString THROW; +extern IString SET; extern IStringSet keywords; @@ -126,12 +128,7 @@ extern const char *OPERATOR_INITS, *SEPARATORS; extern int MAX_OPERATOR_SIZE, LOWEST_PREC; struct OperatorClass { - enum Type { - Binary = 0, - Prefix = 1, - Postfix = 2, - Tertiary = 3 - }; + enum Type { Binary = 0, Prefix = 1, Postfix = 2, Tertiary = 3 }; IStringSet ops; bool rtl; @@ -150,10 +147,11 @@ extern bool isIdentPart(char x); // parser -template<class NodeRef, class Builder> -class 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 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)) { @@ -162,13 +160,16 @@ class Parser { } if (curr[0] == '/' && curr[1] == '/') { curr += 2; - while (*curr && *curr != '\n') curr++; - if (*curr) curr++; + while (*curr && *curr != '\n') + curr++; + if (*curr) + curr++; continue; } if (curr[0] == '/' && curr[1] == '*') { curr += 2; - while (*curr && (curr[0] != '*' || curr[1] != '/')) curr++; + while (*curr && (curr[0] != '*' || curr[1] != '/')) + curr++; curr += 2; continue; } @@ -178,7 +179,12 @@ class Parser { 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; } + 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 { @@ -192,7 +198,9 @@ class Parser { }; struct Frag { -#ifndef _MSC_VER // MSVC does not allow unrestricted unions: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf + // 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; @@ -203,12 +211,10 @@ class Parser { int size; FragType type; - bool isNumber() const { - return type == INT || type == DOUBLE; - } + bool isNumber() const { return type == INT || type == DOUBLE; } explicit Frag(char* src) { - char *start = src; + char* start = src; if (isIdentInit(*src)) { // read an identifier or a keyword src++; @@ -227,15 +233,22 @@ class Parser { } 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. + // 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; + 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 { @@ -244,33 +257,69 @@ class Parser { // 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 + // 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; + ? 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(); + 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 = strlen(str.str); #ifndef NDEBUG @@ -289,10 +338,10 @@ class Parser { src[1] = temp; src++; } else if (*src == '"' || *src == '\'') { - char *end = strchr(src+1, *src); + char* end = strchr(src + 1, *src); *end = 0; - str.set(src+1); - src = end+1; + str.set(src + 1); + src = end + 1; type = STRING; } else { dump("frag parsing", src); @@ -304,7 +353,9 @@ class Parser { struct ExpressionElement { bool isNode; -#ifndef _MSC_VER // MSVC does not allow unrestricted unions: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf + // 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; @@ -326,13 +377,15 @@ class Parser { }; // 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 + // this works by each parseExpression call appending to the vector; then + // recursing out, and the toplevel sorts it all typedef std::vector<ExpressionElement> ExpressionParts; 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); + // 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; @@ -349,44 +402,67 @@ class Parser { 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); + 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(); + 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(); + 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); + 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; @@ -406,13 +482,15 @@ class Parser { src++; while (1) { skipSpace(src); - if (*src == ')') break; + 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 == ')') + break; if (*src == ',') { src++; continue; @@ -429,7 +507,8 @@ class Parser { NodeRef ret = Builder::makeVar(is_const); while (1) { skipSpace(src); - if (*src == ';') break; + if (*src == ';') + break; Frag name(src); assert(name.type == IDENT); NodeRef value; @@ -442,7 +521,8 @@ class Parser { } Builder::appendToVar(ret, name.str, value); skipSpace(src); - if (*src == ';') break; + if (*src == ';') + break; if (*src == ',') { src++; continue; @@ -458,7 +538,8 @@ class Parser { NodeRef value = !hasChar(seps, *src) ? parseElement(src, seps) : nullptr; skipSpace(src); assert(hasChar(seps, *src)); - if (*src == ';') src++; + if (*src == ';') + src++; return Builder::makeReturn(value); } @@ -516,14 +597,16 @@ class Parser { NodeRef parseBreak(char*& src, const char* seps) { skipSpace(src); Frag next(src); - if (next.type == IDENT) src += next.size; + 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; + if (next.type == IDENT) + src += next.size; return Builder::makeContinue(next.type == IDENT ? next.str : IString()); } @@ -535,7 +618,8 @@ class Parser { while (1) { // find all cases and possibly a default skipSpace(src); - if (*src == '}') break; + if (*src == '}') + break; Frag next(src); if (next.type == KEYWORD) { if (next.str == CASE) { @@ -575,12 +659,14 @@ class Parser { src++; continue; } - // otherwise, may be some keyword that happens to start a block (e.g. case 1: _return_ 5) + // 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); + NodeRef subBlock = explicitBlock ? parseBracketedBlock(src) + : parseBlock(src, ";}", CASE, DEFAULT); Builder::appendCodeToSwitch(ret, subBlock, explicitBlock); } skipSpace(src); @@ -595,34 +681,40 @@ class Parser { 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 == '(') + 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 + 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); + 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); + expressionPartsStack.resize(expressionPartsStack.size() + 1); assert(*src == '('); src++; NodeRef ret = Builder::makeCall(target); while (1) { skipSpace(src); - if (*src == ')') break; + if (*src == ')') + break; Builder::appendToCall(ret, parseElement(src, ",)")); skipSpace(src); - if (*src == ')') break; + if (*src == ')') + break; if (*src == ',') { src++; continue; @@ -636,7 +728,7 @@ class Parser { } NodeRef parseIndexing(NodeRef target, char*& src) { - expressionPartsStack.resize(expressionPartsStack.size()+1); + expressionPartsStack.resize(expressionPartsStack.size() + 1); assert(*src == '['); src++; NodeRef ret = Builder::makeIndexing(target, parseElement(src, "]")); @@ -658,7 +750,7 @@ class Parser { } NodeRef parseAfterParen(char*& src) { - expressionPartsStack.resize(expressionPartsStack.size()+1); + expressionPartsStack.resize(expressionPartsStack.size() + 1); skipSpace(src); NodeRef ret = parseElement(src, ")"); skipSpace(src); @@ -670,16 +762,18 @@ class Parser { } NodeRef parseAfterBrace(char*& src) { - expressionPartsStack.resize(expressionPartsStack.size()+1); + expressionPartsStack.resize(expressionPartsStack.size() + 1); NodeRef ret = Builder::makeArray(); while (1) { skipSpace(src); assert(*src); - if (*src == ']') break; + if (*src == ']') + break; NodeRef element = parseElement(src, ",]"); Builder::appendToArray(ret, element); skipSpace(src); - if (*src == ']') break; + if (*src == ']') + break; if (*src == ',') { src++; continue; @@ -691,12 +785,13 @@ class Parser { } NodeRef parseAfterCurly(char*& src) { - expressionPartsStack.resize(expressionPartsStack.size()+1); + expressionPartsStack.resize(expressionPartsStack.size() + 1); NodeRef ret = Builder::makeObject(); while (1) { skipSpace(src); assert(*src); - if (*src == '}') break; + if (*src == '}') + break; Frag key(src); assert(key.type == IDENT || key.type == STRING); src += key.size; @@ -706,7 +801,8 @@ class Parser { NodeRef value = parseElement(src, ",}"); Builder::appendToObject(ret, key.str, value); skipSpace(src); - if (*src == '}') break; + if (*src == '}') + break; if (*src == ',') { src++; continue; @@ -735,12 +831,13 @@ class Parser { if (op == PERIOD) { return Builder::makeDot(left, right); } else { - return Builder::makeBinary(left, op ,right); + return Builder::makeBinary(left, op, right); } } - NodeRef parseExpression(ExpressionElement initial, char*&src, const char* seps) { - //dump("parseExpression", src); + NodeRef + parseExpression(ExpressionElement initial, char*& src, const char* seps) { + // dump("parseExpression", src); ExpressionParts& parts = expressionPartsStack.back(); skipSpace(src); if (*src == 0 || hasChar(seps, *src)) { @@ -771,55 +868,77 @@ class Parser { parts.push_back(initial); } NodeRef last = parseElement(src, seps); - if (!top) return last; + if (!top) + return last; { - ExpressionParts& parts = expressionPartsStack.back(); // |parts| may have been invalidated by that call + // |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); + // 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; + 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()); + 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) continue; // cannot apply prefix operator if it would join two nodes - parts[i] = Builder::makePrefix(op, parts[i+1].getNode()); + } 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()); + // 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); - i = parts.size(); // basically a reset, due to things like x ? y ? 1 : 0 : 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; + 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()); + 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) continue; // cannot apply prefix operator if it would join two nodes - parts[i] = Builder::makePrefix(op, parts[i+1].getNode()); + } 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); - i = std::max(i-2, 0); // allow a previous prefix operator to cascade + // allow a previous prefix operator to cascade + i = std::max(i - 2, 0); } // TODO: tertiary, postfix } } @@ -831,25 +950,33 @@ class Parser { } } - // 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()) { + // 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); + // dump("parseBlock", src); while (1) { skipSpace(src); - if (*src == 0) break; + if (*src == 0) + break; if (*src == ';') { src++; // skip a statement in this block continue; } - if (hasChar(seps, *src)) break; + if (hasChar(seps, *src)) + break; if (!!keywordSep1) { Frag next(src); - if (next.type == KEYWORD && next.str == keywordSep1) break; + if (next.type == KEYWORD && next.str == keywordSep1) + break; } if (!!keywordSep2) { Frag next(src); - if (next.type == KEYWORD && next.str == keywordSep2) break; + if (next.type == KEYWORD && next.str == keywordSep2) + break; } NodeRef element = parseElementOrStatement(src, seps); Builder::appendToBlock(block, element); @@ -861,25 +988,29 @@ class Parser { skipSpace(src); assert(*src == '{'); src++; - NodeRef block = parseBlock(src, ";}"); // the two are not symmetrical, ; is just internally separating, } is the final one - parseBlock knows all this + // 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) { + NodeRef parseElementOrStatement(char*& src, const char* seps) { skipSpace(src); if (*src == ';') { src++; - return Builder::makeBlock(); // we don't need the brackets here, but oh well + // 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; + char* before = src; src++; skipSpace(src); if (*src == '}') { src++; - return Builder::makeBlock(); // we don't need the brackets here, but oh well + // we don't need the brackets here, but oh well + return Builder::makeBlock(); } src = before; } @@ -892,9 +1023,10 @@ class Parser { return ret; } - NodeRef parseMaybeBracketed(char*& src, const char *seps) { + NodeRef parseMaybeBracketed(char*& src, const char* seps) { skipSpace(src); - return *src == '{' ? parseBracketedBlock(src) : parseElementOrStatement(src, seps); + return *src == '{' ? parseBracketedBlock(src) + : parseElementOrStatement(src, seps); } NodeRef parseParenned(char*& src) { @@ -910,13 +1042,15 @@ class Parser { // Debugging - char *allSource = nullptr; + char* allSource = nullptr; int allSize = 0; - static void dump(const char *where, char* curr) { + 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] : '?'); + 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"); @@ -927,20 +1061,19 @@ class Parser { while (*curr) { if (*curr == '\n') { newlinesLeft--; - if (newlinesLeft == 0) break; + if (newlinesLeft == 0) + break; } charsLeft--; - if (charsLeft == 0) break; + if (charsLeft == 0) + break; fprintf(stderr, "%c", *curr++); } fprintf(stderr, "\n\n"); } public: - - Parser() { - expressionPartsStack.resize(1); - } + Parser() { expressionPartsStack.resize(1); } // Highest-level parsing, as of a JavaScript script file. NodeRef parseToplevel(char* src) { diff --git a/src/emscripten-optimizer/simple_ast.cpp b/src/emscripten-optimizer/simple_ast.cpp index 7575cc6f7..5853b3289 100644 --- a/src/emscripten-optimizer/simple_ast.cpp +++ b/src/emscripten-optimizer/simple_ast.cpp @@ -20,37 +20,29 @@ namespace cashew { // Ref methods -Ref& Ref::operator[](unsigned x) { - return (*get())[x]; -} +Ref& Ref::operator[](unsigned x) { return (*get())[x]; } -Ref& Ref::operator[](IString x) { - return (*get())[x]; -} +Ref& Ref::operator[](IString x) { return (*get())[x]; } -bool Ref::operator==(const char *str) { +bool Ref::operator==(const char* str) { return get()->isString() && !strcmp(get()->str.str, str); } -bool Ref::operator!=(const char *str) { +bool Ref::operator!=(const char* str) { return get()->isString() ? !!strcmp(get()->str.str, str) : true; } -bool Ref::operator==(const IString &str) { +bool Ref::operator==(const IString& str) { return get()->isString() && get()->str == str; } -bool Ref::operator!=(const IString &str) { +bool Ref::operator!=(const IString& str) { return get()->isString() && get()->str != str; } -bool Ref::operator==(Ref other) { - return **this == *other; -} +bool Ref::operator==(Ref other) { return **this == *other; } -bool Ref::operator!() { - return !get() || get()->isNull(); -} +bool Ref::operator!() { return !get() || get()->isNull(); } // Arena @@ -80,9 +72,13 @@ AssignName* Value::asAssignName() { return static_cast<AssignName*>(this); } -void Value::stringify(std::ostream &os, bool pretty) { +void Value::stringify(std::ostream& os, bool pretty) { static int indent = 0; - #define indentify() { for (int i_ = 0; i_ < indent; i_++) os << " "; } +#define indentify() \ + { \ + for (int i_ = 0; i_ < indent; i_++) \ + os << " "; \ + } switch (type) { case String: { if (str.str) { @@ -93,7 +89,8 @@ void Value::stringify(std::ostream &os, bool pretty) { break; } case Number: { - os << std::setprecision(17) << num; // doubles can have 17 digits of precision + // doubles can have 17 digits of precision + os << std::setprecision(17) << num; break; } case Array: { @@ -108,8 +105,10 @@ void Value::stringify(std::ostream &os, bool pretty) { } for (size_t i = 0; i < arr->size(); i++) { if (i > 0) { - if (pretty) os << "," << std::endl; - else os << ", "; + if (pretty) + os << "," << std::endl; + else + os << ", "; } indentify(); (*arr)[i]->stringify(os, pretty); @@ -142,7 +141,8 @@ void Value::stringify(std::ostream &os, bool pretty) { first = false; } else { os << ", "; - if (pretty) os << std::endl; + if (pretty) + os << std::endl; } indentify(); os << '"' << i.first.c_str() << "\": "; @@ -176,10 +176,12 @@ void Value::stringify(std::ostream &os, bool pretty) { // dump -void dump(const char *str, Ref node, bool pretty) { +void dump(const char* str, Ref node, bool pretty) { std::cerr << str << ": "; - if (!!node) node->stringify(std::cerr, pretty); - else std::cerr << "(nullptr)"; + if (!!node) + node->stringify(std::cerr, pretty); + else + std::cerr << "(nullptr)"; std::cerr << std::endl; } diff --git a/src/emscripten-optimizer/simple_ast.h b/src/emscripten-optimizer/simple_ast.h index 81d20e612..e4f2c1f86 100644 --- a/src/emscripten-optimizer/simple_ast.h +++ b/src/emscripten-optimizer/simple_ast.h @@ -33,10 +33,10 @@ #include <unordered_set> #include <vector> +#include "mixed_arena.h" #include "parser.h" #include "snprintf.h" #include "support/safe_integer.h" -#include "mixed_arena.h" #define err(str) fprintf(stderr, str "\n"); #define errv(str, ...) fprintf(stderr, str "\n", __VA_ARGS__); @@ -47,13 +47,13 @@ namespace cashew { struct Value; struct Ref; -void dump(const char *str, Ref node, bool pretty=false); +void dump(const char* str, Ref node, bool pretty = false); // Reference to a value, plus some operators for convenience struct Ref { Value* inst; - Ref(Value *v=nullptr) : inst(v) {} + Ref(Value* v = nullptr) : inst(v) {} Value* get() { return inst; } @@ -63,11 +63,16 @@ struct Ref { Ref& operator[](IString x); // special conveniences - bool operator==(const char *str); // comparison to string, which is by value - bool operator!=(const char *str); - bool operator==(const IString &str); - bool operator!=(const IString &str); - bool operator==(double d) { abort(); return false; } // prevent Ref == number, which is potentially ambiguous; use ->getNumber() == number + bool operator==(const char* str); // comparison to string, which is by value + bool operator!=(const char* str); + bool operator==(const IString& str); + bool operator!=(const IString& str); + // prevent Ref == number, which is potentially ambiguous; use ->getNumber() == + // number + bool operator==(double d) { + abort(); + return false; + } bool operator==(Ref other); bool operator!(); // check if null, in effect }; @@ -78,8 +83,7 @@ struct Ref { // receive an allocator, they all use the global one anyhow class GlobalMixedArena : public MixedArena { public: - template<class T> - T* alloc() { + template<class T> T* alloc() { auto* ret = static_cast<T*>(allocSpace(sizeof(T), alignof(T))); new (ret) T(); return ret; @@ -92,7 +96,8 @@ class ArrayStorage : public ArenaVectorBase<ArrayStorage, Ref> { public: void allocate(size_t size) { allocatedElements = size; - data = static_cast<Ref*>(arena.allocSpace(sizeof(Ref) * allocatedElements, alignof(Ref))); + data = static_cast<Ref*>( + arena.allocSpace(sizeof(Ref) * allocatedElements, alignof(Ref))); } }; @@ -116,7 +121,9 @@ struct Value { typedef std::unordered_map<IString, Ref> ObjectStorage; -#ifdef _MSC_VER // MSVC does not allow unrestricted unions: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf + // MSVC does not allow unrestricted unions: + // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf +#ifdef _MSC_VER IString str; #endif union { // TODO: optimize @@ -124,44 +131,41 @@ struct Value { IString str; #endif double num; - ArrayStorage *arr; + ArrayStorage* arr; bool boo; - ObjectStorage *obj; + ObjectStorage* obj; Ref ref; }; // constructors all copy their input Value() {} - explicit Value(const char *s) { - setString(s); - } - explicit Value(double n) { - setNumber(n); - } - explicit Value(ArrayStorage &a) { + explicit Value(const char* s) { setString(s); } + explicit Value(double n) { setNumber(n); } + explicit Value(ArrayStorage& a) { setArray(); *arr = a; } - // no bool constructor - would endanger the double one (int might convert the wrong way) + // no bool constructor - would endanger the double one (int might convert the + // wrong way) - ~Value() { - free(); - } + ~Value() { free(); } void free() { - if (type == Array) { arr->clear(); } - else if (type == Object) delete obj; + if (type == Array) { + arr->clear(); + } else if (type == Object) + delete obj; type = Null; num = 0; } - Value& setString(const char *s) { + Value& setString(const char* s) { free(); type = String; str.set(s); return *this; } - Value& setString(const IString &s) { + Value& setString(const IString& s) { free(); type = String; str.set(s); @@ -173,14 +177,14 @@ struct Value { num = n; return *this; } - Value& setArray(ArrayStorage &a) { + Value& setArray(ArrayStorage& a) { free(); type = Array; arr = arena.alloc<ArrayStorage>(); *arr = a; return *this; } - Value& setArray(size_t size_hint=0) { + Value& setArray(size_t size_hint = 0) { free(); type = Array; arr = arena.alloc<ArrayStorage>(); @@ -192,7 +196,8 @@ struct Value { type = Null; return *this; } - Value& setBool(bool b) { // Bool in the name, as otherwise might overload over int + // Bool in the name, as otherwise might overload over int + Value& setBool(bool b) { free(); type = Bool; boo = b; @@ -209,22 +214,21 @@ struct Value { bool isString() { return type == String; } bool isNumber() { return type == Number; } - bool isArray() { return type == Array; } - bool isNull() { return type == Null; } - bool isBool() { return type == Bool; } + bool isArray() { return type == Array; } + bool isNull() { return type == Null; } + bool isBool() { return type == Bool; } bool isObject() { return type == Object; } bool isAssign() { return type == Assign_; } bool isAssignName() { return type == AssignName_; } - bool isBool(bool b) { return type == Bool && b == boo; } // avoid overloading == as it might overload over int + // avoid overloading == as it might overload over int + bool isBool(bool b) { return type == Bool && b == boo; } // convenience function to check if something is an array and // also has a certain string as the first element. This is a // very common operation as the first element defines the node // type for most ast nodes - bool isArray(IString name) { - return isArray() && (*this)[0] == name; - } + bool isArray(IString name) { return isArray() && (*this)[0] == name; } const char* getCString() { assert(isString()); @@ -282,7 +286,8 @@ struct Value { } bool operator==(const Value& other) { - if (type != other.type) return false; + if (type != other.type) + return false; switch (other.type) { case String: return str == other.str; @@ -303,17 +308,22 @@ struct Value { } char* parse(char* curr) { - #define is_json_space(x) (x == 32 || x == 9 || x == 10 || x == 13) /* space, tab, linefeed/newline, or return */ - #define skip() { while (*curr && is_json_space(*curr)) curr++; } + /* space, tab, linefeed/newline, or return */ +#define is_json_space(x) (x == 32 || x == 9 || x == 10 || x == 13) +#define skip() \ + { \ + while (*curr && is_json_space(*curr)) \ + curr++; \ + } skip(); if (*curr == '"') { // String curr++; - char *close = strchr(curr, '"'); + char* close = strchr(curr, '"'); assert(close); *close = 0; // end this string, and reuse it straight from the input setString(curr); - curr = close+1; + curr = close + 1; } else if (*curr == '[') { // Array curr++; @@ -324,7 +334,8 @@ struct Value { arr->push_back(temp); curr = temp->parse(curr); skip(); - if (*curr == ']') break; + if (*curr == ']') + break; assert(*curr == ','); curr++; skip(); @@ -353,11 +364,11 @@ struct Value { while (*curr != '}') { assert(*curr == '"'); curr++; - char *close = strchr(curr, '"'); + char* close = strchr(curr, '"'); assert(close); *close = 0; // end this string, and reuse it straight from the input IString key(curr); - curr = close+1; + curr = close + 1; skip(); assert(*curr == ':'); curr++; @@ -366,7 +377,8 @@ struct Value { curr = value->parse(curr); (*obj)[key] = value; skip(); - if (*curr == '}') break; + if (*curr == '}') + break; assert(*curr == ','); curr++; skip(); @@ -374,14 +386,14 @@ struct Value { curr++; } else { // Number - char *after; + char* after; setNumber(strtod(curr, &after)); curr = after; } return curr; } - void stringify(std::ostream &os, bool pretty=false); + void stringify(std::ostream& os, bool pretty = false); // String operations @@ -394,14 +406,13 @@ struct Value { return arr->size(); } - bool empty() { - return size() == 0; - } + bool empty() { return size() == 0; } void setSize(size_t size) { assert(isArray()); auto old = arr->size(); - if (old != size) arr->resize(size); + if (old != size) + arr->resize(size); if (old < size) { for (auto i = old; i < size; i++) { (*arr)[i] = arena.alloc<Value>(); @@ -428,7 +439,8 @@ struct Value { Ref back() { assert(isArray()); - if (arr->size() == 0) return nullptr; + if (arr->size() == 0) + return nullptr; return arr->back(); } @@ -440,12 +452,13 @@ struct Value { int indexOf(Ref other) { assert(isArray()); for (size_t i = 0; i < arr->size(); i++) { - if (other == (*arr)[i]) return i; + if (other == (*arr)[i]) + return i; } return -1; } - Ref map(std::function<Ref (Ref node)> func) { + Ref map(std::function<Ref(Ref node)> func) { assert(isArray()); Ref ret = arena.alloc<Value>(); ret->setArray(); @@ -455,13 +468,14 @@ struct Value { return ret; } - Ref filter(std::function<bool (Ref node)> func) { + Ref filter(std::function<bool(Ref node)> func) { assert(isArray()); Ref ret = arena.alloc<Value>(); ret->setArray(); for (size_t i = 0; i < arr->size(); i++) { Ref curr = (*arr)[i]; - if (func(curr)) ret->push_back(curr); + if (func(curr)) + ret->push_back(curr); } return ret; } @@ -502,12 +516,8 @@ struct Assign : public Value { Assign() : Assign(nullptr, nullptr) {} - Ref& target() { - return ref; - } - Ref& value() { - return value_; - } + Ref& target() { return ref; } + Ref& value() { return value_; } }; struct AssignName : public Value { @@ -521,12 +531,8 @@ struct AssignName : public Value { AssignName() : AssignName(IString(), nullptr) {} - IString& target() { - return target_; - } - Ref& value() { - return ref; - } + IString& target() { return target_; } + Ref& value() { return ref; } }; // JS printing support @@ -534,7 +540,7 @@ struct AssignName : public Value { struct JSPrinter { bool pretty, finalize; - char *buffer = nullptr; + char* buffer = nullptr; size_t size = 0; size_t used = 0; @@ -543,11 +549,10 @@ struct JSPrinter { Ref ast; - JSPrinter(bool pretty_, bool finalize_, Ref ast_) : pretty(pretty_), finalize(finalize_), ast(ast_) {} + JSPrinter(bool pretty_, bool finalize_, Ref ast_) + : pretty(pretty_), finalize(finalize_), ast(ast_) {} - ~JSPrinter() { - free(buffer); - } + ~JSPrinter() { free(buffer); } void printAst() { print(ast); @@ -557,7 +562,7 @@ struct JSPrinter { // Utils - void ensure(int safety=100) { + void ensure(int safety = 100) { if (size >= used + safety) { return; } @@ -569,7 +574,7 @@ struct JSPrinter { abort(); } } else { - char *buf = (char*)realloc(buffer, size); + char* buf = (char*)realloc(buffer, size); if (!buf) { free(buffer); errv("Out of memory allocating %zd bytes for output buffer!", size); @@ -581,38 +586,45 @@ struct JSPrinter { void emit(char c) { maybeSpace(c); - if (!pretty && c == '}' && buffer[used-1] == ';') used--; // optimize ;} into }, the ; is not separating anything + if (!pretty && c == '}' && buffer[used - 1] == ';') + used--; // optimize ;} into }, the ; is not separating anything ensure(1); buffer[used++] = c; } - void emit(const char *s) { + void emit(const char* s) { maybeSpace(*s); int len = strlen(s); - ensure(len+1); - strncpy(buffer + used, s, len+1); + ensure(len + 1); + strncpy(buffer + used, s, len + 1); used += len; } void newline() { - if (!pretty) return; + if (!pretty) + return; emit('\n'); - for (int i = 0; i < indent; i++) emit(' '); + for (int i = 0; i < indent; i++) + emit(' '); } void space() { - if (pretty) emit(' '); + if (pretty) + emit(' '); } void safeSpace() { - if (pretty) emit(' '); - else possibleSpace = true; + if (pretty) + emit(' '); + else + possibleSpace = true; } void maybeSpace(char s) { if (possibleSpace) { possibleSpace = false; - if (isIdentPart(s)) emit(' '); + if (isIdentPart(s)) + emit(' '); } } @@ -620,22 +632,22 @@ struct JSPrinter { return node->isArray() && node[0] == TOPLEVEL && node[1]->size() == 0; } - bool isDefun(Ref node) { - return node->isArray() && node[0] == DEFUN; - } + bool isDefun(Ref node) { return node->isArray() && node[0] == DEFUN; } bool endsInBlock(Ref node) { - if (node->isArray() && node[0] == BLOCK) return true; + if (node->isArray() && node[0] == BLOCK) + return true; // Check for a label on a block - if (node->isArray() && node[0] == LABEL && endsInBlock(node[2])) return true; + if (node->isArray() && node[0] == LABEL && endsInBlock(node[2])) + return true; // Check for an if - if (node->isArray() && node[0] == IF && endsInBlock(ifHasElse(node) ? node[3] : node[2])) return true; + if (node->isArray() && node[0] == IF && + endsInBlock(ifHasElse(node) ? node[3] : node[2])) + return true; return false; } - bool isIf(Ref node) { - return node->isArray() && node[0] == IF; - } + bool isIf(Ref node) { return node->isArray() && node[0] == IF; } void print(Ref node) { ensure(); @@ -658,82 +670,119 @@ struct JSPrinter { IString type = node[0]->getIString(); switch (type.str[0]) { case 'a': { - if (type == ARRAY) printArray(node); - else abort(); + if (type == ARRAY) + printArray(node); + else + abort(); break; } case 'b': { - if (type == BINARY) printBinary(node); - else if (type == BLOCK) printBlock(node); - else if (type == BREAK) printBreak(node); - else abort(); + if (type == BINARY) + printBinary(node); + else if (type == BLOCK) + printBlock(node); + else if (type == BREAK) + printBreak(node); + else + abort(); break; } case 'c': { - if (type == CALL) printCall(node); - else if (type == CONDITIONAL) printConditional(node); - else if (type == CONTINUE) printContinue(node); - else abort(); + if (type == CALL) + printCall(node); + else if (type == CONDITIONAL) + printConditional(node); + else if (type == CONTINUE) + printContinue(node); + else + abort(); break; } case 'd': { - if (type == DEFUN) printDefun(node); - else if (type == DO) printDo(node); - else if (type == DOT) printDot(node); - else abort(); + if (type == DEFUN) + printDefun(node); + else if (type == DO) + printDo(node); + else if (type == DOT) + printDot(node); + else + abort(); break; } case 'i': { - if (type == IF) printIf(node); - else abort(); + if (type == IF) + printIf(node); + else + abort(); break; } case 'l': { - if (type == LABEL) printLabel(node); - else abort(); + if (type == LABEL) + printLabel(node); + else + abort(); break; } case 'n': { - if (type == NEW) printNew(node); - else abort(); + if (type == NEW) + printNew(node); + else + abort(); break; } case 'o': { - if (type == OBJECT) printObject(node); + if (type == OBJECT) + printObject(node); break; } case 'r': { - if (type == RETURN) printReturn(node); - else abort(); + if (type == RETURN) + printReturn(node); + else + abort(); break; } case 's': { - if (type == SUB) printSub(node); - else if (type == SEQ) printSeq(node); - else if (type == SWITCH) printSwitch(node); - else if (type == STRING) printString(node); - else abort(); + if (type == SUB) + printSub(node); + else if (type == SEQ) + printSeq(node); + else if (type == SWITCH) + printSwitch(node); + else if (type == STRING) + printString(node); + else + abort(); break; } case 't': { - if (type == TOPLEVEL) printToplevel(node); - else if (type == TRY) printTry(node); - else abort(); + if (type == TOPLEVEL) + printToplevel(node); + else if (type == TRY) + printTry(node); + else + abort(); break; } case 'u': { - if (type == UNARY_PREFIX) printUnaryPrefix(node); - else abort(); + if (type == UNARY_PREFIX) + printUnaryPrefix(node); + else + abort(); break; } case 'v': { - if (type == VAR) printVar(node); - else abort(); + if (type == VAR) + printVar(node); + else + abort(); break; } case 'w': { - if (type == WHILE) printWhile(node); - else abort(); + if (type == WHILE) + printWhile(node); + else + abort(); break; } default: { @@ -744,10 +793,11 @@ struct JSPrinter { } // print a node, and if nothing is emitted, emit something instead - void print(Ref node, const char *otherwise) { + void print(Ref node, const char* otherwise) { auto last = used; print(node); - if (used == last) emit(otherwise); + if (used == last) + emit(otherwise); } void printStats(Ref stats) { @@ -755,8 +805,10 @@ struct JSPrinter { for (size_t i = 0; i < stats->size(); i++) { Ref curr = stats[i]; if (!isNothing(curr)) { - if (first) first = false; - else newline(); + if (first) + first = false; + else + newline(); print(curr); if (!isDefun(curr) && !endsInBlock(curr) && !isIf(curr)) { emit(';'); @@ -791,7 +843,8 @@ struct JSPrinter { emit('('); Ref args = node[2]; for (size_t i = 0; i < args->size(); i++) { - if (i > 0) (pretty ? emit(", ") : emit(',')); + if (i > 0) + (pretty ? emit(", ") : emit(',')); emit(args[i]->getCString()); } emit(')'); @@ -820,7 +873,7 @@ struct JSPrinter { } void printAssignName(Ref node) { - auto *assign = node->asAssignName(); + auto* assign = node->asAssignName(); emit(assign->target().c_str()); space(); emit('='); @@ -828,11 +881,9 @@ struct JSPrinter { printChild(assign->value(), node, 1); } - void printName(Ref node) { - emit(node->getCString()); - } + void printName(Ref node) { emit(node->getCString()); } - static char* numToString(double d, bool finalize=true) { + static char* numToString(double d, bool finalize = true) { // If this number is NaN or infinite then things are a bit tricky. In JS we // want to eventually use `NaN` and/or `Infinity`, but neither of those // identifiers are valid in asm.js. Instead we have to explicitly import @@ -843,28 +894,32 @@ struct JSPrinter { // asm.js code isn't generated any more if (std::isnan(d)) { if (std::signbit(d)) { - return (char*) "-nan"; + return (char*)"-nan"; } else { - return (char*) "nan"; + return (char*)"nan"; } } else if (!std::isfinite(d)) { if (std::signbit(d)) { - return (char*) "-infinity"; + return (char*)"-infinity"; } else { - return (char*) "infinity"; + return (char*)"infinity"; } } bool neg = d < 0; - if (neg) d = -d; + if (neg) + d = -d; // try to emit the fewest necessary characters bool integer = fmod(d, 1) == 0; - #define BUFFERSIZE 1000 - static char full_storage_f[BUFFERSIZE], full_storage_e[BUFFERSIZE]; // f is normal, e is scientific for float, x for integer - static char *storage_f = full_storage_f + 1, *storage_e = full_storage_e + 1; // full has one more char, for a possible '-' +#define BUFFERSIZE 1000 + // f is normal, e is scientific for float, x for integer + static char full_storage_f[BUFFERSIZE], full_storage_e[BUFFERSIZE]; + // full has one more char, for a possible '-' + static char *storage_f = full_storage_f + 1, + *storage_e = full_storage_e + 1; auto err_f = std::numeric_limits<double>::quiet_NaN(); auto err_e = std::numeric_limits<double>::quiet_NaN(); for (int e = 0; e <= 1; e++) { - char *buffer = e ? storage_e : storage_f; + char* buffer = e ? storage_e : storage_f; double temp; if (!integer) { static char format[6]; @@ -881,10 +936,12 @@ struct JSPrinter { format[4] = e ? 'e' : 'f'; format[5] = 0; } - snprintf(buffer, BUFFERSIZE-1, format, d); + snprintf(buffer, BUFFERSIZE - 1, format, d); sscanf(buffer, "%lf", &temp); - //errv("%.18f, %.18e => %s => %.18f, %.18e (%d), ", d, d, buffer, temp, temp, temp == d); - if (temp == d) break; + // errv("%.18f, %.18e => %s => %.18f, %.18e (%d), ", d, d, + // buffer, temp, temp, temp == d); + if (temp == d) + break; } } else { // integer @@ -892,7 +949,7 @@ struct JSPrinter { if (wasm::isUInteger64(d)) { unsigned long long uu = wasm::toUInteger64(d); bool asHex = e && !finalize; - snprintf(buffer, BUFFERSIZE-1, asHex ? "0x%llx" : "%llu", uu); + snprintf(buffer, BUFFERSIZE - 1, asHex ? "0x%llx" : "%llu", uu); if (asHex) { unsigned long long tempULL; sscanf(buffer, "%llx", &tempULL); @@ -902,43 +959,48 @@ struct JSPrinter { } } else { // too large for a machine integer, just use floats - snprintf(buffer, BUFFERSIZE-1, e ? "%e" : "%.0f", d); // even on integers, e with a dot is useful, e.g. 1.2e+200 + // even on integers, e with a dot is useful, e.g. 1.2e+200 + snprintf(buffer, BUFFERSIZE - 1, e ? "%e" : "%.0f", d); sscanf(buffer, "%lf", &temp); } - //errv("%.18f, %.18e => %s => %.18f, %.18e, %llu (%d)\n", d, d, buffer, temp, temp, uu, temp == d); + // errv("%.18f, %.18e => %s => %.18f, %.18e, %llu (%d)\n", d, + // d, buffer, temp, temp, uu, temp == d); } (e ? err_e : err_f) = fabs(temp - d); - //errv("current attempt: %.18f => %s", d, buffer); - //assert(temp == d); - char *dot = strchr(buffer, '.'); + // errv("current attempt: %.18f => %s", d, buffer); + // assert(temp == d); + char* dot = strchr(buffer, '.'); if (dot) { // remove trailing zeros - char *end = dot+1; - while (*end >= '0' && *end <= '9') end++; + char* end = dot + 1; + while (*end >= '0' && *end <= '9') + end++; end--; while (*end == '0') { - char *copy = end; + char* copy = end; do { copy[0] = copy[1]; } while (*copy++ != 0); end--; } - //errv("%.18f => %s", d, buffer); + // errv("%.18f => %s", d, buffer); // remove preceding zeros while (*buffer == '0') { - char *copy = buffer; + char* copy = buffer; do { copy[0] = copy[1]; } while (*copy++ != 0); } - //errv("%.18f ===> %s", d, buffer); + // errv("%.18f ===> %s", d, buffer); } else if (!integer || !e) { // no dot. try to change 12345000 => 12345e3 - char *end = strchr(buffer, 0); + char* end = strchr(buffer, 0); end--; - char *test = end; - // remove zeros, and also doubles can use at most 24 digits, we can truncate any extras even if not zero - while ((*test == '0' || test - buffer > 24) && test > buffer) test--; + char* test = end; + // remove zeros, and also doubles can use at most 24 digits, we can + // truncate any extras even if not zero + while ((*test == '0' || test - buffer > 24) && test > buffer) + test--; int num = end - test; if (num >= 3) { test++; @@ -959,10 +1021,11 @@ struct JSPrinter { } } } - //errv("..current attempt: %.18f => %s", d, buffer); + // errv("..current attempt: %.18f => %s", d, buffer); } - //fprintf(stderr, "options:\n%s\n%s\n (first? %d)\n", storage_e, storage_f, strlen(storage_e) < strlen(storage_f)); - char *ret; + // fprintf(stderr, "options:\n%s\n%s\n (first? %d)\n", storage_e, storage_f, + // strlen(storage_e) < strlen(storage_f)); + char* ret; if (err_e == err_f) { ret = strlen(storage_e) < strlen(storage_f) ? storage_e : storage_f; } else { @@ -976,7 +1039,7 @@ struct JSPrinter { } void printNum(Ref node) { - if (node->getNumber() < 0 && buffer[used-1] == '-') { + if (node->getNumber() < 0 && buffer[used - 1] == '-') { emit(' '); // cannot join - and - to --, looks like the -- operator } emit(numToString(node->getNumber(), finalize)); @@ -1005,28 +1068,37 @@ struct JSPrinter { } Ref type = node[0]; if (type == BINARY || type == UNARY_PREFIX) { - return OperatorClass::getPrecedence(type == BINARY ? OperatorClass::Binary : OperatorClass::Prefix, node[1]->getIString()); + return OperatorClass::getPrecedence( + type == BINARY ? OperatorClass::Binary : OperatorClass::Prefix, + node[1]->getIString()); } else if (type == SEQ) { return OperatorClass::getPrecedence(OperatorClass::Binary, COMMA); } else if (type == CALL) { - return parent ? OperatorClass::getPrecedence(OperatorClass::Binary, COMMA) : -1; // call arguments are split by commas, but call itself is safe + // call arguments are split by commas, but call itself is safe + return parent ? OperatorClass::getPrecedence(OperatorClass::Binary, COMMA) + : -1; } else if (type == CONDITIONAL) { return OperatorClass::getPrecedence(OperatorClass::Tertiary, QUESTION); } - // otherwise, this is something that fixes precedence explicitly, and we can ignore + // otherwise, this is something that fixes precedence explicitly, and we can + // ignore return -1; // XXX } // check whether we need parens for the child, when rendered in the parent - // @param childPosition -1 means it is printed to the left of parent, 0 means "anywhere", 1 means right + // @param childPosition -1 means it is printed to the left of parent, 0 means + // "anywhere", 1 means right bool needParens(Ref parent, Ref child, int childPosition) { int parentPrecedence = getPrecedence(parent, true); int childPrecedence = getPrecedence(child, false); - if (childPrecedence > parentPrecedence) return true; // child is definitely a danger - if (childPrecedence < parentPrecedence) return false; // definitely cool + if (childPrecedence > parentPrecedence) + return true; // child is definitely a danger + if (childPrecedence < parentPrecedence) + return false; // definitely cool // equal precedence, so associativity (rtl/ltr) is what matters - // (except for some exceptions, where multiple operators can combine into confusion) + // (except for some exceptions, where multiple operators can combine into + // confusion) if (parent->isArray() && parent[0] == UNARY_PREFIX) { assert(child[0] == UNARY_PREFIX); if ((parent[1] == PLUS || parent[1] == MINUS) && child[1] == parent[1]) { @@ -1034,18 +1106,24 @@ struct JSPrinter { return true; } } - if (childPosition == 0) return true; // child could be anywhere, so always paren - if (childPrecedence < 0) return false; // both precedences are safe + if (childPosition == 0) + return true; // child could be anywhere, so always paren + if (childPrecedence < 0) + return false; // both precedences are safe // check if child is on the dangerous side - if (OperatorClass::getRtl(parentPrecedence)) return childPosition < 0; - else return childPosition > 0; + if (OperatorClass::getRtl(parentPrecedence)) + return childPosition < 0; + else + return childPosition > 0; } - void printChild(Ref child, Ref parent, int childPosition=0) { + void printChild(Ref child, Ref parent, int childPosition = 0) { bool parens = needParens(parent, child, childPosition); - if (parens) emit('('); + if (parens) + emit('('); print(child); - if (parens) emit(')'); + if (parens) + emit(')'); } void printBinary(Ref node) { @@ -1064,20 +1142,23 @@ struct JSPrinter { // emit a finalized number int last = used; print(node[2]); - ensure(1); // we temporarily append a 0 - char *curr = buffer + last; // ensure might invalidate + ensure(1); // we temporarily append a 0 + char* curr = buffer + last; // ensure might invalidate buffer[used] = 0; - if (strstr(curr, "infinity")) return; - if (strstr(curr, "nan")) return; - if (strchr(curr, '.')) return; // already a decimal point, all good - char *e = strchr(curr, 'e'); + if (strstr(curr, "infinity")) + return; + if (strstr(curr, "nan")) + return; + if (strchr(curr, '.')) + return; // already a decimal point, all good + char* e = strchr(curr, 'e'); if (!e) { emit(".0"); return; } ensure(3); curr = buffer + last; // ensure might invalidate - char *end = strchr(curr, 0); + char* end = strchr(curr, 0); while (end >= e) { end[2] = end[0]; end--; @@ -1087,8 +1168,8 @@ struct JSPrinter { used += 2; return; } - if ((buffer[used-1] == '-' && node[1] == MINUS) || - (buffer[used-1] == '+' && node[1] == PLUS)) { + if ((buffer[used - 1] == '-' && node[1] == MINUS) || + (buffer[used - 1] == '+' && node[1] == PLUS)) { emit(' '); // cannot join - and - to --, looks like the -- operator } emit(node[1]->getCString()); @@ -1112,7 +1193,8 @@ struct JSPrinter { emit('('); Ref args = node[2]; for (size_t i = 0; i < args->size(); i++) { - if (i > 0) (pretty ? emit(", ") : emit(',')); + if (i > 0) + (pretty ? emit(", ") : emit(',')); printChild(args[i], node, 0); } emit(')'); @@ -1156,8 +1238,10 @@ struct JSPrinter { auto curr = used; printStats(c[1]); indent--; - if (curr != used) newline(); - else used--; // avoid the extra indentation we added tentatively + if (curr != used) + newline(); + else + used--; // avoid the extra indentation we added tentatively } else { newline(); } @@ -1185,7 +1269,8 @@ struct JSPrinter { emit("var "); Ref args = node[1]; for (size_t i = 0; i < args->size(); i++) { - if (i > 0) (pretty ? emit(", ") : emit(',')); + if (i > 0) + (pretty ? emit(", ") : emit(',')); emit(args[i][0]->getCString()); if (args[i]->size() > 1) { space(); @@ -1292,7 +1377,8 @@ struct JSPrinter { emit('['); Ref args = node[1]; for (size_t i = 0; i < args->size(); i++) { - if (i > 0) (pretty ? emit(", ") : emit(',')); + if (i > 0) + (pretty ? emit(", ") : emit(',')); print(args[i]); } emit(']'); @@ -1309,7 +1395,7 @@ struct JSPrinter { newline(); } bool needQuote = false; - const char *str; + const char* str; if (args[i][0]->isArray()) { assert(args[i][0][0] == STRING); // A quoted string. @@ -1319,7 +1405,7 @@ struct JSPrinter { // Just a raw string, no quotes. str = args[i][0]->getCString(); } - const char *check = str; + const char* check = str; while (*check) { if (!isalnum(*check) && *check != '_' && *check != '$') { needQuote = true; @@ -1327,9 +1413,11 @@ struct JSPrinter { } check++; } - if (needQuote) emit('"'); + if (needQuote) + emit('"'); emit(str); - if (needQuote) emit('"'); + if (needQuote) + emit('"'); emit(":"); space(); print(args[i][1]); @@ -1340,7 +1428,6 @@ struct JSPrinter { } }; - // cashew builder class ValueBuilder { @@ -1348,40 +1435,40 @@ class ValueBuilder { return &arena.alloc<Value>()->setString(s); } - static Ref makeNull() { - return &arena.alloc<Value>()->setNull(); - } + static Ref makeNull() { return &arena.alloc<Value>()->setNull(); } public: - static Ref makeRawArray(int size_hint=0) { + static Ref makeRawArray(int size_hint = 0) { return &arena.alloc<Value>()->setArray(size_hint); } static Ref makeToplevel() { - return &makeRawArray(2)->push_back(makeRawString(TOPLEVEL)) - .push_back(makeRawArray()); + return &makeRawArray(2) + ->push_back(makeRawString(TOPLEVEL)) + .push_back(makeRawArray()); } static Ref makeString(IString str) { - return &makeRawArray(2)->push_back(makeRawString(STRING)) - .push_back(makeRawString(str)); + return &makeRawArray(2) + ->push_back(makeRawString(STRING)) + .push_back(makeRawString(str)); } static Ref makeBlock() { - return &makeRawArray(2)->push_back(makeRawString(BLOCK)) - .push_back(makeRawArray()); + return &makeRawArray(2) + ->push_back(makeRawString(BLOCK)) + .push_back(makeRawArray()); } - static Ref makeName(IString name) { - return makeRawString(name); - } + static Ref makeName(IString name) { return makeRawString(name); } static void setBlockContent(Ref target, Ref block) { if (target[0] == TOPLEVEL) { target[1]->setArray(block[1]->getArray()); } else if (target[0] == DEFUN) { target[3]->setArray(block[1]->getArray()); - } else abort(); + } else + abort(); } static void appendToBlock(Ref block, Ref element) { @@ -1390,35 +1477,38 @@ public: } static Ref makeCall(Ref target) { - return &makeRawArray(3)->push_back(makeRawString(CALL)) - .push_back(target) - .push_back(makeRawArray()); + return &makeRawArray(3) + ->push_back(makeRawString(CALL)) + .push_back(target) + .push_back(makeRawArray()); } static Ref makeCall(Ref target, Ref arg) { - Ref ret = &makeRawArray(3)->push_back(makeRawString(CALL)) - .push_back(target) - .push_back(makeRawArray()); + Ref ret = &makeRawArray(3) + ->push_back(makeRawString(CALL)) + .push_back(target) + .push_back(makeRawArray()); ret[2]->push_back(arg); return ret; } static Ref makeCall(IString target) { - Ref ret = &makeRawArray(3)->push_back(makeRawString(CALL)) - .push_back(makeName(target)) - .push_back(makeRawArray()); + Ref ret = &makeRawArray(3) + ->push_back(makeRawString(CALL)) + .push_back(makeName(target)) + .push_back(makeRawArray()); return ret; } - template<typename ...Ts> - static Ref makeCall(IString target, Ts... args) { + template<typename... Ts> static Ref makeCall(IString target, Ts... args) { size_t nArgs = sizeof...(Ts); Ref callArgs = makeRawArray(nArgs); Ref argArray[] = {args...}; for (size_t i = 0; i < nArgs; ++i) { callArgs->push_back(argArray[i]); } - return &makeRawArray(3)->push_back(makeRawString(CALL)) - .push_back(makeName(target)) - .push_back(callArgs); + return &makeRawArray(3) + ->push_back(makeRawString(CALL)) + .push_back(makeName(target)) + .push_back(callArgs); } static void appendToCall(Ref call, Ref element) { @@ -1426,59 +1516,57 @@ public: call[2]->push_back(element); } - static Ref makeStatement(Ref contents) { - return contents; - } + static Ref makeStatement(Ref contents) { return contents; } static Ref makeDouble(double num) { return &arena.alloc<Value>()->setNumber(num); } - static Ref makeInt(uint32_t num) { - return makeDouble(double(num)); - } - static Ref makeInt(int32_t num) { - return makeDouble(double(num)); - } - static Ref makeNum(double num) { - return makeDouble(num); - } + static Ref makeInt(uint32_t num) { return makeDouble(double(num)); } + static Ref makeInt(int32_t num) { return makeDouble(double(num)); } + static Ref makeNum(double num) { return makeDouble(num); } static Ref makeUnary(IString op, Ref value) { - return &makeRawArray(3)->push_back(makeRawString(UNARY_PREFIX)) - .push_back(makeRawString(op)) - .push_back(value); + return &makeRawArray(3) + ->push_back(makeRawString(UNARY_PREFIX)) + .push_back(makeRawString(op)) + .push_back(value); } static Ref makeBinary(Ref left, IString op, Ref right) { if (op == SET) { if (left->isString()) { - return &arena.alloc<AssignName>()->setAssignName(left->getIString(), right); + return &arena.alloc<AssignName>()->setAssignName(left->getIString(), + right); } else { return &arena.alloc<Assign>()->setAssign(left, right); } } else if (op == COMMA) { - return &makeRawArray(3)->push_back(makeRawString(SEQ)) - .push_back(left) - .push_back(right); + return &makeRawArray(3) + ->push_back(makeRawString(SEQ)) + .push_back(left) + .push_back(right); } else { - return &makeRawArray(4)->push_back(makeRawString(BINARY)) - .push_back(makeRawString(op)) - .push_back(left) - .push_back(right); + return &makeRawArray(4) + ->push_back(makeRawString(BINARY)) + .push_back(makeRawString(op)) + .push_back(left) + .push_back(right); } } static Ref makePrefix(IString op, Ref right) { - return &makeRawArray(3)->push_back(makeRawString(UNARY_PREFIX)) - .push_back(makeRawString(op)) - .push_back(right); + return &makeRawArray(3) + ->push_back(makeRawString(UNARY_PREFIX)) + .push_back(makeRawString(op)) + .push_back(right); } static Ref makeFunction(IString name) { - return &makeRawArray(4)->push_back(makeRawString(DEFUN)) - .push_back(makeRawString(name)) - .push_back(makeRawArray()) - .push_back(makeRawArray()); + return &makeRawArray(4) + ->push_back(makeRawString(DEFUN)) + .push_back(makeRawString(name)) + .push_back(makeRawArray()) + .push_back(makeRawArray()); } static void appendArgumentToFunction(Ref func, IString arg) { @@ -1486,101 +1574,115 @@ public: func[2]->push_back(makeRawString(arg)); } - static Ref makeVar(bool is_const=false) { - return &makeRawArray(2)->push_back(makeRawString(VAR)) - .push_back(makeRawArray()); + static Ref makeVar(bool is_const = false) { + return &makeRawArray(2) + ->push_back(makeRawString(VAR)) + .push_back(makeRawArray()); } static void appendToVar(Ref var, IString name, Ref value) { assert(var[0] == VAR); Ref array = &makeRawArray(1)->push_back(makeRawString(name)); - if (!!value) array->push_back(value); + if (!!value) + array->push_back(value); var[1]->push_back(array); } static Ref makeReturn(Ref value) { - return &makeRawArray(2)->push_back(makeRawString(RETURN)) - .push_back(!!value ? value : makeNull()); + return &makeRawArray(2) + ->push_back(makeRawString(RETURN)) + .push_back(!!value ? value : makeNull()); } static Ref makeIndexing(Ref target, Ref index) { - return &makeRawArray(3)->push_back(makeRawString(SUB)) - .push_back(target) - .push_back(index); + return &makeRawArray(3) + ->push_back(makeRawString(SUB)) + .push_back(target) + .push_back(index); } static Ref makeIf(Ref condition, Ref ifTrue, Ref ifFalse) { - return &makeRawArray(4)->push_back(makeRawString(IF)) - .push_back(condition) - .push_back(ifTrue) - .push_back(!!ifFalse ? ifFalse : makeNull()); + return &makeRawArray(4) + ->push_back(makeRawString(IF)) + .push_back(condition) + .push_back(ifTrue) + .push_back(!!ifFalse ? ifFalse : makeNull()); } static Ref makeConditional(Ref condition, Ref ifTrue, Ref ifFalse) { - return &makeRawArray(4)->push_back(makeRawString(CONDITIONAL)) - .push_back(condition) - .push_back(ifTrue) - .push_back(ifFalse); + return &makeRawArray(4) + ->push_back(makeRawString(CONDITIONAL)) + .push_back(condition) + .push_back(ifTrue) + .push_back(ifFalse); } static Ref makeSeq(Ref left, Ref right) { - return &makeRawArray(3)->push_back(makeRawString(SEQ)) - .push_back(left) - .push_back(right); + return &makeRawArray(3) + ->push_back(makeRawString(SEQ)) + .push_back(left) + .push_back(right); } static Ref makeDo(Ref body, Ref condition) { - return &makeRawArray(3)->push_back(makeRawString(DO)) - .push_back(condition) - .push_back(body); + return &makeRawArray(3) + ->push_back(makeRawString(DO)) + .push_back(condition) + .push_back(body); } static Ref makeWhile(Ref condition, Ref body) { - return &makeRawArray(3)->push_back(makeRawString(WHILE)) - .push_back(condition) - .push_back(body); + return &makeRawArray(3) + ->push_back(makeRawString(WHILE)) + .push_back(condition) + .push_back(body); } static Ref makeFor(Ref init, Ref condition, Ref inc, Ref body) { - return &makeRawArray(5)->push_back(makeRawString(FOR)) - .push_back(init) - .push_back(condition) - .push_back(inc) - .push_back(body); + return &makeRawArray(5) + ->push_back(makeRawString(FOR)) + .push_back(init) + .push_back(condition) + .push_back(inc) + .push_back(body); } static Ref makeBreak(IString label) { - return &makeRawArray(2)->push_back(makeRawString(BREAK)) - .push_back(!!label ? makeRawString(label) : makeNull()); + return &makeRawArray(2) + ->push_back(makeRawString(BREAK)) + .push_back(!!label ? makeRawString(label) : makeNull()); } static Ref makeContinue(IString label) { - return &makeRawArray(2)->push_back(makeRawString(CONTINUE)) - .push_back(!!label ? makeRawString(label) : makeNull()); + return &makeRawArray(2) + ->push_back(makeRawString(CONTINUE)) + .push_back(!!label ? makeRawString(label) : makeNull()); } static Ref makeLabel(IString name, Ref body) { - return &makeRawArray(3)->push_back(makeRawString(LABEL)) - .push_back(makeRawString(name)) - .push_back(body); + return &makeRawArray(3) + ->push_back(makeRawString(LABEL)) + .push_back(makeRawString(name)) + .push_back(body); } static Ref makeSwitch(Ref input) { - return &makeRawArray(3)->push_back(makeRawString(SWITCH)) - .push_back(input) - .push_back(makeRawArray()); + return &makeRawArray(3) + ->push_back(makeRawString(SWITCH)) + .push_back(input) + .push_back(makeRawArray()); } static void appendCaseToSwitch(Ref switch_, Ref arg) { assert(switch_[0] == SWITCH); - switch_[2]->push_back(&makeRawArray(2)->push_back(arg) - .push_back(makeRawArray())); + switch_[2]->push_back( + &makeRawArray(2)->push_back(arg).push_back(makeRawArray())); } static void appendDefaultToSwitch(Ref switch_) { assert(switch_[0] == SWITCH); - switch_[2]->push_back(&makeRawArray(2)->push_back(makeNull()) - .push_back(makeRawArray())); + switch_[2]->push_back( + &makeRawArray(2)->push_back(makeNull()).push_back(makeRawArray())); } static void appendCodeToSwitch(Ref switch_, Ref code, bool explicitBlock) { @@ -1598,20 +1700,21 @@ public: static Ref makeTry(Ref try_, Ref arg, Ref catch_) { assert(try_[0] == BLOCK); assert(catch_[0] == BLOCK); - return &makeRawArray(3)->push_back(makeRawString(TRY)) - .push_back(try_) - .push_back(arg) - .push_back(catch_); + return &makeRawArray(3) + ->push_back(makeRawString(TRY)) + .push_back(try_) + .push_back(arg) + .push_back(catch_); } static Ref makeDot(Ref obj, IString key) { - return &makeRawArray(3)->push_back(makeRawString(DOT)) - .push_back(obj) - .push_back(makeRawString(key)); + return &makeRawArray(3) + ->push_back(makeRawString(DOT)) + .push_back(obj) + .push_back(makeRawString(key)); } - template<typename ...Ts> - static Ref makeDot(Ref obj, Ref key, Ts... args) { + template<typename... Ts> static Ref makeDot(Ref obj, Ref key, Ts... args) { return makeDot(makeDot(obj, key), args...); } @@ -1621,13 +1724,13 @@ public: } static Ref makeNew(Ref call) { - return &makeRawArray(2)->push_back(makeRawString(NEW)) - .push_back(call); + return &makeRawArray(2)->push_back(makeRawString(NEW)).push_back(call); } static Ref makeArray() { - return &makeRawArray(2)->push_back(makeRawString(ARRAY)) - .push_back(makeRawArray()); + return &makeRawArray(2) + ->push_back(makeRawString(ARRAY)) + .push_back(makeRawArray()); } static void appendToArray(Ref array, Ref element) { @@ -1636,26 +1739,28 @@ public: } static Ref makeObject() { - return &makeRawArray(2)->push_back(makeRawString(OBJECT)) - .push_back(makeRawArray()); + return &makeRawArray(2) + ->push_back(makeRawString(OBJECT)) + .push_back(makeRawArray()); } static void appendToObject(Ref array, IString key, Ref value) { assert(array[0] == OBJECT); - array[1]->push_back(&makeRawArray(2)->push_back(makeRawString(key)) - .push_back(value)); + array[1]->push_back( + &makeRawArray(2)->push_back(makeRawString(key)).push_back(value)); } static void appendToObjectWithQuotes(Ref array, IString key, Ref value) { assert(array[0] == OBJECT); - array[1]->push_back(&makeRawArray(2)->push_back(makeString(key)) - .push_back(value)); + array[1]->push_back( + &makeRawArray(2)->push_back(makeString(key)).push_back(value)); } static Ref makeSub(Ref obj, Ref index) { - return &makeRawArray(2)->push_back(makeRawString(SUB)) - .push_back(obj) - .push_back(index); + return &makeRawArray(2) + ->push_back(makeRawString(SUB)) + .push_back(obj) + .push_back(index); } static Ref makePtrShift(Ref ptr, int shifts) { diff --git a/src/emscripten-optimizer/snprintf.h b/src/emscripten-optimizer/snprintf.h index 86335661d..22c8d8202 100644 --- a/src/emscripten-optimizer/snprintf.h +++ b/src/emscripten-optimizer/snprintf.h @@ -19,34 +19,34 @@ #include <stdarg.h> -// Visual Studio does not support C99, so emulate snprintf support for it manually. +// Visual Studio does not support C99, so emulate snprintf support for it +// manually. #ifdef _MSC_VER #define snprintf c99_snprintf -inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) -{ - int count = -1; +inline int +c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) { + int count = -1; - if (size != 0) - count = _vsnprintf_s(str, size, _TRUNCATE, format, ap); - if (count == -1) - count = _vscprintf(format, ap); + if (size != 0) + count = _vsnprintf_s(str, size, _TRUNCATE, format, ap); + if (count == -1) + count = _vscprintf(format, ap); - return count; + return count; } -inline int c99_snprintf(char* str, size_t size, const char* format, ...) -{ - int count; - va_list ap; +inline int c99_snprintf(char* str, size_t size, const char* format, ...) { + int count; + va_list ap; - va_start(ap, format); - count = c99_vsnprintf(str, size, format, ap); - va_end(ap); + va_start(ap, format); + count = c99_vsnprintf(str, size, format, ap); + va_end(ap); - return count; + return count; } #endif |