Ejemplo n.º 1
0
/** Statically analyse the given ast.
 *
 * \param ast_ The AST.
 * \param in_object Whether or not ast_ is within the lexical scope of an object AST.
 * \param vars The variables defined within lexical scope of ast_.
 * \returns The free variables in ast_.
 */
static IdSet static_analysis(AST *ast_, bool in_object, const IdSet &vars)
{
    IdSet r;

    if (auto *ast = dynamic_cast<const Apply*>(ast_)) {
        append(r, static_analysis(ast->target, in_object, vars));
        for (AST *arg : ast->arguments)
            append(r, static_analysis(arg, in_object, vars));

    } else if (auto *ast = dynamic_cast<const Array*>(ast_)) {
        for (AST *el : ast->elements)
            append(r, static_analysis(el, in_object, vars));

    } else if (auto *ast = dynamic_cast<const Binary*>(ast_)) {
        append(r, static_analysis(ast->left, in_object, vars));
        append(r, static_analysis(ast->right, in_object, vars));

    } else if (dynamic_cast<const BuiltinFunction*>(ast_)) {
        // Nothing to do.

    } else if (auto *ast = dynamic_cast<const Conditional*>(ast_)) {
        append(r, static_analysis(ast->cond, in_object, vars));
        append(r, static_analysis(ast->branchTrue, in_object, vars));
        append(r, static_analysis(ast->branchFalse, in_object, vars));

    } else if (auto *ast = dynamic_cast<const Error*>(ast_)) {
        return static_analysis(ast->expr, in_object, vars);

    } else if (auto *ast = dynamic_cast<const Function*>(ast_)) {
        auto new_vars = vars;
        IdSet params;
        for (auto *p : ast->parameters) {
            if (params.find(p) != params.end()) {
                throw StaticError(ast_->location, "Duplicate function parameter: " + p->name);
            }
            params.insert(p);
            new_vars.insert(p);
        }
        auto fv = static_analysis(ast->body, in_object, new_vars);
        for (auto *p : ast->parameters)
            fv.erase(p);
        append(r, fv);

    } else if (dynamic_cast<const Import*>(ast_)) {
        // Nothing to do.

    } else if (dynamic_cast<const Importstr*>(ast_)) {
        // Nothing to do.

    } else if (auto *ast = dynamic_cast<const Index*>(ast_)) {
        append(r, static_analysis(ast->target, in_object, vars));
        append(r, static_analysis(ast->index, in_object, vars));

    } else if (auto *ast = dynamic_cast<const Local*>(ast_)) {
        IdSet ast_vars;
        for (const auto &bind: ast->binds) {
            ast_vars.insert(bind.first);
        }
        auto new_vars = vars;
        append(new_vars, ast_vars);
        IdSet fvs;
        for (const auto &bind: ast->binds)
            append(fvs, static_analysis(bind.second, in_object, new_vars));

        append(fvs, static_analysis(ast->body, in_object, new_vars));

        for (const auto &bind: ast->binds)
            fvs.erase(bind.first);

        append(r, fvs);

    } else if (dynamic_cast<const LiteralBoolean*>(ast_)) {
        // Nothing to do.

    } else if (dynamic_cast<const LiteralNumber*>(ast_)) {
        // Nothing to do.

    } else if (dynamic_cast<const LiteralString*>(ast_)) {
        // Nothing to do.

    } else if (dynamic_cast<const LiteralNull*>(ast_)) {
        // Nothing to do.

    } else if (auto *ast = dynamic_cast<Object*>(ast_)) {
        for (auto field : ast->fields) {
            append(r, static_analysis(field.name, in_object, vars));
            append(r, static_analysis(field.body, true, vars));
        }

    } else if (auto *ast = dynamic_cast<ObjectComposition*>(ast_)) {
        auto new_vars = vars;
        new_vars.insert(ast->id);
        append(r, static_analysis(ast->field, false, new_vars));
        append(r, static_analysis(ast->value, true, new_vars));
        r.erase(ast->id);
        append(r, static_analysis(ast->array, in_object, vars));

    } else if (dynamic_cast<const Self*>(ast_)) {
        if (!in_object)
            throw StaticError(ast_->location, "Can't use self outside of an object.");

    } else if (dynamic_cast<const Super*>(ast_)) {
        if (!in_object)
            throw StaticError(ast_->location, "Can't use super outside of an object.");

    } else if (auto *ast = dynamic_cast<const Unary*>(ast_)) {
        append(r, static_analysis(ast->expr, in_object, vars));

    } else if (auto *ast = dynamic_cast<const Var*>(ast_)) {
        if (vars.find(ast->id) == vars.end()) {
            throw StaticError(ast->location, "Unknown variable: "+ast->id->name);
        }
        r.insert(ast->id);

    } else {
        std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl;
        std::abort();

    }

    for (auto *id : r)
        ast_->freeVariables.push_back(id);

    return r;
}
Ejemplo n.º 2
0
bool listAllSeries(const std::string& rootCategory, const std::string& outputFile) {
  bool result(false);

  using namespace fredcpp;

  // Initialize

  Api api;
  api.withLogger(external::SimpleLogger::getInstance())
     .withExecutor(external::CurlHttpClient::getInstance())
     .withParser(external::PugiXmlParser::getInstance())
     ;

  external::SimpleLogger::getInstance().enableInfo();

  FREDCPP_LOG_INFO(FREDCPP_FACILITY << " version " << FREDCPP_VERSION_STRING
     << " (" << FREDCPP_BRIEF  << ")");

  FREDCPP_LOG_INFO("Getting API key from environment variable " << ENV_API_KEY << " ...");
  api.withKey(getKeyFromEnv(ENV_API_KEY));


  // Build a list of available sub-categories under the root

  FREDCPP_LOG_INFO("Building list of available sub-categories of category " << rootCategory << " ...");

  ChildrenByIdMap categoryTree;
  if ( 0 == buildCategoryTree(api, categoryTree, rootCategory)) {
    FREDCPP_LOG_FATAL("Unable to retrieve categories");
    exit(EXIT_FAILURE);
  }

  FREDCPP_LOG_INFO("Available categories count:" << categoryTree.size());


  FREDCPP_LOG_INFO("Creating output data file " << outputFile << " ...");
  std::ofstream output(outputFile.c_str());

  if (!output) {
    exitOnBadOutputFile(outputFile);
  }


  // Get series

  IdSet uniqueSeries;
  ApiResponse response;

  for (ChildrenByIdMap::iterator it = categoryTree.begin();
       it != categoryTree.end();
       ++it) {
    std::string categoryId(it->first);

    api.get(ApiRequestBuilder::CategorySeries(categoryId)
            , response) || exitOnApiError(response);

    if (!response.entities.size()) {
      FREDCPP_LOG_INFO("category:" << categoryId << " contains no series");
    }

    // Print series

    // NOTE: a given series can belong to multiple categories,
    // so keep track of unique series

    for (std::size_t n = 0; n < response.entities.size(); ++n) {

      std::string seriesId (response.entities[n].attribute("id"));

      if (uniqueSeries.find(seriesId) != uniqueSeries.end()) {
        continue;
      }

      uniqueSeries.insert(seriesId);

      output << response.entities[n].attribute("id")
             << "|" << response.entities[n].attribute("frequency_short")
             << "|" << response.entities[n].attribute("title")
             << "|" << response.entities[n].attribute("observation_start")
             << "|" << response.entities[n].attribute("observation_end")
             << "|"
             << std::endl;
    }
  }


  // Report stats

  FREDCPP_LOG_INFO("root-category:" << rootCategory
                   << " sub-categories-count:" << categoryTree.size() - 1
                   << " series-count:" << uniqueSeries.size());


  output.close();

  FREDCPP_LOG_INFO("Successfully created file " << outputFile);

  result = true;
  return (result);

}