--- a/js/src/frontend/BinaryAST.cpp
+++ b/js/src/frontend/BinaryAST.cpp
@@ -8,64 +8,58 @@
#include "frontend/BinaryAST.h"
#include "frontend/ParseNode.h"
#include "jsatom.h"
#include "jsopcode.h"
namespace js {
namespace frontend {
-/*
-MOZ_MUST_USE bool binSerialize(JSContext* cx, const ParseNode* node, std::ostringstream& out, std::ostringstream& debug);
-MOZ_MUST_USE ParseNode* binParse(JSContext* cx, std::istringstream& in, std::ostringstream& debug);
-*/
+/**
+ * A marker for presence/absence.
+ */
enum OptionValue {
OptionIsHere = -1,
OptionIsAbsent = -2,
};
-// A (pretty long) header to simplify debugging.
+// A (pretty long) header/footer to simplify debugging.
+// Useful for prototyping, probably useless for a real product.
const char HEADER[] = "I am a header.";
const char FOOTER[] = "Behold the footer.";
// List of names of ParseNodeKind, to simplify logging.
const char* NAMES[] = {
#define EMIT_SLOT(name) "PNK_" #name,
FOR_EACH_PARSE_NODE_KIND(EMIT_SLOT)
#undef EMIT_SLOT
"PNK_LIMIT"
};
size_t totalByteLength(const StringTree::Concat* concat) {
- size_t total = sizeof concat->children.length();
+ size_t total = sizeof concat->children.length()
+ + (sizeof StringTree::variantKind);
for (const UniquePtr<StringTree>& item: concat->children) {
- total += item->byteLength
- + sizeof HEADER
- + sizeof FOOTER
- + sizeof item->variantKind
+ total
+ += sizeof HEADER
+ sizeof item->kind
- + sizeof item->byteLength;
+ + sizeof item->byteLength
+ + item->byteLength
+ + sizeof FOOTER;
}
return total;
}
-size_t totalByteLength(const StringTree::Leaf* concat) {
- return concat->data.length();
+size_t totalByteLength(const StringTree::Leaf* leaf) {
+ return leaf->data.length()
+ + sizeof StringTree::variantKind;
}
-/*
-size_t totalByteLength(const StringTree::Variant& variant) {
- if (variant.is<StringTree::Leaf*>()) {
- return totalByteLength(variant.as<StringTree::Leaf*>());
- } else {
- return totalByteLength(variant.as<StringTree::Concat*>());
- }
-}
-*/
+// FIXME: We should rather have a StringTreeWriter.
StringTree::~StringTree()
{
switch (variantKind) {
case VariantKind::IsLeaf:
delete data.leaf;
return;
case VariantKind::IsConcat:
delete data.concat;
@@ -162,26 +156,27 @@ StringTree::read(JSContext* cx, std::ist
}
ParseNodeKind kind;
in.read((char*)&kind, sizeof kind);
if (kind >= mozilla::ArrayLength(NAMES)) {
MOZ_CRASH("Bad kind");
}
+ size_t byteLength;
+ in.read((char*)&byteLength, sizeof byteLength);
+
VariantKind variant;
in.read((char*)&variant, sizeof variant);
- size_t byteLength;
- in.read((char*)&byteLength, sizeof byteLength);
-
MOZ_ASSERT(variant == VariantKind::IsLeaf || variant == VariantKind::IsConcat);
+ const size_t byteStart = in.tellg();
+
UniquePtr<StringTree> result;
- const size_t byteStart = in.tellg();
if (variant == VariantKind::IsLeaf) {
char* buf = new char[byteLength];
in.read(buf, byteLength);
std::string data(buf, byteLength);
delete[] buf;
result = UniquePtr<StringTree>(StringTree::makeLeaf(cx, kind, Move(data)));
} else {
@@ -195,39 +190,41 @@ StringTree::read(JSContext* cx, std::ist
MOZ_CRASH();
return nullptr;
}
}
result = UniquePtr<StringTree>(StringTree::makeConcat(cx, kind, Move(children)));
}
const size_t byteStop = in.tellg();
- MOZ_ASSERT(byteStop - byteStart == byteLength);
+ MOZ_ASSERT(byteStop - byteStart == byteLength + sizeof byteLength);
char footer[sizeof FOOTER + 1];
in.read(footer, sizeof FOOTER);
if (strncmp(footer, FOOTER, sizeof FOOTER) != 0) {
MOZ_CRASH("Bad footer");
}
return result.release();
}
void
StringTree::write(std::ostringstream& out) const {
out.write(HEADER, sizeof HEADER);
out.write((const char*)&kind, sizeof kind);
+ out.write((const char*)&byteLength, sizeof byteLength);
+ const size_t byteStart = out.tellp();
+
out.write((const char*)&variantKind, sizeof variantKind);
- out.write((const char*)&byteLength, sizeof byteLength);
- const size_t byteStart = out.tellp();
if (isLeaf()) {
const Leaf& leaf = asLeaf();
out << leaf.data;
+// std::cerr << "writeLeaf() (" << byteLength << ") => " << leaf.data << "\n";
} else {
const Concat& concat = asConcat();
const size_t length = concat.children.length();
out.write((const char*)&length, sizeof length);
for (const UniquePtr<StringTree>& tree: concat.children) {
tree->write(out);
}
}
@@ -261,17 +258,17 @@ void serializeAtom(JSContext* cx, JSAtom
OptionValue kind(OptionIsAbsent);
out.write((const char*)&kind, sizeof kind);
}
result = Move(out.str());
}
JSAtom* deserializeAtom(JSContext* cx, const std::string& data)
{
- std::istringstream in(data);
+ std::istringstream in(data); // FIXME: Useless copy.
OptionValue op;
in.read((char*)&op, sizeof(op));
if (op == OptionIsHere) {
size_t size;
in.read((char*)&size, sizeof(size));
@@ -285,55 +282,35 @@ JSAtom* deserializeAtom(JSContext* cx, c
// FIXME: We don't need copy.
JSAtom* result = js::Atomize(cx, buf, size);
delete[] buf;
return result;
} else if (op == OptionIsAbsent) {
return nullptr;
}
- MOZ_CRASH();
+ MOZ_CRASH("Invalid variant");
}
MOZ_MUST_USE
bool deserializePropertyName(JSContext* cx, const std::string& data, MutableHandle<PropertyName*> label) {
RootedAtom atom(cx, deserializeAtom(cx, data));
if (atom) {
label.set(atom->asPropertyName());
} else {
label.set(nullptr);
}
return true;
}
-
-/*
-StringTree* treeSerializeAtom(JSContext* cx, JSAtom* atom) {
- std::string data;
- if (atom) {
- OptionValue kind(OptionIsHere);
- UniquePtr<JSString> quoted(QuoteString(cx, atom, 0));
- JSAutoByteString bs;
- const char* bytes = bs.encodeLatin1(cx, quoted.get());
- data.append((const char*)kind, sizeof(kind));
- data.append(bytes, strlen(bytes));
- } else {
- OptionValue kind(OptionIsAbsent);
- data.append((const char*)kind, sizeof(kind));
- }
- StringTree::Leaf leaf(Move(data));
- return cx->new_<StringTree>(Move(leaf));
-}
-*/
-
MOZ_MUST_USE StringTree*
treeSerialize(JSContext* cx, const ParseNode* node, std::ostringstream& debug)
{
const ParseNodeKind kind = node ? node->getKind() : PNK_LIMIT;
- // fprintf(stderr, "treeSerialize %s\n", NAMES[kind]);
+// std::cerr << "treeSerialize " << NAMES[kind] << "\n";
debug << NAMES[kind] << " ";
switch (kind) {
// Empty tree
case PNK_LIMIT: {
return StringTree::makeLeaf(cx, PNK_LIMIT);
}
// Body
@@ -533,17 +510,17 @@ treeSerialize(JSContext* cx, const Parse
}
return StringTree::makeConcat(cx, kind, Move(children));
}
case PNK_DOT: {
std::string label;
serializeAtom(cx, node->pn_atom, label);
mozilla::Vector<UniquePtr<StringTree>> children;
- if (!children.append(StringTree::makeLeaf(cx, kind, Move(label)))) {
+ if (!children.append(StringTree::makeLeaf(cx, PNK_DOT, Move(label)))) {
MOZ_CRASH();
}
if (!children.append(treeSerialize(cx, node->pn_expr, debug))) {
MOZ_CRASH();
}
return StringTree::makeConcat(cx, kind, Move(children));
}
@@ -576,1064 +553,448 @@ treeSerialize(JSContext* cx, const Parse
case PNK_POSHOLDER:
return StringTree::makeLeaf(cx, kind);
// Entirely undocumented nodes:
case PNK_MODULE: MOZ_FALLTHROUGH;
case PNK_DEBUGGER: MOZ_FALLTHROUGH;
case PNK_ELISION: MOZ_FALLTHROUGH;
case PNK_OBJECT_PROPERTY_NAME: {
- // fprintf(stderr, "Placeholder %s\n", NAMES[kind]);
return StringTree::makeLeaf(cx, kind);
}
// Stuff we don't handle yet:
case PNK_REGEXP: {
// fprintf(stderr, "Placeholder %s\n", NAMES[kind]);
return StringTree::makeLeaf(cx, kind, "/Placeholder regexp/");
}
}
MOZ_CRASH("Shouldn't reach that point.");
}
-MOZ_MUST_USE ParseNode*
-treeParse(JSContext* cx, const StringTree* tree, std::ostringstream& debug)
-{
- const ParseNodeKind kind = tree->kind;
-
- debug << NAMES[kind] << " ";
- // fprintf(stderr, "treeParse %s\n", NAMES[kind]);
+class TreeParser MOZ_RAII {
+public:
+ TreeParser(JSContext* cx_, std::istringstream& in_, std::ostringstream& debug_)
+ : cx(cx_)
+ , in(in_)
+ , debug(debug_)
+ { }
+ ~TreeParser() {
+ MOZ_ASSERT(in.peek() == std::char_traits<char>::eof());
+ }
- switch (kind) {
- // Empty subtree.
- case PNK_LIMIT: {
- const StringTree::Leaf& leaf = tree->asLeaf();
- MOZ_ASSERT(leaf.data.length() == 0);
- return nullptr;
- }
-
- case PNK_LEXICALSCOPE: {
- const StringTree::Concat& concat = tree->asConcat();
- MOZ_ASSERT(concat.children.length() == 1);
-
- UniquePtr<ParseNode> body(treeParse(cx, concat.children[0].get(), debug));
- MOZ_ASSERT(body);
-
- return cx->new_<LexicalScopeNode>(nullptr, body.release());
- }
+ // Parse a subtree as a string. The subtree must have been serialized as a string.
+ // FIXME: Crappy documentation suggests crappy concepts. Clean this up.
+ void parseBuf(ParseNodeKind& kind, std::string& buf)
+ {
+ size_t byteLength;
+ readHeader(kind, byteLength);
- case PNK_FUNCTION: {
- const StringTree::Concat& concat = tree->asConcat();
- MOZ_ASSERT(concat.children.length() == 1);
-
- UniquePtr<ParseNode> body(treeParse(cx, concat.children[0].get(), debug));
- MOZ_ASSERT(body);
-
- CodeNode* result(cx->new_<CodeNode>(kind, JSOP_NOP, TokenPos()));
- result->pn_body = body.release();
- return result;
- }
+ const size_t byteStart = in.tellg();
+ readNodeAsLeaf(buf);
+ readFooter(byteStart, byteLength);
+ }
- case PNK_IF: MOZ_FALLTHROUGH;
- case PNK_IMPORT_SPEC: MOZ_FALLTHROUGH;
- case PNK_EXPORT: MOZ_FALLTHROUGH;
- case PNK_FORHEAD: MOZ_FALLTHROUGH;
- case PNK_CONDITIONAL: MOZ_FALLTHROUGH;
- case PNK_CLASS: MOZ_FALLTHROUGH;
- case PNK_TRY: MOZ_FALLTHROUGH;
- case PNK_CATCH: {
- const StringTree::Concat& concat = tree->asConcat();
- MOZ_ASSERT(concat.children.length() == 3);
+ // Parse a subtree as a ParseNode.
+ MOZ_MUST_USE ParseNode* parseNode()
+ {
+ ParseNodeKind kind;
+ size_t byteLength;
+ readHeader(kind, byteLength);
- UniquePtr<ParseNode> kid1(treeParse(cx, concat.children[0].get(), debug));
- UniquePtr<ParseNode> kid2(treeParse(cx, concat.children[1].get(), debug));
- UniquePtr<ParseNode> kid3(treeParse(cx, concat.children[2].get(), debug));
- return cx->new_<TernaryNode>(kind, JSOP_NOP, kid1.release(), kid2.release(), kid3.release(), TokenPos());
- }
+ const size_t byteStart = in.tellg();
+
+ // Actually parse subtree.
+ UniquePtr<ParseNode> result(parseNode(kind));
+
+ readFooter(byteStart, byteLength);
+ return result.release();
+ }
- case PNK_CASE: MOZ_FALLTHROUGH;
- case PNK_WHILE: MOZ_FALLTHROUGH;
- case PNK_DOWHILE: MOZ_FALLTHROUGH;
- case PNK_FOR: MOZ_FALLTHROUGH;
- case PNK_COMPREHENSIONFOR: MOZ_FALLTHROUGH;
- case PNK_WITH: MOZ_FALLTHROUGH;
- case PNK_EXPORT_FROM: MOZ_FALLTHROUGH;
- case PNK_ASSIGN: MOZ_FALLTHROUGH;
- case PNK_ADDASSIGN: MOZ_FALLTHROUGH;
- case PNK_SUBASSIGN: MOZ_FALLTHROUGH;
- case PNK_BITORASSIGN: MOZ_FALLTHROUGH;
- case PNK_BITXORASSIGN: MOZ_FALLTHROUGH;
- case PNK_BITANDASSIGN: MOZ_FALLTHROUGH;
- case PNK_LSHASSIGN: MOZ_FALLTHROUGH;
- case PNK_RSHASSIGN: MOZ_FALLTHROUGH;
- case PNK_URSHASSIGN: MOZ_FALLTHROUGH;
- case PNK_MULASSIGN: MOZ_FALLTHROUGH;
- case PNK_DIVASSIGN: MOZ_FALLTHROUGH;
- case PNK_MODASSIGN: MOZ_FALLTHROUGH;
- case PNK_POWASSIGN: MOZ_FALLTHROUGH;
- case PNK_ELEM: MOZ_FALLTHROUGH;
- case PNK_COLON: MOZ_FALLTHROUGH;
- case PNK_SHORTHAND: MOZ_FALLTHROUGH;
- case PNK_SETTHIS: MOZ_FALLTHROUGH;
- case PNK_SWITCH: MOZ_FALLTHROUGH;
- case PNK_IMPORT: MOZ_FALLTHROUGH;
- case PNK_EXPORT_SPEC: MOZ_FALLTHROUGH;
- case PNK_CLASSMETHOD: MOZ_FALLTHROUGH;
- case PNK_CLASSNAMES: MOZ_FALLTHROUGH;
- case PNK_NEWTARGET: {
- // FIXME: Handle JSOP
- const StringTree::Concat& concat = tree->asConcat();
- MOZ_ASSERT(concat.children.length() == 2);
+ void readNodeAsLeaf(std::string& buf)
+ {
+ size_t byteLength;
+ in.read((char*)&byteLength, sizeof byteLength);
+
+ StringTree::VariantKind variant;
+ in.read((char*)&variant, sizeof variant);
+ MOZ_ASSERT(variant == StringTree::VariantKind::IsLeaf);
- UniquePtr<ParseNode> left(treeParse(cx, concat.children[0].get(), debug));
- UniquePtr<ParseNode> right(treeParse(cx, concat.children[1].get(), debug));
+ const size_t bufLength = byteLength - sizeof variant;
+ buf.resize(bufLength);
+ in.read(&buf[0], bufLength);
+
+// std::cerr << "readNodeAsLeaf: (" << bufLength << ")" << buf << "\n";
+ }
+ size_t readNodeAsConcat() {
+ size_t byteLength;
+ in.read((char*)&byteLength, sizeof byteLength);
- if (kind == PNK_CASE) {
- return cx->new_<CaseClause>(left.release(), right.release(), 0);
- } else {
- return cx->new_<BinaryNode>(kind, JSOP_NOP, TokenPos(), left.release(), right.release());
- }
- }
- case PNK_FORIN: MOZ_FALLTHROUGH;
- case PNK_FOROF: {
- const StringTree::Concat& concat = tree->asConcat();
- MOZ_ASSERT(concat.children.length() == 2);
+ StringTree::VariantKind variant;
+ in.read((char*)&variant, sizeof variant);
+ MOZ_ASSERT(variant == StringTree::VariantKind::IsConcat);
- UniquePtr<ParseNode> left(treeParse(cx, concat.children[0].get(), debug));
- UniquePtr<ParseNode> right(treeParse(cx, concat.children[1].get(), debug));
- return cx->new_<TernaryNode>(kind, JSOP_NOP, left.release(), nullptr, right.release());
- }
+ size_t length;
+ in.read((char*)&length, sizeof length);
- // pn_kid
- case PNK_THROW: MOZ_FALLTHROUGH;
- case PNK_EXPORT_DEFAULT: MOZ_FALLTHROUGH;
- case PNK_COMPUTED_NAME: MOZ_FALLTHROUGH;
- case PNK_ARRAYPUSH: MOZ_FALLTHROUGH;
- case PNK_SPREAD: MOZ_FALLTHROUGH;
- case PNK_RETURN: MOZ_FALLTHROUGH;
- case PNK_SEMI: MOZ_FALLTHROUGH;
- case PNK_THIS: MOZ_FALLTHROUGH;
- case PNK_YIELD: MOZ_FALLTHROUGH;
- case PNK_YIELD_STAR: MOZ_FALLTHROUGH;
- case PNK_AWAIT: MOZ_FALLTHROUGH;
- case PNK_SUPERBASE: MOZ_FALLTHROUGH;
- case PNK_INITIALYIELD: MOZ_FALLTHROUGH;
- case PNK_POS: MOZ_FALLTHROUGH;
- case PNK_NEG: MOZ_FALLTHROUGH;
- case PNK_VOID: MOZ_FALLTHROUGH;
- case PNK_NOT: MOZ_FALLTHROUGH;
- case PNK_BITNOT: MOZ_FALLTHROUGH;
- case PNK_TYPEOFNAME: MOZ_FALLTHROUGH;
- case PNK_TYPEOFEXPR: MOZ_FALLTHROUGH;
- case PNK_PREINCREMENT: MOZ_FALLTHROUGH;
- case PNK_POSTINCREMENT: MOZ_FALLTHROUGH;
- case PNK_PREDECREMENT: MOZ_FALLTHROUGH;
- case PNK_POSTDECREMENT: MOZ_FALLTHROUGH;
- case PNK_DELETENAME: MOZ_FALLTHROUGH;
- case PNK_DELETEPROP: MOZ_FALLTHROUGH;
- case PNK_DELETEELEM: MOZ_FALLTHROUGH;
- case PNK_DELETEEXPR: MOZ_FALLTHROUGH;
- case PNK_MUTATEPROTO: {
- const mozilla::Vector<UniquePtr<StringTree>>& children = tree->children();
- MOZ_ASSERT(children.length() == 1);
+ return length;
+ }
+private:
+ JSContext* cx;
+ std::istringstream& in;
+ std::ostringstream& debug;
- return cx->new_<UnaryNode>(kind, JSOP_NOP, TokenPos(), treeParse(cx, children[0].get(), debug));
+ void readHeader(ParseNodeKind& kind, size_t& byteLength)
+ {
+ std::string header(sizeof HEADER, '\0');
+ in.read(&header[0], sizeof HEADER);
+ if (header.compare(0, sizeof HEADER - 1, HEADER) != 0) {
+ MOZ_CRASH("Bad header");
}
- // Linked lists
- case PNK_CLASSMETHODLIST: MOZ_FALLTHROUGH;
- case PNK_EXPORT_SPEC_LIST: MOZ_FALLTHROUGH;
- case PNK_STATEMENTLIST: MOZ_FALLTHROUGH;
- case PNK_CATCHLIST: MOZ_FALLTHROUGH;
- case PNK_VAR: MOZ_FALLTHROUGH;
- case PNK_LET: MOZ_FALLTHROUGH;
- case PNK_CONST: MOZ_FALLTHROUGH;
- case PNK_COMMA: MOZ_FALLTHROUGH;
- case PNK_CALL: MOZ_FALLTHROUGH;
- case PNK_GENEXP: MOZ_FALLTHROUGH;
- case PNK_ARRAY: MOZ_FALLTHROUGH;
- case PNK_OBJECT: MOZ_FALLTHROUGH;
- case PNK_PARAMSBODY: MOZ_FALLTHROUGH;
- case PNK_OR: MOZ_FALLTHROUGH;
- case PNK_AND: MOZ_FALLTHROUGH;
- case PNK_BITOR: MOZ_FALLTHROUGH;
- case PNK_BITXOR: MOZ_FALLTHROUGH;
- case PNK_BITAND: MOZ_FALLTHROUGH;
- case PNK_EQ: MOZ_FALLTHROUGH;
- case PNK_NE: MOZ_FALLTHROUGH;
- case PNK_STRICTEQ: MOZ_FALLTHROUGH;
- case PNK_STRICTNE: MOZ_FALLTHROUGH;
- case PNK_LT: MOZ_FALLTHROUGH;
- case PNK_LE: MOZ_FALLTHROUGH;
- case PNK_GT: MOZ_FALLTHROUGH;
- case PNK_GE: MOZ_FALLTHROUGH;
- case PNK_LSH: MOZ_FALLTHROUGH;
- case PNK_RSH: MOZ_FALLTHROUGH;
- case PNK_URSH: MOZ_FALLTHROUGH;
- case PNK_ADD: MOZ_FALLTHROUGH;
- case PNK_SUB: MOZ_FALLTHROUGH;
- case PNK_STAR: MOZ_FALLTHROUGH;
- case PNK_DIV: MOZ_FALLTHROUGH;
- case PNK_MOD: MOZ_FALLTHROUGH;
- case PNK_POW: MOZ_FALLTHROUGH;
- case PNK_NEW: MOZ_FALLTHROUGH;
- case PNK_TEMPLATE_STRING_LIST: MOZ_FALLTHROUGH;
- case PNK_TAGGED_TEMPLATE: MOZ_FALLTHROUGH;
- case PNK_CALLSITEOBJ: MOZ_FALLTHROUGH;
- case PNK_IMPORT_SPEC_LIST: MOZ_FALLTHROUGH;
- case PNK_SUPERCALL: MOZ_FALLTHROUGH;
- case PNK_ARRAYCOMP: MOZ_FALLTHROUGH;
- case PNK_INSTANCEOF: MOZ_FALLTHROUGH;
- case PNK_IN: {
- const mozilla::Vector<UniquePtr<StringTree>>& children = tree->children();
- ParseNode* latest = nullptr;
-
- UniquePtr<ListNode> result(cx->new_<ListNode>(kind, TokenPos()));
-
- for (uint32_t i = 0; i < children.length(); ++i) {
- ParseNode* child = treeParse(cx, children[i].get(), debug);
- if (i == 0) {
- result->pn_head = child;
- result->pn_tail = &result->pn_head;
- } else {
- latest->pn_next = child;
- result->pn_tail = &latest->pn_next;
- }
- latest = child;
- result->pn_count++; // Incrementing progressively in case it helps if the destructor is called early.
- }
-
- return result.release();
+ in.read((char*)&kind, sizeof kind);
+ if (kind >= mozilla::ArrayLength(NAMES)) {
+ MOZ_CRASH("Bad kind");
}
- // Labels
- case PNK_BREAK: MOZ_FALLTHROUGH;
- case PNK_CONTINUE: {
- auto leaf = tree->asLeaf();
- RootedPropertyName label(cx);
- if (!deserializePropertyName(cx, leaf.data, &label)) {
- label = nullptr;
- }
- if (kind == PNK_BREAK) {
- return cx->new_<BreakStatement>(label, TokenPos());
- } else {
- return cx->new_<ContinueStatement>(label, TokenPos());
- }
- }
-
- case PNK_LABEL: MOZ_FALLTHROUGH;
- case PNK_DOT: {
- const mozilla::Vector<UniquePtr<StringTree>>& children = tree->children();
- MOZ_ASSERT(children.length() == 2);
-
- auto atom = children[0]->asLeaf();
- RootedPropertyName label(cx);
- if (!deserializePropertyName(cx, atom.data, &label)) {
- label = nullptr;
- }
-
- UniquePtr<ParseNode> expr(treeParse(cx, children[1].get(), debug));
- if (kind == PNK_LABEL) {
- return cx->new_<LabeledStatement>(label, expr.release(), 0);
- } else {
- return cx->new_<PropertyAccess>(expr.release(), label, 0, 0);
- }
- }
-
- // Strings
- case PNK_NAME: MOZ_FALLTHROUGH;
- case PNK_STRING: MOZ_FALLTHROUGH;
- case PNK_TEMPLATE_STRING: {
- auto leaf = tree->asLeaf();
- RootedAtom atom(cx, deserializeAtom(cx, leaf.data));
- return cx->new_<NullaryNode>(kind, JSOP_NOP, TokenPos(), atom);
- }
+ // Lookahead bytelength
+ in.read((char*)&byteLength, sizeof byteLength);
+ in.seekg(-sizeof byteLength, std::ios_base::seekdir::cur);
+ }
- case PNK_NUMBER: {
- auto leaf = tree->asLeaf();
- std::istringstream input(leaf.data);
-
- double dval;
- input.read((char*)&dval, sizeof dval);
-
- DecimalPoint point;
- input.read((char*)&point, sizeof point);
-
- UniquePtr<ParseNode> node(cx->new_<ParseNode>(kind, JSOP_NOP, PN_NULLARY));
- node->initNumber(dval, point);
- return node.release();
- }
+ void readFooter(const size_t byteStart, const size_t byteLength) {
+ // Check byteLength, footer
+ const size_t byteStop = in.tellg();
- // Nullaries
- case PNK_TRUE: MOZ_FALLTHROUGH;
- case PNK_FALSE: MOZ_FALLTHROUGH;
- case PNK_NULL: MOZ_FALLTHROUGH;
- case PNK_RAW_UNDEFINED: MOZ_FALLTHROUGH;
- case PNK_GENERATOR: MOZ_FALLTHROUGH;
- case PNK_NOP: MOZ_FALLTHROUGH;
- case PNK_EXPORT_BATCH_SPEC: MOZ_FALLTHROUGH;
- case PNK_POSHOLDER: {
- auto leaf = tree->asLeaf();
- MOZ_ASSERT(leaf.data.length() == 0);
+ MOZ_ASSERT(byteStop - byteStart == byteLength + sizeof byteLength);
- return cx->new_<NullaryNode>(kind, JSOP_NOP, TokenPos());
- }
-
- // Entirely undocumented nodes:
- case PNK_MODULE: MOZ_FALLTHROUGH;
- case PNK_DEBUGGER: MOZ_FALLTHROUGH;
- case PNK_ELISION: MOZ_FALLTHROUGH;
- case PNK_OBJECT_PROPERTY_NAME: {
- // fprintf(stderr, "Placeholder %s\n", NAMES[kind]);
- return cx->new_<NullaryNode>(kind, JSOP_NOP, TokenPos());
- }
-
- // Stuff we don't handle yet:
- case PNK_REGEXP: {
- // fprintf(stderr, "Placeholder %s\n", NAMES[kind]);
- return cx->new_<RegExpLiteral>(nullptr, TokenPos());
+ std::string footer(sizeof FOOTER, '\0');
+ in.read(&footer[0], sizeof FOOTER);
+ if (footer.compare(0, sizeof FOOTER - 1, FOOTER) != 0) {
+ MOZ_CRASH("Bad footer");
}
}
- MOZ_CRASH("treeParse: out of switch()");
- return nullptr;
-}
+ MOZ_MUST_USE ParseNode* parseNode(ParseNodeKind kind)
+ {
+// std::cerr << "treeParse " << NAMES[kind] << "\n";
+ debug << NAMES[kind] << " ";
+
+ switch (kind) {
+ // Empty subtree.
+ case PNK_LIMIT: {
+ std::string leaf;
+ readNodeAsLeaf(leaf);
+ MOZ_ASSERT(leaf.length() == 0);
+ return nullptr;
+ }
+
+ case PNK_LEXICALSCOPE: {
+ const size_t length = readNodeAsConcat();
+ MOZ_ASSERT(length == 1);
+
+ UniquePtr<ParseNode> body(parseNode());
+ MOZ_ASSERT(body);
+
+ return cx->new_<LexicalScopeNode>(nullptr, body.release());
+ }
+
+ case PNK_FUNCTION: {
+ const size_t length = readNodeAsConcat();
+ MOZ_ASSERT(length == 1);
+
+ UniquePtr<ParseNode> body(parseNode());
+ MOZ_ASSERT(body);
+
+ CodeNode* result(cx->new_<CodeNode>(kind, JSOP_NOP, TokenPos()));
+ result->pn_body = body.release();
+ return result;
+ }
+
+ case PNK_IF: MOZ_FALLTHROUGH;
+ case PNK_IMPORT_SPEC: MOZ_FALLTHROUGH;
+ case PNK_EXPORT: MOZ_FALLTHROUGH;
+ case PNK_FORHEAD: MOZ_FALLTHROUGH;
+ case PNK_CONDITIONAL: MOZ_FALLTHROUGH;
+ case PNK_CLASS: MOZ_FALLTHROUGH;
+ case PNK_TRY: MOZ_FALLTHROUGH;
+ case PNK_CATCH: {
+ const size_t length = readNodeAsConcat();
+ MOZ_ASSERT(length == 3);
+
+ UniquePtr<ParseNode> kid1(parseNode());
+ UniquePtr<ParseNode> kid2(parseNode());
+ UniquePtr<ParseNode> kid3(parseNode());
+ return cx->new_<TernaryNode>(kind, JSOP_NOP, kid1.release(), kid2.release(), kid3.release(), TokenPos());
+ }
-#if DO_NOT_BUILD
-MOZ_MUST_USE bool binSerializeAtom(JSContext* cx, JSAtom* atom, std::ostringstream& out) {
- if (atom) {
- OptionValue kind(OptionIsHere);
- out.write((const char*)&kind, sizeof(kind));
+ case PNK_CASE: MOZ_FALLTHROUGH;
+ case PNK_WHILE: MOZ_FALLTHROUGH;
+ case PNK_DOWHILE: MOZ_FALLTHROUGH;
+ case PNK_FOR: MOZ_FALLTHROUGH;
+ case PNK_COMPREHENSIONFOR: MOZ_FALLTHROUGH;
+ case PNK_WITH: MOZ_FALLTHROUGH;
+ case PNK_EXPORT_FROM: MOZ_FALLTHROUGH;
+ case PNK_ASSIGN: MOZ_FALLTHROUGH;
+ case PNK_ADDASSIGN: MOZ_FALLTHROUGH;
+ case PNK_SUBASSIGN: MOZ_FALLTHROUGH;
+ case PNK_BITORASSIGN: MOZ_FALLTHROUGH;
+ case PNK_BITXORASSIGN: MOZ_FALLTHROUGH;
+ case PNK_BITANDASSIGN: MOZ_FALLTHROUGH;
+ case PNK_LSHASSIGN: MOZ_FALLTHROUGH;
+ case PNK_RSHASSIGN: MOZ_FALLTHROUGH;
+ case PNK_URSHASSIGN: MOZ_FALLTHROUGH;
+ case PNK_MULASSIGN: MOZ_FALLTHROUGH;
+ case PNK_DIVASSIGN: MOZ_FALLTHROUGH;
+ case PNK_MODASSIGN: MOZ_FALLTHROUGH;
+ case PNK_POWASSIGN: MOZ_FALLTHROUGH;
+ case PNK_ELEM: MOZ_FALLTHROUGH;
+ case PNK_COLON: MOZ_FALLTHROUGH;
+ case PNK_SHORTHAND: MOZ_FALLTHROUGH;
+ case PNK_SETTHIS: MOZ_FALLTHROUGH;
+ case PNK_SWITCH: MOZ_FALLTHROUGH;
+ case PNK_IMPORT: MOZ_FALLTHROUGH;
+ case PNK_EXPORT_SPEC: MOZ_FALLTHROUGH;
+ case PNK_CLASSMETHOD: MOZ_FALLTHROUGH;
+ case PNK_CLASSNAMES: MOZ_FALLTHROUGH;
+ case PNK_NEWTARGET: MOZ_FALLTHROUGH;
+ case PNK_FORIN: MOZ_FALLTHROUGH;
+ case PNK_FOROF: {
+ const size_t length = readNodeAsConcat();
+ MOZ_ASSERT(length == 2);
+
+ UniquePtr<ParseNode> left(parseNode());
+ UniquePtr<ParseNode> right(parseNode());
- JSString* quoted = QuoteString(cx, atom, 0);
- JSAutoByteString bs;
- const char* bytes = bs.encodeLatin1(cx, quoted);
+ if (kind == PNK_CASE) {
+ return cx->new_<CaseClause>(left.release(), right.release(), 0);
+ } else if (kind == PNK_FORIN || kind == PNK_FOROF) {
+ return cx->new_<TernaryNode>(kind, JSOP_NOP, left.release(), nullptr, right.release());
+ } else {
+ return cx->new_<BinaryNode>(kind, JSOP_NOP, TokenPos(), left.release(), right.release());
+ }
+ }
+
+ // pn_kid
+ case PNK_THROW: MOZ_FALLTHROUGH;
+ case PNK_EXPORT_DEFAULT: MOZ_FALLTHROUGH;
+ case PNK_COMPUTED_NAME: MOZ_FALLTHROUGH;
+ case PNK_ARRAYPUSH: MOZ_FALLTHROUGH;
+ case PNK_SPREAD: MOZ_FALLTHROUGH;
+ case PNK_RETURN: MOZ_FALLTHROUGH;
+ case PNK_SEMI: MOZ_FALLTHROUGH;
+ case PNK_THIS: MOZ_FALLTHROUGH;
+ case PNK_YIELD: MOZ_FALLTHROUGH;
+ case PNK_YIELD_STAR: MOZ_FALLTHROUGH;
+ case PNK_AWAIT: MOZ_FALLTHROUGH;
+ case PNK_SUPERBASE: MOZ_FALLTHROUGH;
+ case PNK_INITIALYIELD: MOZ_FALLTHROUGH;
+ case PNK_POS: MOZ_FALLTHROUGH;
+ case PNK_NEG: MOZ_FALLTHROUGH;
+ case PNK_VOID: MOZ_FALLTHROUGH;
+ case PNK_NOT: MOZ_FALLTHROUGH;
+ case PNK_BITNOT: MOZ_FALLTHROUGH;
+ case PNK_TYPEOFNAME: MOZ_FALLTHROUGH;
+ case PNK_TYPEOFEXPR: MOZ_FALLTHROUGH;
+ case PNK_PREINCREMENT: MOZ_FALLTHROUGH;
+ case PNK_POSTINCREMENT: MOZ_FALLTHROUGH;
+ case PNK_PREDECREMENT: MOZ_FALLTHROUGH;
+ case PNK_POSTDECREMENT: MOZ_FALLTHROUGH;
+ case PNK_DELETENAME: MOZ_FALLTHROUGH;
+ case PNK_DELETEPROP: MOZ_FALLTHROUGH;
+ case PNK_DELETEELEM: MOZ_FALLTHROUGH;
+ case PNK_DELETEEXPR: MOZ_FALLTHROUGH;
+ case PNK_MUTATEPROTO: {
+ const size_t length = readNodeAsConcat();
+ MOZ_ASSERT(length == 1);
+
+ return cx->new_<UnaryNode>(kind, JSOP_NOP, TokenPos(), parseNode());
+ }
- const size_t size = strlen(bytes); // FIXME: Is this really the size?
- out.write((const char*)&size, sizeof(size));
- out.write(bytes, size);
+ // Linked lists
+ case PNK_CLASSMETHODLIST: MOZ_FALLTHROUGH;
+ case PNK_EXPORT_SPEC_LIST: MOZ_FALLTHROUGH;
+ case PNK_STATEMENTLIST: MOZ_FALLTHROUGH;
+ case PNK_CATCHLIST: MOZ_FALLTHROUGH;
+ case PNK_VAR: MOZ_FALLTHROUGH;
+ case PNK_LET: MOZ_FALLTHROUGH;
+ case PNK_CONST: MOZ_FALLTHROUGH;
+ case PNK_COMMA: MOZ_FALLTHROUGH;
+ case PNK_CALL: MOZ_FALLTHROUGH;
+ case PNK_GENEXP: MOZ_FALLTHROUGH;
+ case PNK_ARRAY: MOZ_FALLTHROUGH;
+ case PNK_OBJECT: MOZ_FALLTHROUGH;
+ case PNK_PARAMSBODY: MOZ_FALLTHROUGH;
+ case PNK_OR: MOZ_FALLTHROUGH;
+ case PNK_AND: MOZ_FALLTHROUGH;
+ case PNK_BITOR: MOZ_FALLTHROUGH;
+ case PNK_BITXOR: MOZ_FALLTHROUGH;
+ case PNK_BITAND: MOZ_FALLTHROUGH;
+ case PNK_EQ: MOZ_FALLTHROUGH;
+ case PNK_NE: MOZ_FALLTHROUGH;
+ case PNK_STRICTEQ: MOZ_FALLTHROUGH;
+ case PNK_STRICTNE: MOZ_FALLTHROUGH;
+ case PNK_LT: MOZ_FALLTHROUGH;
+ case PNK_LE: MOZ_FALLTHROUGH;
+ case PNK_GT: MOZ_FALLTHROUGH;
+ case PNK_GE: MOZ_FALLTHROUGH;
+ case PNK_LSH: MOZ_FALLTHROUGH;
+ case PNK_RSH: MOZ_FALLTHROUGH;
+ case PNK_URSH: MOZ_FALLTHROUGH;
+ case PNK_ADD: MOZ_FALLTHROUGH;
+ case PNK_SUB: MOZ_FALLTHROUGH;
+ case PNK_STAR: MOZ_FALLTHROUGH;
+ case PNK_DIV: MOZ_FALLTHROUGH;
+ case PNK_MOD: MOZ_FALLTHROUGH;
+ case PNK_POW: MOZ_FALLTHROUGH;
+ case PNK_NEW: MOZ_FALLTHROUGH;
+ case PNK_TEMPLATE_STRING_LIST: MOZ_FALLTHROUGH;
+ case PNK_TAGGED_TEMPLATE: MOZ_FALLTHROUGH;
+ case PNK_CALLSITEOBJ: MOZ_FALLTHROUGH;
+ case PNK_IMPORT_SPEC_LIST: MOZ_FALLTHROUGH;
+ case PNK_SUPERCALL: MOZ_FALLTHROUGH;
+ case PNK_ARRAYCOMP: MOZ_FALLTHROUGH;
+ case PNK_INSTANCEOF: MOZ_FALLTHROUGH;
+ case PNK_IN: {
+ const size_t length = readNodeAsConcat();
+ ParseNode* latest = nullptr;
+
+ UniquePtr<ListNode> result(cx->new_<ListNode>(kind, TokenPos()));
+
+ for (uint32_t i = 0; i < length; ++i) {
+ auto link = parseNode();
+ if (i == 0) {
+ result->pn_head = link;
+ result->pn_tail = &result->pn_head;
+ } else {
+ latest->pn_next = link;
+ result->pn_tail = &latest->pn_next;
+ }
+ latest = link;
+ result->pn_count++; // Incrementing progressively in case it helps if the destructor is called early.
+ }
+
+ return result.release();
+ }
+
+ // Labels
+ case PNK_BREAK: MOZ_FALLTHROUGH;
+ case PNK_CONTINUE: {
+ std::string leaf;
+ readNodeAsLeaf(leaf);
+ RootedPropertyName label(cx);
+ if (!deserializePropertyName(cx, leaf, &label)) {
+ label = nullptr;
+ }
+ if (kind == PNK_BREAK) {
+ return cx->new_<BreakStatement>(label, TokenPos());
+ } else {
+ return cx->new_<ContinueStatement>(label, TokenPos());
+ }
+ }
- // fprintf(stderr, "binSerializeAtom %s (%zu)\n", bytes, size);
- return true;
- } else {
- OptionValue kind(OptionIsAbsent);
- out.write((const char*)&kind, sizeof(kind));
- return true;
+ case PNK_LABEL: MOZ_FALLTHROUGH;
+ case PNK_DOT: {
+ const size_t length = readNodeAsConcat();
+ MOZ_ASSERT(length == 2);
+
+ ParseNodeKind subkind;
+ std::string leaf;
+ parseBuf(subkind, leaf);
+ MOZ_ASSERT(subkind == kind);
+ RootedAtom atom(cx, deserializeAtom(cx, leaf));
+
+ RootedPropertyName label(cx);
+ if (atom) {
+ label.set(atom->asPropertyName());
+ }
+ UniquePtr<ParseNode> expr(parseNode());
+ if (kind == PNK_LABEL) {
+ return cx->new_<LabeledStatement>(label, expr.release(), 0);
+ } else {
+ return cx->new_<PropertyAccess>(expr.release(), label, 0, 0);
+ }
+ }
+
+ // Strings
+ case PNK_NAME: MOZ_FALLTHROUGH;
+ case PNK_STRING: MOZ_FALLTHROUGH;
+ case PNK_TEMPLATE_STRING: {
+ std::string leaf;
+ readNodeAsLeaf(leaf);
+ RootedAtom atom(cx, deserializeAtom(cx, leaf));
+ return cx->new_<NullaryNode>(kind, JSOP_NOP, TokenPos(), atom);
+ }
+
+ case PNK_NUMBER: {
+ std::string leaf;
+ readNodeAsLeaf(leaf);
+ std::istringstream input(leaf); // FIXME: Useless copy.
+
+ double dval;
+ input.read((char*)&dval, sizeof dval);
+
+ DecimalPoint point;
+ input.read((char*)&point, sizeof point);
+
+ UniquePtr<ParseNode> node(cx->new_<ParseNode>(kind, JSOP_NOP, PN_NULLARY));
+ node->initNumber(dval, point);
+ return node.release();
+ }
+
+ // Nullaries
+ case PNK_TRUE: MOZ_FALLTHROUGH;
+ case PNK_FALSE: MOZ_FALLTHROUGH;
+ case PNK_NULL: MOZ_FALLTHROUGH;
+ case PNK_RAW_UNDEFINED: MOZ_FALLTHROUGH;
+ case PNK_GENERATOR: MOZ_FALLTHROUGH;
+ case PNK_NOP: MOZ_FALLTHROUGH;
+ case PNK_EXPORT_BATCH_SPEC: MOZ_FALLTHROUGH;
+ case PNK_POSHOLDER: {
+ std::string leaf;
+ readNodeAsLeaf(leaf);
+ MOZ_ASSERT(leaf.length() == 0);
+
+ return cx->new_<NullaryNode>(kind, JSOP_NOP, TokenPos());
+ }
+
+ // Entirely undocumented nodes:
+ case PNK_MODULE: MOZ_FALLTHROUGH;
+ case PNK_DEBUGGER: MOZ_FALLTHROUGH;
+ case PNK_ELISION: MOZ_FALLTHROUGH;
+ case PNK_OBJECT_PROPERTY_NAME: {
+ std::string leaf;
+ readNodeAsLeaf(leaf);
+ MOZ_ASSERT(leaf.length() == 0);
+
+ return cx->new_<NullaryNode>(kind, JSOP_NOP, TokenPos());
+ }
+
+ // Stuff we don't handle yet:
+ case PNK_REGEXP: {
+ std::string leaf;
+ readNodeAsLeaf(leaf);
+
+ return cx->new_<RegExpLiteral>(nullptr, TokenPos());
+ }
+ }
+
+ MOZ_CRASH("treeParse: out of switch()");
+ return nullptr;
}
-}
-
+};
-MOZ_MUST_USE bool
-binSerialize(JSContext* cx, const ParseNode* node, std::ostringstream& out, std::ostringstream& debug)
-{
- if (!node) {
- out.put(PNK_LIMIT);
- debug << "PNK_LIMIT ";
- return true;
+MOZ_MUST_USE bool binSerialize(JSContext* cx, const ParseNode* node, std::ostringstream& out, std::ostringstream& debug) {
+ const UniquePtr<StringTree> tree(treeSerialize(cx, node, debug));
+ if (!tree) {
+ return false;
}
-
- // fprintf(stderr, "binSerialize %s\n", NAMES[node->getKind()]);
-
- // Sanity check: add a header
- out.write(HEADER, sizeof(HEADER));
-
- ParseNodeKind kind = node->getKind();
- out.write((const char*)&kind, sizeof(node->getKind()));
- debug << NAMES[kind] << " ";
- switch (node->getKind()) {
- case PNK_LEXICALSCOPE:
- // fprintf(stderr, "PNK_LEXICALSCOPE: placeholder implementation\n");
- MOZ_FALLTHROUGH;
- case PNK_FUNCTION:
- if (!binSerialize(cx, node->pn_body, out, debug)) {
- return false;
- }
- return true;
- case PNK_IF: MOZ_FALLTHROUGH;
- case PNK_IMPORT_SPEC: MOZ_FALLTHROUGH;
- case PNK_EXPORT:
- if (!binSerialize(cx, node->pn_kid1, out, debug)) {
- return false;
- }
- if (!binSerialize(cx, node->pn_kid2, out, debug)) {
- return false;
- }
- return binSerialize(cx, node->pn_kid3, out, debug);
- case PNK_CASE:
- if (!binSerialize(cx, node->pn_left, out, debug)) {
- return false;
- }
- if (!binSerialize(cx, node->pn_right, out, debug)) {
- return false;
- }
- return true;
- case PNK_WHILE: MOZ_FALLTHROUGH;
- case PNK_DOWHILE: MOZ_FALLTHROUGH;
- case PNK_FOR: MOZ_FALLTHROUGH;
- case PNK_COMPREHENSIONFOR: MOZ_FALLTHROUGH;
- case PNK_WITH: MOZ_FALLTHROUGH;
- case PNK_EXPORT_FROM: MOZ_FALLTHROUGH;
- case PNK_ASSIGN: MOZ_FALLTHROUGH;
- case PNK_ADDASSIGN: MOZ_FALLTHROUGH;
- case PNK_SUBASSIGN: MOZ_FALLTHROUGH;
- case PNK_BITORASSIGN: MOZ_FALLTHROUGH;
- case PNK_BITXORASSIGN: MOZ_FALLTHROUGH;
- case PNK_BITANDASSIGN: MOZ_FALLTHROUGH;
- case PNK_LSHASSIGN: MOZ_FALLTHROUGH;
- case PNK_RSHASSIGN: MOZ_FALLTHROUGH;
- case PNK_URSHASSIGN: MOZ_FALLTHROUGH;
- case PNK_MULASSIGN: MOZ_FALLTHROUGH;
- case PNK_DIVASSIGN: MOZ_FALLTHROUGH;
- case PNK_MODASSIGN: MOZ_FALLTHROUGH;
- case PNK_POWASSIGN: MOZ_FALLTHROUGH;
- case PNK_ELEM: MOZ_FALLTHROUGH;
- case PNK_COLON: MOZ_FALLTHROUGH;
- case PNK_SHORTHAND: MOZ_FALLTHROUGH;
- case PNK_SETTHIS: MOZ_FALLTHROUGH;
- case PNK_SWITCH: MOZ_FALLTHROUGH;
- case PNK_IMPORT: MOZ_FALLTHROUGH;
- case PNK_EXPORT_SPEC: MOZ_FALLTHROUGH;
- case PNK_CLASSMETHOD: MOZ_FALLTHROUGH;
- case PNK_CLASSNAMES: MOZ_FALLTHROUGH;
- case PNK_NEWTARGET:
- if (!binSerialize(cx, node->pn_left, out, debug)) {
- return false;
- }
- if (!binSerialize(cx, node->pn_right, out, debug)) {
- return false;
- }
- return true;
- case PNK_FORIN: MOZ_FALLTHROUGH;
- case PNK_FOROF:
- if (!binSerialize(cx, node->pn_kid1, out, debug)) {
- return false;
- }
- // No node->pn_kid2 for these nodes.
- if (!binSerialize(cx, node->pn_kid3, out, debug)) {
- return false;
- }
- return true;
- case PNK_FORHEAD:
- if (!binSerialize(cx, node->pn_kid1, out, debug)) {
- return false;
- }
- if (!binSerialize(cx, node->pn_kid2, out, debug)) {
- return false;
- }
- if (!binSerialize(cx, node->pn_kid3, out, debug)) {
- return false;
- }
- return true;
- case PNK_CONDITIONAL: MOZ_FALLTHROUGH;
- case PNK_CLASS:
- if (!binSerialize(cx, node->pn_kid1, out, debug)) {
- return false;
- }
- if (!binSerialize(cx, node->pn_kid2, out, debug)) {
- return false;
- }
- if (!binSerialize(cx, node->pn_kid3, out, debug)) {
- return false;
- }
- return true;
- // Unaries
- case PNK_THROW: MOZ_FALLTHROUGH;
- case PNK_EXPORT_DEFAULT: MOZ_FALLTHROUGH;
- case PNK_COMPUTED_NAME: MOZ_FALLTHROUGH;
- case PNK_ARRAYPUSH: MOZ_FALLTHROUGH;
- case PNK_SPREAD:
- if (!binSerialize(cx, node->pn_kid, out, debug)) {
- return false;
- }
- return true;
- case PNK_TRY:
- if (!binSerialize(cx, node->pn_kid1, out, debug)) {
- return false;
- }
- if (!binSerialize(cx, node->pn_kid2, out, debug)) {
- return false;
- }
- if (!binSerialize(cx, node->pn_kid3, out, debug)) {
- return false;
- }
- return true;
- case PNK_CLASSMETHODLIST: MOZ_FALLTHROUGH;
- case PNK_EXPORT_SPEC_LIST: MOZ_FALLTHROUGH;
- case PNK_STATEMENTLIST: MOZ_FALLTHROUGH;
- case PNK_CATCHLIST: MOZ_FALLTHROUGH;
- case PNK_VAR: MOZ_FALLTHROUGH;
- case PNK_LET: MOZ_FALLTHROUGH;
- case PNK_CONST: MOZ_FALLTHROUGH;
- case PNK_COMMA: MOZ_FALLTHROUGH;
- case PNK_CALL: MOZ_FALLTHROUGH;
- case PNK_GENEXP: MOZ_FALLTHROUGH;
- case PNK_ARRAY: MOZ_FALLTHROUGH;
- case PNK_OBJECT: MOZ_FALLTHROUGH;
- case PNK_PARAMSBODY: MOZ_FALLTHROUGH;
- case PNK_OR: MOZ_FALLTHROUGH;
- case PNK_AND: MOZ_FALLTHROUGH;
- case PNK_BITOR: MOZ_FALLTHROUGH;
- case PNK_BITXOR: MOZ_FALLTHROUGH;
- case PNK_BITAND: MOZ_FALLTHROUGH;
- case PNK_EQ: MOZ_FALLTHROUGH;
- case PNK_NE: MOZ_FALLTHROUGH;
- case PNK_STRICTEQ: MOZ_FALLTHROUGH;
- case PNK_STRICTNE: MOZ_FALLTHROUGH;
- case PNK_LT: MOZ_FALLTHROUGH;
- case PNK_LE: MOZ_FALLTHROUGH;
- case PNK_GT: MOZ_FALLTHROUGH;
- case PNK_GE: MOZ_FALLTHROUGH;
- case PNK_LSH: MOZ_FALLTHROUGH;
- case PNK_RSH: MOZ_FALLTHROUGH;
- case PNK_URSH: MOZ_FALLTHROUGH;
- case PNK_ADD: MOZ_FALLTHROUGH;
- case PNK_SUB: MOZ_FALLTHROUGH;
- case PNK_STAR: MOZ_FALLTHROUGH;
- case PNK_DIV: MOZ_FALLTHROUGH;
- case PNK_MOD: MOZ_FALLTHROUGH;
- case PNK_POW: MOZ_FALLTHROUGH;
- case PNK_NEW: MOZ_FALLTHROUGH;
- case PNK_TEMPLATE_STRING_LIST: MOZ_FALLTHROUGH;
- case PNK_TAGGED_TEMPLATE: MOZ_FALLTHROUGH;
- case PNK_CALLSITEOBJ: MOZ_FALLTHROUGH;
- case PNK_IMPORT_SPEC_LIST: MOZ_FALLTHROUGH;
- case PNK_SUPERCALL: MOZ_FALLTHROUGH;
- case PNK_ARRAYCOMP: MOZ_FALLTHROUGH;
- case PNK_INSTANCEOF: MOZ_FALLTHROUGH;
- case PNK_IN: {
- // fprintf(stderr, "binSerialize list of %d items\n", node->pn_count);
- const size_t count = node->pn_count;
- out.write((const char *)&count, sizeof(node->pn_count));
- for (ParseNode* statement = node->pn_head; statement != nullptr; statement = statement->pn_next) {
- if (!binSerialize(cx, statement, out, debug)) {
- return false;
- }
- }
- return true;
- }
- case PNK_CATCH:
- if (!binSerialize(cx, node->pn_kid1, out, debug)) {
- return false;
- }
- if (!binSerialize(cx, node->pn_kid2, out, debug)) {
- return false;
- }
- if (!binSerialize(cx, node->pn_kid3, out, debug)) {
- return false;
- }
- return true;
- case PNK_BREAK: MOZ_FALLTHROUGH;
- case PNK_CONTINUE:
- if (!binSerializeAtom(cx, node->pn_u.loopControl.label, out)) {
- return false;
- }
- return true;
- case PNK_RETURN: MOZ_FALLTHROUGH;
- case PNK_SEMI:
- if (!binSerialize(cx, node->pn_kid, out, debug)) {
- return false;
- }
- return true;
- case PNK_LABEL:
- if (!binSerializeAtom(cx, node->pn_atom, out)) {
- return false;
- }
- if (!binSerialize(cx, node->pn_expr, out, debug)) {
- return false;
- }
- return true;
- case PNK_POS: MOZ_FALLTHROUGH;
- case PNK_NEG: MOZ_FALLTHROUGH;
- case PNK_VOID: MOZ_FALLTHROUGH;
- case PNK_NOT: MOZ_FALLTHROUGH;
- case PNK_BITNOT: MOZ_FALLTHROUGH;
- case PNK_TYPEOFNAME: MOZ_FALLTHROUGH;
- case PNK_TYPEOFEXPR: MOZ_FALLTHROUGH;
- case PNK_PREINCREMENT: MOZ_FALLTHROUGH;
- case PNK_POSTINCREMENT: MOZ_FALLTHROUGH;
- case PNK_PREDECREMENT: MOZ_FALLTHROUGH;
- case PNK_POSTDECREMENT: MOZ_FALLTHROUGH;
- case PNK_DELETENAME: MOZ_FALLTHROUGH;
- case PNK_DELETEPROP: MOZ_FALLTHROUGH;
- case PNK_DELETEELEM: MOZ_FALLTHROUGH;
- case PNK_DELETEEXPR: MOZ_FALLTHROUGH;
- case PNK_MUTATEPROTO:
- return binSerialize(cx, node->pn_kid, out, debug);
- case PNK_DOT:
- if (!binSerialize(cx, node->pn_expr, out, debug)) {
- return false;
- }
- if (!binSerializeAtom(cx, node->pn_atom, out)) {
- return false;
- }
- return true;
- case PNK_NAME: MOZ_FALLTHROUGH;
- case PNK_STRING: MOZ_FALLTHROUGH;
- case PNK_TEMPLATE_STRING: {
- if (!binSerializeAtom(cx, node->pn_atom, out)) { // FIXME: Double-check.
- return false;
- }
- return true;
- }
- case PNK_NUMBER: {
- double dval = node->pn_dval;
- out.write((const char*)&dval, sizeof(dval));
- DecimalPoint point = node->pn_u.number.decimalPoint;
- out.write((const char*)&point, sizeof(point));
- // fprintf(stderr, "binSerialize number: %f\n", dval);
- return true;
- }
- // Nullaries
- case PNK_TRUE: MOZ_FALLTHROUGH;
- case PNK_FALSE: MOZ_FALLTHROUGH;
- case PNK_NULL: MOZ_FALLTHROUGH;
- case PNK_RAW_UNDEFINED: MOZ_FALLTHROUGH;
- case PNK_GENERATOR: MOZ_FALLTHROUGH;
- case PNK_NOP: MOZ_FALLTHROUGH;
- case PNK_EXPORT_BATCH_SPEC: MOZ_FALLTHROUGH;
- case PNK_POSHOLDER:
- return true;
- case PNK_THIS: MOZ_FALLTHROUGH;
- case PNK_YIELD: MOZ_FALLTHROUGH;
- case PNK_YIELD_STAR: MOZ_FALLTHROUGH;
- case PNK_AWAIT:
- return binSerialize(cx, node->pn_kid, out, debug);
- case PNK_SUPERBASE: MOZ_FALLTHROUGH;
- case PNK_INITIALYIELD:
- return binSerialize(cx, node->pn_kid, out, debug);
-
- case PNK_LEXICALSCOPE:
- // fprintf(stderr, "PNK_LEXICALSCOPE: placeholder implementation\n");
- return binSerialize(cx, node->pn_body, out, debug);
-
- // Stuff we don't handle yet:
- case PNK_REGEXP:
- MOZ_CRASH("TODO");
- break;
-
- // And now, the undocumented nodes:
- case PNK_MODULE: MOZ_FALLTHROUGH;
- case PNK_DEBUGGER: MOZ_FALLTHROUGH;
- case PNK_ELISION: MOZ_FALLTHROUGH;
- case PNK_OBJECT_PROPERTY_NAME:
- return true;
- case PNK_LIMIT:
- MOZ_CRASH("Invalid token PNK_LIMIT");
- }
- MOZ_CRASH("Should not have reached this point");
-}
-
-MOZ_MUST_USE
-JSAtom* binParseAtom(JSContext* cx, std::istringstream& in) {
- OptionValue op;
-
- in.read((char*)&op, sizeof(op));
- if (op == OptionIsHere) {
- size_t size;
- in.read((char*)&size, sizeof(size));
-
- char* buf(new char[size + 1]);
- in.read(buf, size);
-
- {
- buf[size] = '\0';
- // fprintf(stderr, "binParseAtom: %s (%zu)\n", buf, size);
- }
-
- // FIXME: We don't need copy.
- JSAtom* result = js::Atomize(cx, buf, size);
- delete[] buf;
- return result;
- } else if (op == OptionIsAbsent) {
- return nullptr;
- }
- MOZ_CRASH();
-}
-
-MOZ_MUST_USE
-bool binParsePropertyName(JSContext* cx, std::istringstream& in, MutableHandle<PropertyName*> label) {
- JSAtom* atom = binParseAtom(cx, in);
- label.set(atom->asPropertyName());
+ tree->write(out);
return true;
}
-
-MOZ_MUST_USE
-ParseNode* binParseAux(JSContext* cx, ParseNodeKind kind, std::istringstream& in, std::ostringstream& debug);
-MOZ_MUST_USE
-ParseNode* binParse(JSContext* cx, std::istringstream& in, std::ostringstream& debug) {
- static unsigned int depth = 0;
- char header[sizeof(HEADER)];
- in.read(header, sizeof(header));
-
- {
- char tmp = header[sizeof(HEADER) - 1];
- header[sizeof(HEADER) - 1] = 0;
- // fprintf(stderr, "Expected header %s\n", HEADER);
- // fprintf(stderr, "Got header %s\n", header);
- header[sizeof(HEADER) - 1] = tmp;
- }
-
- if (strncmp(header, HEADER, sizeof(HEADER)) != 0) {
- for (size_t i = 0; i < sizeof(HEADER); ++i) {
- // fprintf(stderr, "%u ", header[i]);
- }
- // fprintf(stderr, "\n");
- MOZ_CRASH("Bad header");
- }
-
- ParseNodeKind kind;
- in.read((char*)&kind, sizeof(ParseNodeKind));
-
- MOZ_ASSERT(kind < ArrayLength(NAMES));
- // fprintf(stderr, ">> [%u] binParse %s\n", depth, NAMES[kind]);
- ++depth;
- debug.write(NAMES[kind], strlen(NAMES[kind]));
- debug.write(" ", 1);
-
- ParseNode* result = binParseAux(cx, kind, in, debug);
-
- --depth;
- // fprintf(stderr, "<< [%u] binParse %s\n", depth, NAMES[kind]);
-
-#if 0
- // Sanity check, to find out as early as possible if we failed to swallow all our bytes.
- if (!in.eof()) {
- const size_t pos = in.tellg();
- in.read(header, sizeof(header));
-
- if (strncmp(header, HEADER, sizeof(HEADER)) != 0) {
- char tmp = header[sizeof(HEADER) - 1];
- header[sizeof(HEADER) - 1] = 0;
- // fprintf(stderr, "ERROR: Misaligned read.\n");
- // fprintf(stderr, "Expected header %s\n", HEADER);
- // fprintf(stderr, "Got header %s\n", header);
- header[sizeof(HEADER) - 1] = tmp;
- MOZ_CRASH();
- }
-
- in.seekg(pos);
- }
-#endif
- return result;
+MOZ_MUST_USE ParseNode* binParse(JSContext* cx, std::istringstream& in, std::ostringstream& debug) {
+ TreeParser parser(cx, in, debug);
+ return parser.parseNode();
}
-MOZ_MUST_USE
-ParseNode* binParseAux(JSContext* cx, ParseNodeKind kind, std::istringstream& in, std::ostringstream& debug) {
- switch (kind) {
- case PNK_LIMIT:
- return nullptr;
- case PNK_FUNCTION: {
- UniquePtr<ParseNode> body(binParse(cx, in, debug));
- CodeNode* result(cx->new_<CodeNode>(kind, JSOP_NOP, TokenPos()));
- result->pn_body = body.release();
- return result;
- }
- case PNK_IF: {
- UniquePtr<ParseNode> cond(binParse(cx, in, debug));
- MOZ_ASSERT(cond != nullptr);
- UniquePtr<ParseNode> thenBranch(binParse(cx, in, debug));
- MOZ_ASSERT(thenBranch != nullptr);
- UniquePtr<ParseNode> elseBranch(binParse(cx, in, debug));
- return cx->new_<TernaryNode>(kind, JSOP_NOP, cond.release(), thenBranch.release(), elseBranch.release());
- }
- case PNK_CASE: {
- UniquePtr<ParseNode> expr(binParse(cx, in, debug));
- UniquePtr<ParseNode> statement(binParse(cx, in, debug));
- MOZ_ASSERT(statement != nullptr);
- return cx->new_<CaseClause>(expr.release(), statement.release(), 0);
- }
- case PNK_WHILE: MOZ_FALLTHROUGH;
- case PNK_DOWHILE: MOZ_FALLTHROUGH;
- case PNK_FOR: MOZ_FALLTHROUGH;
- case PNK_COMPREHENSIONFOR: MOZ_FALLTHROUGH;
- case PNK_WITH: MOZ_FALLTHROUGH;
- case PNK_EXPORT_FROM: MOZ_FALLTHROUGH;
- case PNK_ASSIGN: MOZ_FALLTHROUGH;
- case PNK_ADDASSIGN: MOZ_FALLTHROUGH;
- case PNK_SUBASSIGN: MOZ_FALLTHROUGH;
- case PNK_BITORASSIGN: MOZ_FALLTHROUGH;
- case PNK_BITXORASSIGN: MOZ_FALLTHROUGH;
- case PNK_BITANDASSIGN: MOZ_FALLTHROUGH;
- case PNK_LSHASSIGN: MOZ_FALLTHROUGH;
- case PNK_RSHASSIGN: MOZ_FALLTHROUGH;
- case PNK_URSHASSIGN: MOZ_FALLTHROUGH;
- case PNK_MULASSIGN: MOZ_FALLTHROUGH;
- case PNK_DIVASSIGN: MOZ_FALLTHROUGH;
- case PNK_MODASSIGN: MOZ_FALLTHROUGH;
- case PNK_POWASSIGN: MOZ_FALLTHROUGH;
- case PNK_ELEM: MOZ_FALLTHROUGH;
- case PNK_COLON: MOZ_FALLTHROUGH;
- case PNK_SHORTHAND: MOZ_FALLTHROUGH;
- case PNK_SETTHIS: MOZ_FALLTHROUGH;
- case PNK_SWITCH: MOZ_FALLTHROUGH;
- case PNK_IMPORT: MOZ_FALLTHROUGH;
- case PNK_EXPORT_SPEC: MOZ_FALLTHROUGH;
- case PNK_CLASSMETHOD: MOZ_FALLTHROUGH;
- case PNK_CLASSNAMES: MOZ_FALLTHROUGH;
- case PNK_NEWTARGET: {
- UniquePtr<ParseNode> left(binParse(cx, in, debug));
- MOZ_ASSERT(left != nullptr);
- UniquePtr<ParseNode> right(binParse(cx, in, debug));
- MOZ_ASSERT(right != nullptr);
- return cx->new_<BinaryNode>(kind, JSOP_NOP, TokenPos(), left.release(), right.release());
- }
- case PNK_FORIN: MOZ_FALLTHROUGH;
- case PNK_FOROF: {
- JSOp op = kind == PNK_FORIN ? JSOP_ITER : JSOP_NOP;
- UniquePtr<ParseNode> kid1(binParse(cx, in, debug));
- UniquePtr<ParseNode> kid3(binParse(cx, in, debug));
- return cx->new_<TernaryNode>(kind, op, kid1.release(), nullptr, kid3.release());
- }
- case PNK_TRY: MOZ_FALLTHROUGH;
- case PNK_FORHEAD: MOZ_FALLTHROUGH;
- case PNK_CONDITIONAL: {
- UniquePtr<ParseNode> kid1(binParse(cx, in, debug));
- UniquePtr<ParseNode> kid2(binParse(cx, in, debug));
- UniquePtr<ParseNode> kid3(binParse(cx, in, debug));
- return cx->new_<TernaryNode>(kind, JSOP_NOP, kid1.release(), kid2.release(), kid3.release());
- }
- case PNK_THROW: MOZ_FALLTHROUGH;
- case PNK_EXPORT_DEFAULT: MOZ_FALLTHROUGH;
- case PNK_COMPUTED_NAME: MOZ_FALLTHROUGH;
- case PNK_ARRAYPUSH: MOZ_FALLTHROUGH;
- case PNK_SPREAD: {
- UniquePtr<ParseNode> kid(binParse(cx, in, debug));
- JSOp op = kind == PNK_THROW ? JSOP_THROW :
- kind == PNK_ARRAYPUSH ? JSOP_ARRAYPUSH :
- JSOP_NOP;
- return cx->new_<UnaryNode>(kind, op, TokenPos(), kid.release());
- }
- case PNK_STATEMENTLIST: MOZ_FALLTHROUGH;
- case PNK_CATCHLIST: MOZ_FALLTHROUGH;
- case PNK_VAR: MOZ_FALLTHROUGH;
- case PNK_LET: MOZ_FALLTHROUGH;
- case PNK_CONST: MOZ_FALLTHROUGH;
- case PNK_COMMA: MOZ_FALLTHROUGH;
- case PNK_CALL: MOZ_FALLTHROUGH;
- case PNK_GENEXP: MOZ_FALLTHROUGH;
- case PNK_ARRAY: MOZ_FALLTHROUGH;
- case PNK_OBJECT: MOZ_FALLTHROUGH;
- case PNK_PARAMSBODY: MOZ_FALLTHROUGH;
- case PNK_OR: MOZ_FALLTHROUGH;
- case PNK_AND: MOZ_FALLTHROUGH;
- case PNK_BITOR: MOZ_FALLTHROUGH;
- case PNK_BITXOR: MOZ_FALLTHROUGH;
- case PNK_BITAND: MOZ_FALLTHROUGH;
- case PNK_EQ: MOZ_FALLTHROUGH;
- case PNK_NE: MOZ_FALLTHROUGH;
- case PNK_STRICTEQ: MOZ_FALLTHROUGH;
- case PNK_STRICTNE: MOZ_FALLTHROUGH;
- case PNK_LT: MOZ_FALLTHROUGH;
- case PNK_LE: MOZ_FALLTHROUGH;
- case PNK_GT: MOZ_FALLTHROUGH;
- case PNK_GE: MOZ_FALLTHROUGH;
- case PNK_LSH: MOZ_FALLTHROUGH;
- case PNK_RSH: MOZ_FALLTHROUGH;
- case PNK_URSH: MOZ_FALLTHROUGH;
- case PNK_ADD: MOZ_FALLTHROUGH;
- case PNK_SUB: MOZ_FALLTHROUGH;
- case PNK_STAR: MOZ_FALLTHROUGH;
- case PNK_DIV: MOZ_FALLTHROUGH;
- case PNK_MOD: MOZ_FALLTHROUGH;
- case PNK_POW: MOZ_FALLTHROUGH;
- case PNK_NEW: MOZ_FALLTHROUGH;
- case PNK_TEMPLATE_STRING_LIST: MOZ_FALLTHROUGH;
- case PNK_TAGGED_TEMPLATE: MOZ_FALLTHROUGH;
- case PNK_CALLSITEOBJ: MOZ_FALLTHROUGH;
- case PNK_ARRAYCOMP: MOZ_FALLTHROUGH;
- case PNK_IN: MOZ_FALLTHROUGH;
- case PNK_IMPORT_SPEC_LIST: MOZ_FALLTHROUGH;
- case PNK_EXPORT_SPEC_LIST: MOZ_FALLTHROUGH;
- case PNK_CLASSMETHODLIST: MOZ_FALLTHROUGH;
- case PNK_SUPERCALL: MOZ_FALLTHROUGH;
- case PNK_INSTANCEOF: {
- uint32_t count;
- ParseNode* latest = nullptr;
- in.read((char*)&count, sizeof(count));
- // fprintf(stderr, "binParse %s list of %d items\n", NAMES[kind], count);
-
- UniquePtr<ListNode> result(cx->new_<ListNode>(kind, TokenPos()));
-
- for (uint32_t i = 0; i < count; ++i) {
- ParseNode* child = binParse(cx, in, debug);
- if (i == 0) {
- result->pn_head = child;
- result->pn_tail = &result->pn_head;
- } else {
- latest->pn_next = child;
- result->pn_tail = &latest->pn_next;
- }
- latest = child;
- result->pn_count++; // FIXME: Incrementing progressively in case it helps if the destructor is called early.
- }
-
- // fprintf(stderr, "binParse %s list of %d items complete\n", NAMES[kind], count);
- return result.release();
- }
- case PNK_CATCH: {
- UniquePtr<ParseNode> kid1(binParse(cx, in, debug));
- UniquePtr<ParseNode> kid2(binParse(cx, in, debug));
- UniquePtr<ParseNode> kid3(binParse(cx, in, debug));
- return cx->new_<TernaryNode>(kind, JSOP_NOP, kid1.release(), kid2.release(), kid3.release());
- }
- case PNK_BREAK: {
- RootedPropertyName label(cx);
- if (!binParsePropertyName(cx, in, &label)) {
- label = nullptr;
- }
- return cx->new_<BreakStatement>(label, TokenPos());
- }
- case PNK_CONTINUE: {
- RootedPropertyName label(cx);
- if (!binParsePropertyName(cx, in, &label)) {
- label = nullptr;
- }
- return cx->new_<ContinueStatement>(label, TokenPos());
- }
- case PNK_LABEL: {
- RootedPropertyName label(cx);
- if (!binParsePropertyName(cx, in, &label)) {
- label = nullptr;
- }
- UniquePtr<ParseNode> expr(binParse(cx, in, debug));
- return cx->new_<LabeledStatement>(label, expr.release(), 0);
- }
- // JSOP_NOP
- case PNK_SEMI: MOZ_FALLTHROUGH;
- case PNK_TYPEOFNAME: MOZ_FALLTHROUGH;
- case PNK_TYPEOFEXPR: MOZ_FALLTHROUGH;
- case PNK_PREINCREMENT: MOZ_FALLTHROUGH;
- case PNK_POSTINCREMENT: MOZ_FALLTHROUGH;
- case PNK_PREDECREMENT: MOZ_FALLTHROUGH;
- case PNK_POSTDECREMENT: MOZ_FALLTHROUGH;
- case PNK_DELETENAME: MOZ_FALLTHROUGH;
- case PNK_DELETEPROP: MOZ_FALLTHROUGH;
- case PNK_DELETEELEM: MOZ_FALLTHROUGH;
- case PNK_DELETEEXPR: MOZ_FALLTHROUGH;
- // Operation
- case PNK_RETURN: MOZ_FALLTHROUGH;
- case PNK_POS: MOZ_FALLTHROUGH;
- case PNK_NEG: MOZ_FALLTHROUGH;
- case PNK_VOID: MOZ_FALLTHROUGH;
- case PNK_NOT: MOZ_FALLTHROUGH;
- case PNK_BITNOT: {
- JSOp op =
- kind == PNK_RETURN ? JSOP_RETURN :
- kind == PNK_POS ? JSOP_POS :
- kind == PNK_NEG ? JSOP_NEG :
- kind == PNK_VOID ? JSOP_VOID :
- kind == PNK_NOT ? JSOP_NOT :
- kind == PNK_BITNOT ? JSOP_BITNOT :
- JSOP_NOP;
- UniquePtr<ParseNode> kid(binParse(cx, in, debug));
- return cx->new_<UnaryNode>(kind, op, TokenPos(), kid.release());
- }
- case PNK_DOT: {
- UniquePtr<ParseNode> expr(binParse(cx, in, debug));
- RootedPropertyName name(cx);
- if (!binParsePropertyName(cx, in, &name)) {
- return nullptr; // FIXME: Assert?
- }
- return cx->new_<PropertyAccess>(expr.release(), name, 0, 0);
- }
- case PNK_STRING: MOZ_FALLTHROUGH;
- case PNK_TEMPLATE_STRING: {
- UniquePtr<JSAtom> atom(binParseAtom(cx, in));
- // FIXME: No clue why it seems to need one more byte.
- char buf[1];
- in.read((char*)buf, sizeof(buf));
- return cx->new_<NullaryNode>(kind, JSOP_NOP, TokenPos(), atom.release());
- }
- case PNK_NAME: {
- UniquePtr<JSAtom> atom(binParseAtom(cx, in));
- return cx->new_<NameNode>(PNK_NAME, JSOP_GETNAME, atom.release(), TokenPos());
- }
- case PNK_NUMBER: {
- double dval;
- in.read((char*)&dval, sizeof(dval));
- DecimalPoint point;
- in.read((char*)&point, sizeof(point));
- UniquePtr<NullaryNode> result(cx->new_<NullaryNode>(PNK_NUMBER, TokenPos()));
- result->initNumber(dval, point);
- // fprintf(stderr, "binParse number: %f\n", dval);
- return result.release();
- }
- case PNK_TRUE: MOZ_FALLTHROUGH;
- case PNK_FALSE: {
- return cx->new_<BooleanLiteral>(kind == PNK_TRUE, TokenPos());
- }
- case PNK_NULL: {
- return cx->new_<NullLiteral>(TokenPos());
- }
- case PNK_RAW_UNDEFINED: {
- return cx->new_<RawUndefinedLiteral>(TokenPos());
- }
- case PNK_GENERATOR: MOZ_FALLTHROUGH;
- case PNK_NOP: MOZ_FALLTHROUGH;
- case PNK_ELISION: MOZ_FALLTHROUGH;
- case PNK_OBJECT_PROPERTY_NAME: MOZ_FALLTHROUGH;
- case PNK_MODULE: MOZ_FALLTHROUGH;
- case PNK_DEBUGGER: MOZ_FALLTHROUGH;
- case PNK_EXPORT_BATCH_SPEC: MOZ_FALLTHROUGH;
- case PNK_POSHOLDER: {
- return cx->new_<NullaryNode>(kind, TokenPos());
- }
- case PNK_THIS: {
- UniquePtr<ParseNode> value(binParse(cx, in, debug));
- return cx->new_<ThisLiteral>(TokenPos(), value.release());
- }
- case PNK_YIELD: {
- UniquePtr<ParseNode> value(binParse(cx, in, debug));
- return cx->new_<UnaryNode>(kind, JSOP_YIELD, TokenPos(), value.release());
- }
- case PNK_YIELD_STAR: {
- UniquePtr<ParseNode> value(binParse(cx, in, debug));
- return cx->new_<UnaryNode>(kind, JSOP_NOP, TokenPos(), value.release());
- }
- case PNK_AWAIT: {
- UniquePtr<ParseNode> value(binParse(cx, in, debug));
- return cx->new_<UnaryNode>(kind, JSOP_AWAIT, TokenPos(), value.release());
- }
- case PNK_SUPERBASE: {
- UniquePtr<ParseNode> value(binParse(cx, in, debug));
- return cx->new_<UnaryNode>(kind, JSOP_NOP, TokenPos(), value.release());
- }
- case PNK_INITIALYIELD: {
- UniquePtr<ParseNode> value(binParse(cx, in, debug));
- return cx->new_<UnaryNode>(kind, JSOP_INITIALYIELD, TokenPos(), value.release());
- }
- case PNK_REGEXP: {
- MOZ_CRASH("No idea how to handle this yet");
- return nullptr;
- }
- case PNK_LEXICALSCOPE: {
- // fprintf(stderr, "PNK_LEXICALSCOPE: placeholder parser\n");
- UniquePtr<ParseNode> body(binParse(cx, in, debug));
- return cx->new_<LexicalScopeNode>(nullptr, body.release());
- }
- case PNK_MUTATEPROTO: {
- // fprintf(stderr, "PNK_MUTATEPROTO: placeholder parser\n");
- UniquePtr<ParseNode> kid(binParse(cx, in, debug));
- return cx->new_<UnaryNode>(kind, JSOP_NOP, TokenPos(), kid.release());
- }
- case PNK_EXPORT: MOZ_FALLTHROUGH;
- case PNK_IMPORT_SPEC: {
- UniquePtr<ParseNode> kid1(binParse(cx, in, debug));
- UniquePtr<ParseNode> kid2(binParse(cx, in, debug));
- UniquePtr<ParseNode> kid3(binParse(cx, in, debug));
- return cx->new_<TernaryNode>(kind, JSOP_NOP, kid1.release(), kid2.release(), kid3.release());
- }
- case PNK_CLASS: {
- UniquePtr<ParseNode> kid1(binParse(cx, in, debug));
- UniquePtr<ParseNode> kid2(binParse(cx, in, debug));
- UniquePtr<ParseNode> kid3(binParse(cx, in, debug));
- return cx->new_<ClassNode>(kid1.release(), kid2.release(), kid3.release());
- }
-
- }
- MOZ_CRASH("Should not have reached that point");
-}
-
-#endif // 0
-
} // namespace frontend
} // namespace js