diff options
Diffstat (limited to 'src/emscripten-optimizer/simple_ast.cpp')
-rw-r--r-- | src/emscripten-optimizer/simple_ast.cpp | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/src/emscripten-optimizer/simple_ast.cpp b/src/emscripten-optimizer/simple_ast.cpp new file mode 100644 index 000000000..89b8ce8ed --- /dev/null +++ b/src/emscripten-optimizer/simple_ast.cpp @@ -0,0 +1,259 @@ + +#include "simple_ast.h" + +namespace cashew { + +// Ref methods + +Ref& Ref::operator[](unsigned x) { + return (*get())[x]; +} + +Ref& Ref::operator[](IString x) { + return (*get())[x]; +} + +bool Ref::operator==(const char *str) { + return get()->isString() && !strcmp(get()->str.str, str); +} + +bool Ref::operator!=(const char *str) { + return get()->isString() ? !!strcmp(get()->str.str, str) : true; +} + +bool Ref::operator==(const IString &str) { + return get()->isString() && get()->str == str; +} + +bool Ref::operator!=(const IString &str) { + return get()->isString() && get()->str != str; +} + +bool Ref::operator==(Ref other) { + return **this == *other; +} + +bool Ref::operator!() { + return !get() || get()->isNull(); +} + +// Arena + +Arena arena; + +Ref Arena::alloc() { + if (chunks.size() == 0 || index == CHUNK_SIZE) { + chunks.push_back(new Value[CHUNK_SIZE]); + index = 0; + } + return &chunks.back()[index++]; +} + +ArrayStorage* Arena::allocArray() { + if (arr_chunks.size() == 0 || arr_index == CHUNK_SIZE) { + arr_chunks.push_back(new ArrayStorage[CHUNK_SIZE]); + arr_index = 0; + } + return &arr_chunks.back()[arr_index++]; +} + +// dump + +void dump(const char *str, Ref node, bool pretty) { + std::cerr << str << ": "; + if (!!node) node->stringify(std::cerr, pretty); + else std::cerr << "(nullptr)"; + std::cerr << std::endl; +} + +// AST traversals + +// Traversals + +struct TraverseInfo { + TraverseInfo() {} + TraverseInfo(Ref node, ArrayStorage* arr) : node(node), arr(arr), index(0) {} + Ref node; + ArrayStorage* arr; + int index; +}; + +template <class T, int init> +struct StackedStack { // a stack, on the stack + T stackStorage[init]; + T* storage; + int used, available; // used amount, available amount + bool alloced; + + StackedStack() : used(0), available(init), alloced(false) { + storage = stackStorage; + } + ~StackedStack() { + if (alloced) free(storage); + } + + int size() { return used; } + + void push_back(const T& t) { + assert(used <= available); + if (used == available) { + available *= 2; + if (!alloced) { + T* old = storage; + storage = (T*)malloc(sizeof(T)*available); + memcpy(storage, old, sizeof(T)*used); + alloced = true; + } else { + T *newStorage = (T*)realloc(storage, sizeof(T)*available); + assert(newStorage); + storage = newStorage; + } + } + assert(used < available); + assert(storage); + storage[used++] = t; + } + + T& back() { + assert(used > 0); + return storage[used-1]; + } + + void pop_back() { + assert(used > 0); + used--; + } +}; + +#define visitable(node) (node->isArray() && node->size() > 0) + +#define TRAV_STACK 40 + +// Traverse, calling visit before the children +void traversePre(Ref node, std::function<void (Ref)> visit) { + if (!visitable(node)) return; + visit(node); + StackedStack<TraverseInfo, TRAV_STACK> stack; + int index = 0; + ArrayStorage* arr = &node->getArray(); + int arrsize = (int)arr->size(); + Ref* arrdata = arr->data(); + stack.push_back(TraverseInfo(node, arr)); + while (1) { + if (index < arrsize) { + Ref sub = *(arrdata+index); + index++; + if (visitable(sub)) { + stack.back().index = index; + index = 0; + visit(sub); + arr = &sub->getArray(); + arrsize = (int)arr->size(); + arrdata = arr->data(); + stack.push_back(TraverseInfo(sub, arr)); + } + } else { + stack.pop_back(); + if (stack.size() == 0) break; + TraverseInfo& back = stack.back(); + index = back.index; + arr = back.arr; + arrsize = (int)arr->size(); + arrdata = arr->data(); + } + } +} + +// Traverse, calling visitPre before the children and visitPost after +void traversePrePost(Ref node, std::function<void (Ref)> visitPre, std::function<void (Ref)> visitPost) { + if (!visitable(node)) return; + visitPre(node); + StackedStack<TraverseInfo, TRAV_STACK> stack; + int index = 0; + ArrayStorage* arr = &node->getArray(); + int arrsize = (int)arr->size(); + Ref* arrdata = arr->data(); + stack.push_back(TraverseInfo(node, arr)); + while (1) { + if (index < arrsize) { + Ref sub = *(arrdata+index); + index++; + if (visitable(sub)) { + stack.back().index = index; + index = 0; + visitPre(sub); + arr = &sub->getArray(); + arrsize = (int)arr->size(); + arrdata = arr->data(); + stack.push_back(TraverseInfo(sub, arr)); + } + } else { + visitPost(stack.back().node); + stack.pop_back(); + if (stack.size() == 0) break; + TraverseInfo& back = stack.back(); + index = back.index; + arr = back.arr; + arrsize = (int)arr->size(); + arrdata = arr->data(); + } + } +} + +// Traverse, calling visitPre before the children and visitPost after. If pre returns false, do not traverse children +void traversePrePostConditional(Ref node, std::function<bool (Ref)> visitPre, std::function<void (Ref)> visitPost) { + if (!visitable(node)) return; + if (!visitPre(node)) return; + StackedStack<TraverseInfo, TRAV_STACK> stack; + int index = 0; + ArrayStorage* arr = &node->getArray(); + int arrsize = (int)arr->size(); + Ref* arrdata = arr->data(); + stack.push_back(TraverseInfo(node, arr)); + while (1) { + if (index < arrsize) { + Ref sub = *(arrdata+index); + index++; + if (visitable(sub)) { + if (visitPre(sub)) { + stack.back().index = index; + index = 0; + arr = &sub->getArray(); + arrsize = (int)arr->size(); + arrdata = arr->data(); + stack.push_back(TraverseInfo(sub, arr)); + } + } + } else { + visitPost(stack.back().node); + stack.pop_back(); + if (stack.size() == 0) break; + TraverseInfo& back = stack.back(); + index = back.index; + arr = back.arr; + arrsize = (int)arr->size(); + arrdata = arr->data(); + } + } +} + +// Traverses all the top-level functions in the document +void traverseFunctions(Ref ast, std::function<void (Ref)> visit) { + if (!ast || ast->size() == 0) return; + if (ast[0] == TOPLEVEL) { + Ref stats = ast[1]; + for (size_t i = 0; i < stats->size(); i++) { + Ref curr = stats[i]; + if (curr[0] == DEFUN) visit(curr); + } + } else if (ast[0] == DEFUN) { + visit(ast); + } +} + +// ValueBuilder + +IStringSet ValueBuilder::statable("assign call binary unary-prefix if name num conditional dot new sub seq string object array"); + +} // namespace cashew + |