summaryrefslogtreecommitdiff
path: root/src/emscripten-optimizer
diff options
context:
space:
mode:
Diffstat (limited to 'src/emscripten-optimizer')
-rw-r--r--src/emscripten-optimizer/parser.cpp1
-rw-r--r--src/emscripten-optimizer/parser.h1
-rw-r--r--src/emscripten-optimizer/simple_ast.cpp102
-rw-r--r--src/emscripten-optimizer/simple_ast.h164
4 files changed, 149 insertions, 119 deletions
diff --git a/src/emscripten-optimizer/parser.cpp b/src/emscripten-optimizer/parser.cpp
index 645762f0a..e85947e22 100644
--- a/src/emscripten-optimizer/parser.cpp
+++ b/src/emscripten-optimizer/parser.cpp
@@ -24,7 +24,6 @@ IString TOPLEVEL("toplevel"),
DEFUN("defun"),
BLOCK("block"),
STAT("stat"),
- ASSIGN("assign"),
VAR("var"),
CONST("const"),
CONDITIONAL("conditional"),
diff --git a/src/emscripten-optimizer/parser.h b/src/emscripten-optimizer/parser.h
index 8b988a6c2..20e936a76 100644
--- a/src/emscripten-optimizer/parser.h
+++ b/src/emscripten-optimizer/parser.h
@@ -39,7 +39,6 @@ extern IString TOPLEVEL,
DEFUN,
BLOCK,
STAT,
- ASSIGN,
VAR,
CONST,
CONDITIONAL,
diff --git a/src/emscripten-optimizer/simple_ast.cpp b/src/emscripten-optimizer/simple_ast.cpp
index 7379e9740..f28ef9b13 100644
--- a/src/emscripten-optimizer/simple_ast.cpp
+++ b/src/emscripten-optimizer/simple_ast.cpp
@@ -56,6 +56,106 @@ bool Ref::operator!() {
GlobalMixedArena arena;
+// Value
+
+Value& Value::setAssign(Ref target, Ref value) {
+ asAssign()->target() = target;
+ asAssign()->value() = value;
+ return *this;
+}
+
+Assign* Value::asAssign() {
+ assert(isAssign());
+ return static_cast<Assign*>(this);
+}
+
+void Value::stringify(std::ostream &os, bool pretty) {
+ static int indent = 0;
+ #define indentify() { for (int i_ = 0; i_ < indent; i_++) os << " "; }
+ switch (type) {
+ case String: {
+ if (str.str) {
+ os << '"' << str.str << '"';
+ } else {
+ os << "\"(null)\"";
+ }
+ break;
+ }
+ case Number: {
+ os << std::setprecision(17) << num; // doubles can have 17 digits of precision
+ break;
+ }
+ case Array: {
+ if (arr->size() == 0) {
+ os << "[]";
+ break;
+ }
+ os << '[';
+ if (pretty) {
+ os << std::endl;
+ indent++;
+ }
+ for (size_t i = 0; i < arr->size(); i++) {
+ if (i > 0) {
+ if (pretty) os << "," << std::endl;
+ else os << ", ";
+ }
+ indentify();
+ (*arr)[i]->stringify(os, pretty);
+ }
+ if (pretty) {
+ os << std::endl;
+ indent--;
+ }
+ indentify();
+ os << ']';
+ break;
+ }
+ case Null: {
+ os << "null";
+ break;
+ }
+ case Bool: {
+ os << (boo ? "true" : "false");
+ break;
+ }
+ case Object: {
+ os << '{';
+ if (pretty) {
+ os << std::endl;
+ indent++;
+ }
+ bool first = true;
+ for (auto i : *obj) {
+ if (first) {
+ first = false;
+ } else {
+ os << ", ";
+ if (pretty) os << std::endl;
+ }
+ indentify();
+ os << '"' << i.first.c_str() << "\": ";
+ i.second->stringify(os, pretty);
+ }
+ if (pretty) {
+ os << std::endl;
+ indent--;
+ }
+ indentify();
+ os << '}';
+ break;
+ }
+ case Assign_: {
+ os << "[";
+ ref->stringify(os, pretty);
+ os << ", ";
+ asAssign()->value()->stringify(os, pretty);
+ os << "]";
+ break;
+ }
+ }
+}
+
// dump
void dump(const char *str, Ref node, bool pretty) {
@@ -252,6 +352,6 @@ void traverseFunctions(Ref ast, std::function<void (Ref)> visit) {
// ValueBuilder
-IStringSet ValueBuilder::statable("assign call binary unary-prefix conditional dot new sub seq string object array");
+IStringSet ValueBuilder::statable("call binary unary-prefix conditional dot new sub seq string object array");
} // namespace cashew
diff --git a/src/emscripten-optimizer/simple_ast.h b/src/emscripten-optimizer/simple_ast.h
index f4dce76aa..784f49632 100644
--- a/src/emscripten-optimizer/simple_ast.h
+++ b/src/emscripten-optimizer/simple_ast.h
@@ -44,8 +44,8 @@
namespace cashew {
-struct Ref;
struct Value;
+struct Ref;
void dump(const char *str, Ref node, bool pretty=false);
@@ -96,6 +96,8 @@ public:
}
};
+struct Assign;
+
// Main value type
struct Value {
enum Type {
@@ -104,7 +106,8 @@ struct Value {
Array = 2,
Null = 3,
Bool = 4,
- Object = 5
+ Object = 5,
+ Assign_ = 6 // ref = target
};
Type type;
@@ -122,6 +125,7 @@ struct Value {
ArrayStorage *arr;
bool boo;
ObjectStorage *obj;
+ Ref ref;
};
// constructors all copy their input
@@ -198,13 +202,15 @@ struct Value {
obj = new ObjectStorage();
return *this;
}
+ Value& setAssign(Ref target, Ref 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 isObject() { return type == Object; }
+ bool isObject() { return type == Object; }
+ bool isAssign() { return type == Assign_; }
bool isBool(bool b) { return type == Bool && b == boo; } // avoid overloading == as it might overload over int
@@ -237,6 +243,8 @@ struct Value {
return boo;
}
+ Assign* asAssign();
+
int32_t getInteger() { // convenience function to get a known integer
assert(fmod(getNumber(), 1) == 0);
int32_t ret = getNumber();
@@ -262,7 +270,7 @@ struct Value {
case Bool:
setBool(other.boo);
break;
- case Object:
+ default:
abort(); // TODO
}
return *this;
@@ -283,31 +291,12 @@ struct Value {
return boo == other.boo;
case Object:
return this == &other; // if you want a deep compare, use deepCompare
+ default:
+ abort();
}
return true;
}
- bool deepCompare(Ref ref) {
- Value& other = *ref;
- if (*this == other) return true; // either same pointer, or identical value type (string, number, null or bool)
- if (type != other.type) return false;
- if (type == Array) {
- if (arr->size() != other.arr->size()) return false;
- for (unsigned i = 0; i < arr->size(); i++) {
- if (!(*arr)[i]->deepCompare((*other.arr)[i])) return false;
- }
- return true;
- } else if (type == Object) {
- if (obj->size() != other.obj->size()) return false;
- for (auto i : *obj) {
- if (other.obj->count(i.first) == 0) return false;
- if (i.second->deepCompare((*other.obj)[i.first])) return false;
- }
- return true;
- }
- return false;
- }
-
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++; }
@@ -387,78 +376,7 @@ struct Value {
return curr;
}
- void stringify(std::ostream &os, bool pretty=false) {
- static int indent = 0;
- #define indentify() { for (int i_ = 0; i_ < indent; i_++) os << " "; }
- switch (type) {
- case String:
- if (str.str) {
- os << '"' << str.str << '"';
- } else {
- os << "\"(null)\"";
- }
- break;
- case Number:
- os << std::setprecision(17) << num; // doubles can have 17 digits of precision
- break;
- case Array:
- if (arr->size() == 0) {
- os << "[]";
- break;
- }
- os << '[';
- if (pretty) {
- os << std::endl;
- indent++;
- }
- for (size_t i = 0; i < arr->size(); i++) {
- if (i > 0) {
- if (pretty) os << "," << std::endl;
- else os << ", ";
- }
- indentify();
- (*arr)[i]->stringify(os, pretty);
- }
- if (pretty) {
- os << std::endl;
- indent--;
- }
- indentify();
- os << ']';
- break;
- case Null:
- os << "null";
- break;
- case Bool:
- os << (boo ? "true" : "false");
- break;
- case Object:
- os << '{';
- if (pretty) {
- os << std::endl;
- indent++;
- }
- bool first = true;
- for (auto i : *obj) {
- if (first) {
- first = false;
- } else {
- os << ", ";
- if (pretty) os << std::endl;
- }
- indentify();
- os << '"' << i.first.c_str() << "\": ";
- i.second->stringify(os, pretty);
- }
- if (pretty) {
- os << std::endl;
- indent--;
- }
- indentify();
- os << '}';
- break;
- }
- }
+ void stringify(std::ostream &os, bool pretty=false);
// String operations
@@ -559,6 +477,25 @@ struct Value {
}
};
+struct Assign : public Value {
+ Ref value_;
+
+ Assign(Ref targetInit, Ref valueInit) {
+ type = Assign_;
+ target() = targetInit;
+ value() = valueInit;
+ }
+
+ Assign() : Assign(nullptr, nullptr) {}
+
+ Ref& target() {
+ return ref;
+ }
+ Ref& value() {
+ return value_;
+ }
+};
+
// AST traversals
// Traverse, calling visit before the children
@@ -663,12 +600,14 @@ struct JSPrinter {
printNum(node);
return;
}
+ if (node->isAssign()) {
+ printAssign(node);
+ }
IString type = node[0]->getIString();
//fprintf(stderr, "printing %s\n", type.str);
switch (type.str[0]) {
case 'a': {
- if (type == ASSIGN) printAssign(node);
- else if (type == ARRAY) printArray(node);
+ if (type == ARRAY) printArray(node);
else abort();
break;
}
@@ -829,11 +768,12 @@ struct JSPrinter {
}
void printAssign(Ref node) {
- printChild(node[2], node, -1);
+ auto* assign = node->asAssign();
+ printChild(assign->target(), node, -1);
space();
emit('=');
space();
- printChild(node[3], node, 1);
+ printChild(assign->value(), node, 1);
}
void printName(Ref node) {
@@ -980,6 +920,9 @@ struct JSPrinter {
}
int getPrecedence(Ref node, bool parent) {
+ if (node->isAssign()) {
+ return OperatorClass::getPrecedence(OperatorClass::Binary, SET);
+ }
Ref type = node[0];
if (type == BINARY || type == UNARY_PREFIX) {
return OperatorClass::getPrecedence(type == BINARY ? OperatorClass::Binary : OperatorClass::Prefix, node[1]->getIString());
@@ -987,8 +930,6 @@ struct JSPrinter {
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
- } else if (type == ASSIGN) {
- return OperatorClass::getPrecedence(OperatorClass::Binary, SET);
} else if (type == CONDITIONAL) {
return OperatorClass::getPrecedence(OperatorClass::Tertiary, QUESTION);
}
@@ -1454,7 +1395,7 @@ public:
}
static Ref makeStatement(Ref contents) {
- if (contents->isNumber() || contents->isString() || statable.has(contents[0]->getIString())) {
+ if (contents->isNumber() || contents->isString() || contents->isAssign() || statable.has(contents[0]->getIString())) {
return &makeRawArray(2)->push_back(makeRawString(STAT))
.push_back(contents);
} else {
@@ -1480,10 +1421,7 @@ public:
static Ref makeBinary(Ref left, IString op, Ref right) {
if (op == SET) {
- return &makeRawArray(4)->push_back(makeRawString(ASSIGN))
- .push_back(&arena.alloc<Value>()->setBool(true))
- .push_back(left)
- .push_back(right);
+ return &arena.alloc<Assign>()->setAssign(left, right);
} else if (op == COMMA) {
return &makeRawArray(3)->push_back(makeRawString(SEQ))
.push_back(left)
@@ -1661,16 +1599,10 @@ public:
}
static Ref makeAssign(Ref target, Ref value) {
- return &makeRawArray(3)->push_back(makeRawString(ASSIGN))
- .push_back(&arena.alloc<Value>()->setBool(true))
- .push_back(target)
- .push_back(value);
+ return &arena.alloc<Assign>()->setAssign(target, value);
}
static Ref makeAssign(IString target, Ref value) {
- return &makeRawArray(3)->push_back(makeRawString(ASSIGN))
- .push_back(&arena.alloc<Value>()->setBool(true))
- .push_back(makeName(target))
- .push_back(value);
+ return &arena.alloc<Assign>()->setAssign(makeName(target), value);
}
static Ref makeSub(Ref obj, Ref index) {