/* -*- C++ -*- * Serene Programming Language * * Copyright (c) 2019-2024 Sameer Rahmani * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "serene/config.h" // for SERENE_VERSION #include "serene/jit/halley.h" // for Halley #include "serene/options.h" // for serene #include "serene/serene.h" // for applySereneCLOptions #include "serene/types/types.h" // for InternalString #include // for ParseCommandLineOptions #include // for operator<<, Error #include // for formatv, formatv_object #include // for provider_format_adapter #include // for errs, raw_ostream #include // for allocator, unique_ptr #include // for string #include // for tuple // #include "serene/jit/halley.h" // #include "serene/namespace.h" // #include "serene/reader/location.h" // #include "serene/reader/reader.h" // #include "serene/semantics.h" // #include "serene/serene.h" // #include "serene/slir/generatable.h" // #include "serene/slir/slir.h" // #include // #include // #include // #include // #include // #include // #include // #include // #include // //#include // #include // #include // #include // #include // #include // #include // #include // using namespace std; using namespace serene; namespace cl = llvm::cl; // namespace { // enum Action { // None, // DumpAST, // DumpSLIR, // DumpMLIR, // DumpSemantic, // DumpLIR, // DumpIR, // CompileToObject, // Compile, // // TODO: Remove this option and replace it by a subcommand // RunJIT, // }; // } // namespace static std::string banner = llvm::formatv("\n\nSerene Compiler Version {0}" "\nCopyright (C) 2019-2024 " "Sameer Rahmani \n" "Serene comes with ABSOLUTELY NO WARRANTY;\n" "This is free software, and you are welcome\n" "to redistribute it under certain conditions; \n" "for details take a look at the LICENSE file.\n", SERENE_VERSION); // static cl::opt inputNS(cl::Positional, cl::desc(""), // cl::Required); // static cl::opt outputFile( // "o", cl::desc("The relative path to the output file from the build dir"), // cl::init("-"), cl::value_desc("filename")); // static cl::opt // outputDir("b", cl::desc("The absolute path to the build directory"), // cl::value_desc("dir"), cl::Required); // static cl::opt emitAction( // "emit", cl::desc("Select what to dump."), cl::init(Compile), // cl::values(clEnumValN(DumpSemantic, "semantic", // "Output the AST after one level of analysis // only")), // cl::values(clEnumValN(DumpIR, "ir", "Output the lowered IR only")), // cl::values(clEnumValN(DumpSLIR, "slir", "Output the SLIR only")), // cl::values(clEnumValN(DumpMLIR, "mlir", // "Output the MLIR only (Lowered SLIR)")), // cl::values(clEnumValN(DumpLIR, "lir", // "Output the LIR only (Lowerd to LLVM dialect)")), // cl::values(clEnumValN(DumpAST, "ast", "Output the AST only")), // cl::values(clEnumValN(CompileToObject, "object", // "Compile to object file.")), // cl::values(clEnumValN(Compile, "target", // "Compile to target code. (Default)")), // cl::values(clEnumValN(RunJIT, "jit", // "Run the give input file with the JIT.")) // ); // int dumpAsObject(Namespace &ns) { // // TODO: Move the compilation process to the Namespace class // auto maybeModule = ns.compileToLLVM(); // // TODO: Fix this call to raise the wrapped error instead // if (!maybeModule) { // // TODO: Rais and error: "Faild to generato LLVM IR for namespace" // return -1; // } // auto module = std::move(maybeModule.getValue()); // auto &ctx = ns.getContext(); // // TODO: We need to set the triple data layout and everything to that sort // in // // one place. We want them for the JIT as well and also we're kinda // // duplicating what we're doing in `Namespace#compileToLLVM`. // module->setTargetTriple(ctx.targetTriple); // std::string Error; // const auto *target = // llvm::TargetRegistry::lookupTarget(ctx.targetTriple, Error); // // Print an error and exit if we couldn't find the requested target. // // This generally occurs if we've forgotten to initialise the // // TargetRegistry or we have a bogus target triple. // if (target == nullptr) { // llvm::errs() << Error; // return 1; // } // const auto *cpu = "generic"; // const auto *features = ""; // llvm::TargetOptions opt; // auto rm = std::optional(); // auto *targetMachinePtr = // target->createTargetMachine(ctx.targetTriple, cpu, features, opt, rm); // auto targetMachine = // std::unique_ptr(targetMachinePtr); // module->setDataLayout(targetMachine->createDataLayout()); // const auto *filename = // strcmp(outputFile.c_str(), "-") == 0 ? "output" : outputFile.c_str(); // std::error_code ec; // const auto pathSize(256); // llvm::SmallString destFile(outputDir); // llvm::sys::path::append(destFile, filename); // auto destObjFilePath = llvm::formatv("{0}.o", destFile).str(); // llvm::raw_fd_ostream dest(destObjFilePath, ec, llvm::sys::fs::OF_None); // if (ec) { // llvm::errs() << "Could not open file: " << destObjFilePath; // llvm::errs() << "Could not open file: " << ec.message(); // return 1; // } // llvm::legacy::PassManager pass; // auto fileType = llvm::CGFT_ObjectFile; // if (targetMachine->addPassesToEmitFile(pass, dest, nullptr, fileType)) { // llvm::errs() << "TheTargetMachine can't emit a file of this type"; // return 1; // } // pass.run(*module); // dest.flush(); // if (emitAction == Action::Compile) { // std::vector args = {"serenec"}; // args.push_back("--eh-frame-hdr"); // args.push_back("-m"); // args.push_back("elf_x86_64"); // args.push_back("-dynamic-linker"); // args.push_back("/lib64/ld-linux-x86-64.so.2"); // args.push_back( // "/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../lib64/crt1.o"); // args.push_back( // "/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../lib64/crti.o"); // args.push_back("/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/crtbegin.o"); // args.push_back("-L"); // args.push_back("/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/"); // args.push_back("-L"); // args.push_back("/usr/lib64/"); // args.push_back(destObjFilePath.c_str()); // args.push_back("-o"); // args.push_back(destFile.c_str()); // args.push_back("-lgcc"); // args.push_back("--as-needed"); // args.push_back("-lgcc_s"); // args.push_back("--no-as-needed"); // args.push_back("-lc"); // args.push_back("-lgcc"); // args.push_back("--as-needed"); // args.push_back("-lgcc_s"); // args.push_back("--no-as-needed"); // args.push_back("/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/crtend.o"); // args.push_back( // "/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../lib64/crtn.o"); // lld::elf::link(args, false, llvm::outs(), llvm::errs()); // // llvm::IntrusiveRefCntPtr opts = // // new clang::DiagnosticOptions; // // clang::DiagnosticsEngine diags( // // new clang::DiagnosticIDs, opts, // // new clang::TextDiagnosticPrinter(llvm::errs(), opts.get())); // // clang::driver::Driver d("clang", ctx.targetTriple, diags, // // "Serene compiler"); // // std::vector args = {"serenec"}; // // args.push_back(destObjFilePath.c_str()); // // args.push_back("-o"); // // args.push_back(destFile.c_str()); // // d.setCheckInputsExist(true); // // std::unique_ptr compilation; // // compilation.reset(d.BuildCompilation(args)); // // if (!compilation) { // // llvm::errs() << "can't create the compilation!\n"; // // return 1; // // } // // llvm::SmallVector> // // failCommand; // // d.ExecuteCompilation(*compilation, failCommand); // // if (failCommand.empty()) { // // llvm::outs() << "Done!\n"; // // } else { // // llvm::errs() << "Linking failed!\n"; // // failCommand.front().second->Print(llvm::errs(), "\n", false); // // } // // } // return 0; // }; int main(int argc, char *argv[]) { SERENE_INIT(); registerSereneCLOptions(); cl::ParseCommandLineOptions(argc, argv, banner); auto maybeEngine = makeEngine(); if (!maybeEngine) { llvm::errs() << "Error: Couldn't create the engine due to '" << maybeEngine.takeError() << "'\n"; return 1; } auto &engine = *maybeEngine; applySereneCLOptions(*engine); const std::string forms{"some.ns/sym"}; const types::InternalString data(forms.c_str(), forms.size()); auto err = engine->createEmptyNS("some.ns"); if (err) { llvm::errs() << "Error: " << err << "'\n"; return 1; } // err = engine->loadModule("some.ns", "/home/lxsameer/test.ll"); // if (err) { // llvm::errs() << "Error: " << err << "'\n"; // return 1; // } std::string core = "serene.core"; auto maybeCore = engine->loadNamespace(core); if (!maybeCore) { llvm::errs() << "Error: " << maybeCore.takeError() << "'\n"; return 1; } auto bt = engine->lookup("serene.core", "compile"); if (!bt) { llvm::errs() << "Error: " << bt.takeError() << "'\n"; return 1; } if (*bt == nullptr) { llvm::errs() << "Error: nullptr?\n"; return 1; } auto *c = *bt; (void)c; // void *res = c(); // // for (int i = 0; i <= 10; i++) { // // printf(">> %02x", *(c + i)); // // } // printf("Res >> %p\n", res); // llvm::outs() << "Res: " << *((int *)res) << "\n"; // (void)res; // // TODO: handle the outputDir by not forcing it. it should be // // default to the current working dir // if (outputDir == "-") { // llvm::errs() << "Error: The build directory is not set. Did you // forget to // " // "use '-b'?\n"; // return 1; // } // switch (emitAction) { // case Action::RunJIT: { // // TODO: Replace it by a proper jit configuration // ctx->setOperationPhase(CompilationPhase::NoOptimization); // break; // }; // // Just print out the raw AST // case Action::DumpAST: { // ctx->setOperationPhase(CompilationPhase::Parse); // break; // }; // case Action::DumpSemantic: { // ctx->setOperationPhase(CompilationPhase::Analysis); // break; // }; // case Action::DumpSLIR: { // ctx->setOperationPhase(CompilationPhase::SLIR); // break; // } // case Action::DumpMLIR: { // ctx->setOperationPhase(CompilationPhase::MLIR); // break; // } // case Action::DumpLIR: { // ctx->setOperationPhase(CompilationPhase::LIR); // break; // } // case Action::DumpIR: { // ctx->setOperationPhase(CompilationPhase::IR); // break; // } // case Action::CompileToObject: { // ctx->setOperationPhase(CompilationPhase::NoOptimization); // break; // } // case Action::Compile: { // ctx->setOperationPhase(CompilationPhase::NoOptimization); // break; // } // default: { // llvm::errs() << "No action specified. TODO: Print out help here\n"; // return 1; // } // } // auto runLoc = reader::LocationRange::UnknownLocation(inputNS); // auto maybeNS = ctx->importNamespace(inputNS, runLoc); // if (!maybeNS) { // auto err = maybeNS.takeError(); // throwErrors(*ctx, err); // return (int)std::errc::no_such_file_or_directory; // } // auto ns = *maybeNS; // switch (emitAction) { // case Action::DumpAST: // case Action::DumpSemantic: { // auto ast = ns->getTree(); // llvm::outs() << exprs::astToString(&ast) << "\n"; // return 0; // } // case Action::DumpSLIR: // case Action::DumpMLIR: // case Action::DumpLIR: { // ns->dump(); // break; // }; // case Action::DumpIR: { // auto maybeModule = ns->compileToLLVM(); // if (!maybeModule) { // llvm::errs() << "Failed to generate the IR.\n"; // return 1; // } // auto tsm = std::move(*maybeModule); // tsm.withModuleDo([](auto &m) { m.dump(); }); // break; // }; // // case Action::RunJIT: { // // auto maybeJIT = JIT::make(*ns); // // if (!maybeJIT) { // // // TODO: panic in here: "Couldn't creat the JIT!" // // return -1; // // } // // auto jit = std::move(maybeJIT.getValue()); // // if (jit->invoke("main")) { // // llvm::errs() << "Faild to invoke the 'main' function.\n"; // // return 1; // // } // // llvm::outs() << "Done!"; // // break; // // }; // // case Action::Compile: // // case Action::CompileToObject: { // // return dumpAsObject(*ns); // // }; // default: { // llvm::errs() << "Action is not supported yet!\n"; // }; // } return 0; }