llvh::Optional ASTBuilder::build()

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;
}