in lib/AST/ASTBuilder.cpp [242:717]
llvh::Optional<Node *> ASTBuilder::build(const JSONValue *node) {
if (isa<parser::JSONNull>(node))
return new (context_) EmptyNode();
auto jsObj = dyn_cast<JSONObject>(node);
if (!jsObj) {
sm_.error(SMLoc{}, "node is not an object");
return None;
}
assert(jsObj && "invalid node type");
// Get the type of the serialized object.
auto TypeItr = jsObj->find("type");
// If the 'type' field is unspecified then this is a metadata object.
if (TypeItr == jsObj->end())
return new (context_) ESTree::MetadataNode();
// Read the name of the property.
assert(isa<JSONString>((*TypeItr).second) && "invalid 'type' property");
StringRef Typename = dyn_cast<JSONString>((*TypeItr).second)->str();
/* // Ignore the following nodes as they are not supported.
if (Typename == "CommentLine" || Typename == "CommentBlock") {
return nullptr;
}*/
// Optionally extract location information.
SMRange sourceRng;
if (jsSource_) {
const auto *start = dyn_cast_or_null<JSONNumber>(jsObj->get("start"));
const auto *end = dyn_cast_or_null<JSONNumber>(jsObj->get("end"));
// If start or end are missing, check for range array.
if (!start || !end) {
if (auto *range = dyn_cast_or_null<JSONArray>(jsObj->get("range"))) {
if (range->size() == 2) {
start = dyn_cast_or_null<JSONNumber>(range->at(0));
end = dyn_cast_or_null<JSONNumber>(range->at(1));
}
}
}
if (start && end) {
auto startN = (int)start->getValue();
auto endN = (int)end->getValue();
if (startN >= 0 && startN < (int)jsSource_->getBufferSize() &&
endN >= startN && endN <= (int)jsSource_->getBufferSize()) {
sourceRng.Start =
SMLoc::getFromPointer(jsSource_->getBufferStart() + startN);
sourceRng.End =
SMLoc::getFromPointer(jsSource_->getBufferStart() + endN);
}
}
}
Node *result = nullptr;
// Some parsers (e.g. Flow) emit RestProperty instead of RestElement, so map
// the former to the latter. Same for SpreadProperty and SpreadElement.
if (Typename == "RestProperty")
Typename = "RestElement";
else if (Typename == "SpreadProperty")
Typename = "SpreadElement";
if (Typename == "Literal") {
// Special-case ESTree Literal nodes, which we have to convert to a type-
// specific literal.
auto lit = convertLiteral(jsObj);
if (!lit)
return None;
result = *lit;
result->setSourceRange(sourceRng);
return result;
}
if (Typename == "TemplateElement") {
auto templateElement = convertTemplateElement(jsObj);
if (!templateElement) {
return None;
}
result = *templateElement;
result->setSourceRange(sourceRng);
return result;
}
#define ESTREE_NODE_0_ARGS(NAME, BASE) \
if (Typename == #NAME) { \
result = new (context_) NAME##Node(); \
result->setSourceRange(sourceRng); \
return result; \
}
#define ESTREE_NODE_1_ARGS(NAME, BASE, ARG0TY, ARG0NM, ARG0OPT) \
if (Typename == #NAME) { \
ARG0TY arg0{}; \
if (!extract##ARG0TY(jsObj, #ARG0NM, arg0) && !(ARG0OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG0NM "' in " #NAME); \
return None; \
} \
result = new (context_) NAME##Node(std::move(arg0)); \
result->setSourceRange(sourceRng); \
return result; \
}
#define ESTREE_NODE_2_ARGS( \
NAME, BASE, ARG0TY, ARG0NM, ARG0OPT, ARG1TY, ARG1NM, ARG1OPT) \
if (Typename == #NAME) { \
ARG0TY arg0{}; \
ARG1TY arg1{}; \
if (!extract##ARG0TY(jsObj, #ARG0NM, arg0) && !(ARG0OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG0NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG1TY(jsObj, #ARG1NM, arg1) && !(ARG1OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG1NM "' in " #NAME); \
return None; \
} \
result = new (context_) NAME##Node(std::move(arg0), std::move(arg1)); \
result->setSourceRange(sourceRng); \
return result; \
}
#define ESTREE_NODE_3_ARGS( \
NAME, \
BASE, \
ARG0TY, \
ARG0NM, \
ARG0OPT, \
ARG1TY, \
ARG1NM, \
ARG1OPT, \
ARG2TY, \
ARG2NM, \
ARG2OPT) \
if (Typename == #NAME) { \
ARG0TY arg0{}; \
ARG1TY arg1{}; \
ARG2TY arg2{}; \
if (!extract##ARG0TY(jsObj, #ARG0NM, arg0) && !(ARG0OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG0NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG1TY(jsObj, #ARG1NM, arg1) && !(ARG1OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG1NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG2TY(jsObj, #ARG2NM, arg2) && !(ARG2OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG2NM "' in " #NAME); \
return None; \
} \
result = new (context_) \
NAME##Node(std::move(arg0), std::move(arg1), std::move(arg2)); \
result->setSourceRange(sourceRng); \
return result; \
}
#define ESTREE_NODE_4_ARGS( \
NAME, \
BASE, \
ARG0TY, \
ARG0NM, \
ARG0OPT, \
ARG1TY, \
ARG1NM, \
ARG1OPT, \
ARG2TY, \
ARG2NM, \
ARG2OPT, \
ARG3TY, \
ARG3NM, \
ARG3OPT) \
if (Typename == #NAME) { \
ARG0TY arg0{}; \
ARG1TY arg1{}; \
ARG2TY arg2{}; \
ARG3TY arg3{}; \
if (!extract##ARG0TY(jsObj, #ARG0NM, arg0) && !(ARG0OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG0NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG1TY(jsObj, #ARG1NM, arg1) && !(ARG1OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG1NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG2TY(jsObj, #ARG2NM, arg2) && !(ARG2OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG2NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG3TY(jsObj, #ARG3NM, arg3) && !(ARG3OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG3NM "' in " #NAME); \
return None; \
} \
result = new (context_) NAME##Node( \
std::move(arg0), std::move(arg1), std::move(arg2), std::move(arg3)); \
result->setSourceRange(sourceRng); \
return result; \
}
#define ESTREE_NODE_5_ARGS( \
NAME, \
BASE, \
ARG0TY, \
ARG0NM, \
ARG0OPT, \
ARG1TY, \
ARG1NM, \
ARG1OPT, \
ARG2TY, \
ARG2NM, \
ARG2OPT, \
ARG3TY, \
ARG3NM, \
ARG3OPT, \
ARG4TY, \
ARG4NM, \
ARG4OPT) \
if (Typename == #NAME) { \
ARG0TY arg0{}; \
ARG1TY arg1{}; \
ARG2TY arg2{}; \
ARG3TY arg3{}; \
ARG4TY arg4{}; \
if (!extract##ARG0TY(jsObj, #ARG0NM, arg0) && !(ARG0OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG0NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG1TY(jsObj, #ARG1NM, arg1) && !(ARG1OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG1NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG2TY(jsObj, #ARG2NM, arg2) && !(ARG2OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG2NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG3TY(jsObj, #ARG3NM, arg3) && !(ARG3OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG3NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG4TY(jsObj, #ARG4NM, arg4) && !(ARG4OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG4NM "' in " #NAME); \
return None; \
} \
result = new (context_) NAME##Node( \
std::move(arg0), \
std::move(arg1), \
std::move(arg2), \
std::move(arg3), \
std::move(arg4)); \
result->setSourceRange(sourceRng); \
return result; \
}
#define ESTREE_NODE_6_ARGS( \
NAME, \
BASE, \
ARG0TY, \
ARG0NM, \
ARG0OPT, \
ARG1TY, \
ARG1NM, \
ARG1OPT, \
ARG2TY, \
ARG2NM, \
ARG2OPT, \
ARG3TY, \
ARG3NM, \
ARG3OPT, \
ARG4TY, \
ARG4NM, \
ARG4OPT, \
ARG5TY, \
ARG5NM, \
ARG5OPT) \
if (Typename == #NAME) { \
ARG0TY arg0{}; \
ARG1TY arg1{}; \
ARG2TY arg2{}; \
ARG3TY arg3{}; \
ARG4TY arg4{}; \
ARG5TY arg5{}; \
if (!extract##ARG0TY(jsObj, #ARG0NM, arg0) && !(ARG0OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG0NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG1TY(jsObj, #ARG1NM, arg1) && !(ARG1OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG1NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG2TY(jsObj, #ARG2NM, arg2) && !(ARG2OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG2NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG3TY(jsObj, #ARG3NM, arg3) && !(ARG3OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG3NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG4TY(jsObj, #ARG4NM, arg4) && !(ARG4OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG4NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG5TY(jsObj, #ARG5NM, arg5) && !(ARG5OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG5NM "' in " #NAME); \
return None; \
} \
result = new (context_) NAME##Node( \
std::move(arg0), \
std::move(arg1), \
std::move(arg2), \
std::move(arg3), \
std::move(arg4), \
std::move(arg5)); \
result->setSourceRange(sourceRng); \
return result; \
}
#define ESTREE_NODE_7_ARGS( \
NAME, \
BASE, \
ARG0TY, \
ARG0NM, \
ARG0OPT, \
ARG1TY, \
ARG1NM, \
ARG1OPT, \
ARG2TY, \
ARG2NM, \
ARG2OPT, \
ARG3TY, \
ARG3NM, \
ARG3OPT, \
ARG4TY, \
ARG4NM, \
ARG4OPT, \
ARG5TY, \
ARG5NM, \
ARG5OPT, \
ARG6TY, \
ARG6NM, \
ARG6OPT) \
if (Typename == #NAME) { \
ARG0TY arg0{}; \
ARG1TY arg1{}; \
ARG2TY arg2{}; \
ARG3TY arg3{}; \
ARG4TY arg4{}; \
ARG5TY arg5{}; \
ARG6TY arg6{}; \
if (!extract##ARG0TY(jsObj, #ARG0NM, arg0) && !(ARG0OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG0NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG1TY(jsObj, #ARG1NM, arg1) && !(ARG1OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG1NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG2TY(jsObj, #ARG2NM, arg2) && !(ARG2OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG2NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG3TY(jsObj, #ARG3NM, arg3) && !(ARG3OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG3NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG4TY(jsObj, #ARG4NM, arg4) && !(ARG4OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG4NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG5TY(jsObj, #ARG5NM, arg5) && !(ARG5OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG5NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG6TY(jsObj, #ARG6NM, arg6) && !(ARG6OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG6NM "' in " #NAME); \
return None; \
} \
result = new (context_) NAME##Node( \
std::move(arg0), \
std::move(arg1), \
std::move(arg2), \
std::move(arg3), \
std::move(arg4), \
std::move(arg5), \
std::move(arg6)); \
result->setSourceRange(sourceRng); \
return result; \
}
#define ESTREE_NODE_8_ARGS( \
NAME, \
BASE, \
ARG0TY, \
ARG0NM, \
ARG0OPT, \
ARG1TY, \
ARG1NM, \
ARG1OPT, \
ARG2TY, \
ARG2NM, \
ARG2OPT, \
ARG3TY, \
ARG3NM, \
ARG3OPT, \
ARG4TY, \
ARG4NM, \
ARG4OPT, \
ARG5TY, \
ARG5NM, \
ARG5OPT, \
ARG6TY, \
ARG6NM, \
ARG6OPT, \
ARG7TY, \
ARG7NM, \
ARG7OPT) \
if (Typename == #NAME) { \
ARG0TY arg0{}; \
ARG1TY arg1{}; \
ARG2TY arg2{}; \
ARG3TY arg3{}; \
ARG4TY arg4{}; \
ARG5TY arg5{}; \
ARG6TY arg6{}; \
ARG7TY arg7{}; \
if (!extract##ARG0TY(jsObj, #ARG0NM, arg0) && !(ARG0OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG0NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG1TY(jsObj, #ARG1NM, arg1) && !(ARG1OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG1NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG2TY(jsObj, #ARG2NM, arg2) && !(ARG2OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG2NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG3TY(jsObj, #ARG3NM, arg3) && !(ARG3OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG3NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG4TY(jsObj, #ARG4NM, arg4) && !(ARG4OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG4NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG5TY(jsObj, #ARG5NM, arg5) && !(ARG5OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG5NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG6TY(jsObj, #ARG6NM, arg6) && !(ARG6OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG6NM "' in " #NAME); \
return None; \
} \
if (!extract##ARG7TY(jsObj, #ARG7NM, arg7) && !(ARG7OPT)) { \
sm_.error(SMLoc{}, "Invalid field '" #ARG7NM "' in " #NAME); \
return None; \
} \
result = new (context_) NAME##Node( \
std::move(arg0), \
std::move(arg1), \
std::move(arg2), \
std::move(arg3), \
std::move(arg4), \
std::move(arg5), \
std::move(arg6), \
std::move(arg7)); \
result->setSourceRange(sourceRng); \
return result; \
}
#include "hermes/AST/ESTree.def"
assert(result == nullptr && "result must be returned");
sm_.error(SMLoc{}, Twine("Unknown node type '") + Typename + "'");
return None;
}