Implement basic REPL under swift -repl. Known demo-blockers: need error recovery, need better brace/paren handling, need to implement the "print" part of REPL.

Swift SVN r1452
This commit is contained in:
Eli Friedman
2012-04-18 00:52:11 +00:00
parent ee0e03adc1
commit dc213bca76
12 changed files with 202 additions and 56 deletions

View File

@@ -16,38 +16,54 @@
//===----------------------------------------------------------------------===//
#include "Immediate.h"
#include "Frontend.h"
#include "swift/Subsystems.h"
#include "swift/IRGen/Options.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Component.h"
#include "swift/AST/Diagnostics.h"
#include "swift/AST/Module.h"
#include "swift/AST/Stmt.h"
#include "swift/Basic/DiagnosticConsumer.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/system_error.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Linker.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include <histedit.h>
#include <dlfcn.h>
static void LoadSwiftRuntime() {
// FIXME: Need error-checking.
llvm::sys::Path LibPath =
llvm::sys::Path::GetMainExecutable(0, (void*)&swift::RunImmediately);
LibPath.eraseComponent();
LibPath.eraseComponent();
LibPath.appendComponent("lib");
LibPath.appendComponent("libswift_abi.dylib");
dlopen(LibPath.c_str(), 0);
}
void swift::RunImmediately(TranslationUnit *TU) {
ASTContext &Context = TU->Ctx;
irgen::Options Options;
Options.OutputFilename = TU->Name.str();
Options.OutputFilename = "";
Options.Triple = llvm::sys::getDefaultTargetTriple();
Options.OptLevel = 0;
Options.OutputKind = irgen::OutputKind::Module;
// IRGen the main module.
llvm::LLVMContext LLVMContext;
llvm::Module Module(Options.OutputFilename, LLVMContext);
llvm::Module Module(TU->Name.str(), LLVMContext);
performCaptureAnalysis(TU);
performIRGeneration(Options, &Module, TU);
@@ -82,15 +98,7 @@ void swift::RunImmediately(TranslationUnit *TU) {
}
}
// Load the swift runtime.
// FIXME: Need error-checking.
llvm::sys::Path LibPath =
llvm::sys::Path::GetMainExecutable(0, (void*)&RunImmediately);
LibPath.eraseComponent();
LibPath.eraseComponent();
LibPath.appendComponent("lib");
LibPath.appendComponent("libswift_abi.dylib");
dlopen(LibPath.c_str(), 0);
LoadSwiftRuntime();
// Run the generated program.
@@ -101,12 +109,133 @@ void swift::RunImmediately(TranslationUnit *TU) {
std::string ErrorMsg;
builder.setErrorStr(&ErrorMsg);
builder.setEngineKind(llvm::EngineKind::JIT);
builder.setUseMCJIT(true);
llvm::ExecutionEngine *EE = builder.create();
EE->runFunctionAsMain(EntryFn, std::vector<std::string>(), 0);
}
struct InitEditLine {
EditLine *e;
InitEditLine() {
e = el_init("swift", stdin, stdout, stderr);
el_set(e, EL_EDITOR, "emacs");
char *(*PromptFn)(EditLine *) =
[](EditLine *e) { return (char*)"swift> "; };
el_set(e, EL_PROMPT, PromptFn);
}
~InitEditLine() {
el_end(e);
}
operator EditLine*() { return e; }
};
void swift::REPL(ASTContext &Context) {
// FIXME: We should do something a bit more elaborate than
// "allocate a 1MB buffer and hope it's enough".
llvm::MemoryBuffer *Buffer =
llvm::MemoryBuffer::getNewMemBuffer(1 << 20, "<REPL Buffer>");
Component *Comp = new (Context.Allocate<Component>(1)) Component();
unsigned BufferID =
Context.SourceMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
Identifier ID = Context.getIdentifier("REPL");
TranslationUnit *TU = new (Context) TranslationUnit(ID, Comp, Context,
/*IsMainModule=*/true);
llvm::SmallPtrSet<TranslationUnit*, 8> ImportedModules;
llvm::LLVMContext LLVMContext;
llvm::Module Module("REPL", LLVMContext);
LoadSwiftRuntime();
irgen::Options Options;
Options.OutputFilename = "";
Options.Triple = llvm::sys::getDefaultTargetTriple();
Options.OptLevel = 0;
Options.OutputKind = irgen::OutputKind::Module;
char* CurBuffer = const_cast<char*>(Buffer->getBufferStart());
unsigned CurBufferOffset = 0;
unsigned CurBufferEndOffset = 0;
InitEditLine e;
while (1) {
unsigned CurTUElem = TU->Body ? TU->Body->getNumElements() : 0;
int LineCount;
const char* Line = el_gets(e, &LineCount);
if (!Line)
return;
// FIXME: Should continue reading lines when there is an unbalanced
// brace/paren/bracket.
strcpy(CurBuffer, Line);
CurBuffer += strlen(Line);
*CurBuffer++ = '\n';
CurBufferEndOffset += strlen(Line) + 1;
swift::appendToMainTranslationUnit(TU, BufferID, CurBufferOffset,
CurBufferEndOffset);
// FIXME: Better error recovery would be really nice here.
if (Context.hadError())
return;
// IRGen the main module.
performCaptureAnalysis(TU, CurTUElem);
performIRGeneration(Options, &Module, TU, CurTUElem);
if (Context.hadError())
return;
// IRGen the modules this module depends on.
for (auto ModPair : TU->getImportedModules()) {
if (isa<BuiltinModule>(ModPair.second))
continue;
TranslationUnit *SubTU = cast<TranslationUnit>(ModPair.second);
if (!ImportedModules.insert(SubTU))
continue;
// FIXME: Need to check whether this is actually safe in general.
llvm::Module SubModule(SubTU->Name.str(), LLVMContext);
performCaptureAnalysis(SubTU);
performIRGeneration(Options, &SubModule, SubTU);
if (Context.hadError())
return;
std::string ErrorMessage;
if (llvm::Linker::LinkModules(&Module, &SubModule,
llvm::Linker::DestroySource,
&ErrorMessage)) {
llvm::errs() << "Error linking swift modules\n";
llvm::errs() << ErrorMessage << "\n";
return;
}
}
// The way we do this is really ugly... we should be able to improve this.
llvm::Function *EntryFn = Module.getFunction("main");
{
llvm::EngineBuilder builder(&Module);
std::string ErrorMsg;
builder.setErrorStr(&ErrorMsg);
builder.setEngineKind(llvm::EngineKind::JIT);
llvm::ExecutionEngine *EE = builder.create();
EE->runFunctionAsMain(EntryFn, std::vector<std::string>(), 0);
}
EntryFn->eraseFromParent();
}
}
// FIXME: We shouldn't be writing implemenetations for functions in the swift
// module in C, and this isn't really an ideal place to put those
// implementations.
@@ -118,7 +247,7 @@ extern "C" void _TSs5printFT3valNSs6Double_T_(double l) {
printf("%f", l);
}
extern "C" void __TSs9printCharFT9characterNSs5Int64_T_(int64_t l) {
extern "C" void _TSs9printCharFT9characterNSs5Int64_T_(int64_t l) {
printf("%c", (char)l);
}
@@ -130,6 +259,6 @@ extern "C" bool _TNSs4Bool13getLogicValuefRS_FT_i1(bool* b) {
return *b;
}
extern "C" void _TSs4exitFT8exitCodeNSs5int64_T_(int64_t l) {
extern "C" void _TSs4exitFT8exitCodeNSs5Int64_T_(int64_t l) {
exit(l);
}