Esempio n. 1
0
File: VM.cpp Progetto: relrod/magpie
  bool VM::initRepl()
  {
    ErrorReporter reporter;
    Module* core = addModule(reporter, String::create("core"), NULL);
    if (reporter.numErrors() > 0) return false;
    if (!core->compile(*this)) return false;
    scheduler_.runModule(core);

    return true;
  }
Esempio n. 2
0
  bool Module::compile(VM& vm)
  {
    ASSERT(!ast_.isNull(), "Must parse module before compiling.");

    ErrorReporter reporter;
    Compiler::compileModule(vm, reporter, ast_, this);

    // Now that we've compiled it, we can throw away the AST.
    ast_ = NULL;

    return reporter.numErrors() == 0;
  }
Esempio n. 3
0
  // TODO: hacky, parses arbitrary code string into a module
  void ParserTests::testCode(const char* sourceString, const char* expected)
  {
    gc<String> code = String::create(sourceString);
    ErrorReporter reporter;
    gc<SourceFile> source = new SourceFile(String::create("<file>"), code);
    Parser parser(source, reporter);
    gc<ModuleAst> module = parser.parseModule();

    int numErrors = reporter.numErrors();

    EXPECT_EQUAL(0, numErrors);

    if (numErrors == 0) {
        gc<String> text = module->body()->toString();
        EXPECT_EQUAL(expected, *text);
    }
  }
Esempio n. 4
0
File: VM.cpp Progetto: relrod/magpie
  gc<Object> VM::evaluateReplExpression(gc<Expr> expr)
  {
    ErrorReporter reporter;

    if (replModule_ == NULL)
    {
      replModule_ = new Module(String::create("<repl>"), String::create(""));
      modules_.add(replModule_);

      // Implicitly import core.
      importModule(reporter, replModule_, NULL, String::create("core"));
    }

    // Compile it.
    Compiler::compileExpression(*this, reporter, expr, replModule_);
    if (reporter.numErrors() > 0) return gc<Object>();

    return scheduler_.runModule(replModule_);
  }
Esempio n. 5
0
File: VM.cpp Progetto: relrod/magpie
  bool VM::runProgram(gc<String> path)
  {
    // Remember where the program is so we can import modules from there.
    programDir_ = path::dir(path::real(path));

    // Traverse the import graph.
    ErrorReporter reporter;
    addModule(reporter, NULL, path);
    if (reporter.numErrors() > 0) return false;

    // Sort the modules by their imports so that dependencies are run before
    // modules that depend on them.
    // See: http://en.wikipedia.org/wiki/Topological_sorting
    // Clone the import graph so we can destructively modify it.
    // TODO(bob): This does lots of array copies since ImportGraph stores an
    // array directly. Do something smarter here.
    Array<ImportGraph> graph;
    for (int i = 0; i < modules_.count(); i++)
    {
      graph.add(ImportGraph(modules_[i]));
    }

    Array<Module*> modules;
    while (graph.count() > 0)
    {
      bool madeProgress = false;
      for (int i = 0; i < graph.count(); i++)
      {
        // See if all of this module's imports are accounted for.
        if (graph[i].imports.count() == 0)
        {
          // They are, so it's ready to process.
          modules.add(graph[i].module);

          // And now everything that imports it doesn't have to worry about it
          // anymore.
          for (int j = 0; j < graph.count(); j++)
          {
            for (int k = 0; k < graph[j].imports.count(); k++)
            {
              if (graph[j].imports[k] == graph[i].module)
              {
                graph[j].imports.removeAt(k);
                k--;
              }
            }
          }

          graph.removeAt(i);
          i--;
          madeProgress = true;
        }
      }

      // Bail if there is an import cycle.
      // TODO(bob): Better error-handling.
      if (!madeProgress) return false;
    }

    // Compile all modules before running any of them.
    for (int i = 0; i < modules.count(); i++)
    {
      if (!modules[i]->compile(*this)) return false;
    }

    scheduler_.run(modules);
    return true;
  }