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; }
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; }
// 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); } }
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_); }
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; }