From 16d8faa31adcd5cba6aac76dfc73e72251e85c92 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Wed, 10 Dec 2025 19:39:41 -0500 Subject: [PATCH 01/56] Update header to and use `const`. --- compiler/parachute.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/parachute.cpp b/compiler/parachute.cpp index 308312cb..6bb047c2 100644 --- a/compiler/parachute.cpp +++ b/compiler/parachute.cpp @@ -55,13 +55,13 @@ namespace clay { // Signal parachute -#include +#include namespace clay { static volatile int threatLevel = 0; - static void emergencyCompileContext(int sig) { - int oldThreatLevel = __sync_fetch_and_add(&threatLevel, 1); + static void emergencyCompileContext(const int sig) { + const int oldThreatLevel = __sync_fetch_and_add(&threatLevel, 1); if (oldThreatLevel == 0) { fprintf(stderr, "signal %d!\n", sig); displayCompileContext(); From 2f3625cb691d608ee9afa584a2fac5d83aec62ad Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Wed, 10 Dec 2025 21:45:52 -0500 Subject: [PATCH 02/56] Remove deprecated Path from RemoveFileOnSignal --- compiler/clay.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/clay.cpp b/compiler/clay.cpp index 6a034da0..3b1b4efe 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -311,7 +311,7 @@ namespace clay { llvm::errs() << "error creating temporary object file: " << ec.message() << '\n'; return false; } - llvm::sys::RemoveFileOnSignal(llvm::sys::Path(tempObj)); + llvm::sys::RemoveFileOnSignal(tempObj); { llvm::raw_fd_ostream objOut(fd, /*shouldClose=*/ true); @@ -1024,7 +1024,7 @@ namespace clay { llvm::errs() << "error: output file '" << outputFile << "' is a directory\n"; return 1; } - llvm::sys::RemoveFileOnSignal(llvm::sys::Path(outputFile)); + llvm::sys::RemoveFileOnSignal(outputFile); } if (generateDeps) { @@ -1044,7 +1044,7 @@ namespace clay { llvm::errs() << "error: dependencies output file '" << dependenciesOutputFile << "' is a directory\n"; return 1; } - llvm::sys::RemoveFileOnSignal(llvm::sys::Path(dependenciesOutputFile)); + llvm::sys::RemoveFileOnSignal(dependenciesOutputFile); } HiResTimer loadTimer, compileTimer, optTimer, outputTimer; From d4ad0f3aba06d129b68e78de6c0520d8658a3be3 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Wed, 10 Dec 2025 21:47:37 -0500 Subject: [PATCH 03/56] Update generateBinary and helper to modern LLVM --- compiler/clay.cpp | 54 +++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/compiler/clay.cpp b/compiler/clay.cpp index 3b1b4efe..ffa5cfb7 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -28,8 +28,8 @@ namespace clay { using namespace std; - static void addOptimizationPasses(llvm::legacy::PassManager &passes, - llvm::legacy::FunctionPassManager &fpasses, + static void addOptimizationPasses(llvm::PassManager &passes, + llvm::FunctionPassManager &fpasses, unsigned optLevel, bool internalize) { llvm::Pass *inliningPass = 0; @@ -280,18 +280,14 @@ namespace clay { fpasses.doFinalization(); } - static string joinCmdArgs(llvm::ArrayRef args) { + static string joinCmdArgs(llvm::ArrayRef args) { string s; llvm::raw_string_ostream ss(s); - for (char const *const *arg = args.begin(); - arg != args.end(); ++arg) { - if (arg != args.begin()) { + for (const llvm::StringRef &arg : args) { + if (&arg != args.begin()) { ss << " "; } - if (*arg == 0 && arg + 1 == args.end()) { - continue; - } - ss << *arg; + ss << arg; } return s; } @@ -299,7 +295,7 @@ namespace clay { static bool generateBinary(llvm::Module *module, llvm::TargetMachine *targetMachine, llvm::Twine const &outputFilePath, - llvm::sys::Path const &clangPath, + llvm::StringRef const &clangPath, bool /*exceptions*/, bool sharedLib, bool debug, @@ -307,7 +303,7 @@ namespace clay { bool verbose) { int fd; PathString tempObj; - if (llvm::error_code ec = llvm::sys::fs::unique_file("clayobj-%%%%%%%%.obj", fd, tempObj)) { + if (std::error_code ec = llvm::sys::fs::createUniqueFile("clayobj-%%%%%%%%.obj", fd, tempObj)) { llvm::errs() << "error creating temporary object file: " << ec.message() << '\n'; return false; } @@ -321,8 +317,8 @@ namespace clay { string outputFilePathStr = outputFilePath.str(); - vector clangArgs; - clangArgs.push_back(clangPath.c_str()); + std::vector clangArgs; + clangArgs.push_back(clangPath.data()); switch (llvmDataLayout->getPointerSizeInBits()) { case 32: @@ -340,8 +336,7 @@ namespace clay { if (sharedLib) { clangArgs.push_back("-shared"); - if (triple.getOS() == llvm::Triple::MinGW32 - || triple.getOS() == llvm::Triple::Cygwin) { + if (triple.isOSWindows()) { PathString defPath; outputFilePath.toVector(defPath); llvm::sys::path::replace_extension(defPath, "def"); @@ -356,39 +351,44 @@ namespace clay { clangArgs.push_back("-Wl,/debug"); } clangArgs.push_back("-o"); - clangArgs.push_back(outputFilePathStr.c_str()); - clangArgs.push_back(tempObj.c_str()); + clangArgs.push_back(outputFilePathStr); + clangArgs.push_back(tempObj); for (unsigned i = 0; i < arguments.size(); ++i) clangArgs.push_back(arguments[i].c_str()); - clangArgs.push_back(nullptr); if (verbose) { llvm::errs() << "executing clang to generate binary:\n"; llvm::errs() << " " << joinCmdArgs(clangArgs) << "\n"; } - int result = llvm::sys::Program::ExecuteAndWait(clangPath, &clangArgs[0]); + int result = llvm::sys::ExecuteAndWait(clangPath, clangArgs); + + if (debug && triple.isOSDarwin()) { + llvm::ErrorOr DsymutilPathOrErr = llvm::sys::findProgramByName("dsymutil"); + if (std::error_code EC = DsymutilPathOrErr.getError()) + llvm::errs() << "error creating dsymutil: " << EC.message() << '\n'; if (debug && triple.getOS() == llvm::Triple::Darwin) { llvm::sys::Path dsymutilPath = llvm::sys::Program::FindProgramByName("dsymutil"); if (dsymutilPath.isValid()) { + std::string dsymutilPath = DsymutilPathOrErr ? *DsymutilPathOrErr : ""; + + if (!dsymutilPath.empty()) { string outputDSYMPath = outputFilePathStr; outputDSYMPath.append(".dSYM"); - vector dsymutilArgs; - dsymutilArgs.push_back(dsymutilPath.c_str()); + std::vector dsymutilArgs; + dsymutilArgs.push_back(dsymutilPath); dsymutilArgs.push_back("-o"); - dsymutilArgs.push_back(outputDSYMPath.c_str()); - dsymutilArgs.push_back(outputFilePathStr.c_str()); - dsymutilArgs.push_back(nullptr); + dsymutilArgs.push_back(outputDSYMPath); + dsymutilArgs.push_back(outputFilePathStr); if (verbose) { llvm::errs() << "executing dsymutil:"; llvm::errs() << " " << joinCmdArgs(dsymutilArgs) << "\n"; } - int dsymResult = llvm::sys::Program::ExecuteAndWait(dsymutilPath, - &dsymutilArgs[0]); + int dsymResult = llvm::sys::ExecuteAndWait(dsymutilPath, dsymutilArgs); if (dsymResult != 0) llvm::errs() << "warning: dsymutil exited with error code " << dsymResult << "\n"; From fc70c2e39848082fd5564cdf2ed5c5b693e50fe5 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Wed, 10 Dec 2025 21:47:49 -0500 Subject: [PATCH 04/56] Add header files --- compiler/clay.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/compiler/clay.cpp b/compiler/clay.cpp index ffa5cfb7..1705aa54 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -1,3 +1,19 @@ +#include +#include +#include +#include +#include +#include "llvm/Support/DynamicLibrary.h" +#include +#include +#include +#include +#include +#include + +#include +#include + #include "clay.hpp" #include "hirestimer.hpp" #include "error.hpp" @@ -368,9 +384,6 @@ namespace clay { if (std::error_code EC = DsymutilPathOrErr.getError()) llvm::errs() << "error creating dsymutil: " << EC.message() << '\n'; - if (debug && triple.getOS() == llvm::Triple::Darwin) { - llvm::sys::Path dsymutilPath = llvm::sys::Program::FindProgramByName("dsymutil"); - if (dsymutilPath.isValid()) { std::string dsymutilPath = DsymutilPathOrErr ? *DsymutilPathOrErr : ""; if (!dsymutilPath.empty()) { From bb45fb6a8743e8fd6ffd43d2c528581cc9b9b0c3 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Wed, 10 Dec 2025 21:48:18 -0500 Subject: [PATCH 05/56] Use modern versions to find OS type --- compiler/clay.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/compiler/clay.cpp b/compiler/clay.cpp index 1705aa54..1757834b 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -479,33 +479,27 @@ namespace clay { } static string sharedExtensionForTarget(llvm::Triple const &triple) { - if (triple.getOS() == llvm::Triple::Win32 - || triple.getOS() == llvm::Triple::MinGW32 - || triple.getOS() == llvm::Triple::Cygwin) { + if (triple.isOSWindows()) { return ".dll"; - } else if (triple.getOS() == llvm::Triple::Darwin) { + } + if (triple.isOSDarwin()) { return ".dylib"; - } else { - return ".so"; } + return ".so"; } static string objExtensionForTarget(llvm::Triple const &triple) { - if (triple.getOS() == llvm::Triple::Win32) { + if (triple.isOSWindows()) { return ".obj"; - } else { - return ".o"; } + return ".o"; } static string exeExtensionForTarget(llvm::Triple const &triple) { - if (triple.getOS() == llvm::Triple::Win32 - || triple.getOS() == llvm::Triple::MinGW32 - || triple.getOS() == llvm::Triple::Cygwin) { + if (triple.isOSWindows()) { return ".exe"; - } else { - return ""; } + return ""; } static void printVersion() { From 85052ef3c781155d8bb5e84df6a90b03d3d56585 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Wed, 10 Dec 2025 21:51:21 -0500 Subject: [PATCH 06/56] Use getMainExecutable from filesystem --- compiler/clay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/clay.cpp b/compiler/clay.cpp index 1757834b..4d2519b1 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -983,7 +983,7 @@ namespace clay { } while (*end); } // Add the relative path from the executable - PathString clayExe(llvm::sys::Path::GetMainExecutable(argv[0], (void *) (uintptr_t) &usage).c_str()); + PathString clayExe(llvm::sys::fs::getMainExecutable(argv[0], (void *) (uintptr_t) &usage)); llvm::StringRef clayDir = llvm::sys::path::parent_path(clayExe); PathString libDirDevelopment(clayDir); From 0e6d332e892bb3decf46a5ecb22e011fc5272830 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Wed, 10 Dec 2025 22:05:17 -0500 Subject: [PATCH 07/56] Remove the temporary object from generateBinary --- compiler/clay.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/clay.cpp b/compiler/clay.cpp index 4d2519b1..cdb51c84 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -323,7 +324,7 @@ namespace clay { llvm::errs() << "error creating temporary object file: " << ec.message() << '\n'; return false; } - llvm::sys::RemoveFileOnSignal(tempObj); + llvm::FileRemover removeTempObj(tempObj); { llvm::raw_fd_ostream objOut(fd, /*shouldClose=*/ true); @@ -410,9 +411,6 @@ namespace clay { "warning: unable to find dsymutil on the path; debug info for executable will not be generated\n"; } - bool dontcare; - llvm::sys::fs::remove(llvm::StringRef(tempObj), dontcare); - return (result == 0); } From 32fe90b53fc05cfca6f360d10d0bc4c4ca54a92e Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Wed, 10 Dec 2025 22:28:59 -0500 Subject: [PATCH 08/56] Use modern features of C++ --- compiler/clay.cpp | 103 ++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 54 deletions(-) diff --git a/compiler/clay.cpp b/compiler/clay.cpp index cdb51c84..7f562c7b 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -49,7 +49,7 @@ namespace clay { llvm::FunctionPassManager &fpasses, unsigned optLevel, bool internalize) { - llvm::Pass *inliningPass = 0; + llvm::Pass *inliningPass = nullptr; if (optLevel > 1) { int threshold = 225; if (optLevel > 2) @@ -160,11 +160,11 @@ namespace clay { llvm::ArrayRef libs) { if (libs.empty()) return true; + llvm::Linker linker("clay", llvmModule, llvm::Linker::Verbose); linker.addSystemPaths(); linker.addPaths(libSearchPaths); - for (size_t i = 0; i < libs.size(); ++i) { - string lib = libs[i]; + for (auto lib : libs) { llvmModule->addLibrary(lib); //as in cling/lib/Interpreter/Interpreter.cpp bool isNative = true; @@ -202,11 +202,9 @@ namespace clay { bool hasError = llvm::sys::DynamicLibrary ::LoadLibraryPermanently(SoFile.str().c_str(), &errMsg); if (hasError) { - if (hasError) { - llvm::errs() << "Couldn't load shared library " << lib << "\n" << errMsg.c_str(); - linker.releaseModule(); - return false; - } + llvm::errs() << "Couldn't load shared library " << lib << "\n" << errMsg.c_str(); + linker.releaseModule(); + return false; } } } @@ -242,7 +240,7 @@ namespace clay { llvm::PassManager passes; string moduleDataLayout = module->getDataLayout(); - llvm::DataLayout *dl = new llvm::DataLayout(moduleDataLayout); + auto *dl = new llvm::DataLayout(moduleDataLayout); passes.add(dl); llvm::FunctionPassManager fpasses(module); @@ -252,9 +250,8 @@ namespace clay { addOptimizationPasses(passes, fpasses, optLevel, internalize); fpasses.doInitialization(); - for (llvm::Module::iterator i = module->begin(), e = module->end(); - i != e; ++i) { - fpasses.run(*i); + for (auto & i : *module) { + fpasses.run(i); } passes.add(llvm::createVerifierPass()); @@ -290,15 +287,15 @@ namespace clay { assert(!result); fpasses.doInitialization(); - for (llvm::Module::iterator i = module->begin(), e = module->end(); - i != e; ++i) { - fpasses.run(*i); + for (auto & i : *module) { + fpasses.run(i); } fpasses.doFinalization(); } - static string joinCmdArgs(llvm::ArrayRef args) { - string s; + [[maybe_unused]] static std::string joinCmdArgs(llvm::ArrayRef args) + { + std::string s; llvm::raw_string_ostream ss(s); for (const llvm::StringRef &arg : args) { if (&arg != args.begin()) { @@ -335,43 +332,43 @@ namespace clay { string outputFilePathStr = outputFilePath.str(); std::vector clangArgs; - clangArgs.push_back(clangPath.data()); + clangArgs.emplace_back(clangPath.data()); switch (llvmDataLayout->getPointerSizeInBits()) { case 32: - clangArgs.push_back("-m32"); + clangArgs.emplace_back("-m32"); break; case 64: - clangArgs.push_back("-m64"); + clangArgs.emplace_back("-m64"); break; default: assert(false); } llvm::Triple triple(llvmModule->getTargetTriple()); - string linkerFlags; if (sharedLib) { - clangArgs.push_back("-shared"); + clangArgs.emplace_back("-shared"); if (triple.isOSWindows()) { + string linkerFlags; PathString defPath; outputFilePath.toVector(defPath); llvm::sys::path::replace_extension(defPath, "def"); linkerFlags = "-Wl,--output-def," + string(defPath.begin(), defPath.end()); - clangArgs.push_back(linkerFlags.c_str()); + clangArgs.emplace_back(linkerFlags); } } if (debug) { if (triple.getOS() == llvm::Triple::Win32) - clangArgs.push_back("-Wl,/debug"); + clangArgs.emplace_back("-Wl,/debug"); } - clangArgs.push_back("-o"); - clangArgs.push_back(outputFilePathStr); + clangArgs.emplace_back("-o"); + clangArgs.emplace_back(outputFilePathStr); clangArgs.push_back(tempObj); - for (unsigned i = 0; i < arguments.size(); ++i) - clangArgs.push_back(arguments[i].c_str()); + for (const auto & argument : arguments) + clangArgs.emplace_back(argument); if (verbose) { llvm::errs() << "executing clang to generate binary:\n"; @@ -392,10 +389,10 @@ namespace clay { outputDSYMPath.append(".dSYM"); std::vector dsymutilArgs; - dsymutilArgs.push_back(dsymutilPath); - dsymutilArgs.push_back("-o"); - dsymutilArgs.push_back(outputDSYMPath); - dsymutilArgs.push_back(outputFilePathStr); + dsymutilArgs.emplace_back(dsymutilPath); + dsymutilArgs.emplace_back("-o"); + dsymutilArgs.emplace_back(outputDSYMPath); + dsymutilArgs.emplace_back(outputFilePathStr); if (verbose) { llvm::errs() << "executing dsymutil:"; @@ -414,7 +411,7 @@ namespace clay { return (result == 0); } - static void usage(char *argv0) { + static void usage(const char *argv0) { llvm::errs() << "usage: " << argv0 << " \n"; llvm::errs() << " " << argv0 << " -e \n"; llvm::errs() << "options:\n"; @@ -630,7 +627,7 @@ namespace clay { if (dot == nullptr) { logMatchSymbols.insert(make_pair(string("*"), argv[i])); } else { - logMatchSymbols.insert(make_pair(string((char const *) argv[i], dot), string(dot + 1))); + logMatchSymbols.insert(make_pair(string(static_cast(argv[i]), dot), string(dot + 1))); } } else if (strcmp(argv[i], "-e") == 0) { if (i + 1 == argc) { @@ -832,7 +829,7 @@ namespace clay { return 1; } } - searchPath.push_back(PathString(path)); + searchPath.emplace_back(path); } else if (strstr(argv[i], "-version") == argv[i] || strcmp(argv[i], "--version") == 0) { printVersion(); @@ -964,24 +961,23 @@ namespace clay { initExternalTarget(targetTriple); // Try environment variables first - char *libclayPath = getenv("CLAY_PATH"); - if (libclayPath) { + if (char *libclayPath = getenv("CLAY_PATH")) { // Parse the environment variable - // Format expected is standard PATH form, i.e - // CLAY_PATH=path1:path2:path3 (on unix) - // CLAY_PATH=path1;path2;path3 (on windows) + // Format expected is standard PATH form, i.e. + // CLAY_PATH=path1:path2:path3 (on Unix) + // CLAY_PATH=path1;path2;path3 (on Windows) char *begin = libclayPath; char *end; do { end = begin; while (*end && (*end != ENV_SEPARATOR)) ++end; - searchPath.push_back(llvm::StringRef(begin, (size_t) (end - begin))); + searchPath.emplace_back(llvm::StringRef(begin, static_cast(end - begin))); begin = end + 1; } while (*end); } // Add the relative path from the executable - PathString clayExe(llvm::sys::fs::getMainExecutable(argv[0], (void *) (uintptr_t) &usage)); + PathString clayExe(llvm::sys::fs::getMainExecutable(argv[0], reinterpret_cast(&usage))); llvm::StringRef clayDir = llvm::sys::path::parent_path(clayExe); PathString libDirDevelopment(clayDir); @@ -995,14 +991,13 @@ namespace clay { searchPath.push_back(libDirDevelopment); searchPath.push_back(libDirProduction1); searchPath.push_back(libDirProduction2); - searchPath.push_back(PathString(".")); + searchPath.emplace_back("."); if (verbose) { llvm::errs() << "using search path:\n"; - for (std::vector::const_iterator it = searchPath.begin(); - it != searchPath.end(); ++it) { - llvm::errs() << " " << *it << "\n"; + for (const auto & it : searchPath) { + llvm::errs() << " " << it << "\n"; } } @@ -1061,9 +1056,9 @@ namespace clay { initLoader(); ModulePtr m; - string clayScriptSource; vector sourceFiles; if (!clayScript.empty()) { + string clayScriptSource; clayScriptSource = clayScriptImports + "main() {\n" + clayScript + "}"; m = loadProgramSource("-e", clayScriptSource, verbose, repl); } else if (generateDeps) @@ -1111,9 +1106,9 @@ namespace clay { optTimer.stop(); if (run) { - vector argv; - argv.push_back(clayFile); - runModule(llvmModule, argv, envp, libSearchPath, libraries); + vector runArgs; + runArgs.push_back(clayFile); + runModule(llvmModule, runArgs, envp, libSearchPath, libraries); } else if (repl) { linkLibraries(llvmModule, libSearchPath, libraries); runInteractive(llvmModule, m); @@ -1175,10 +1170,10 @@ namespace clay { return 1; } if (showTiming) { - llvm::errs() << "load time = " << (size_t) loadTimer.elapsedMillis() << " ms\n"; - llvm::errs() << "compile time = " << (size_t) compileTimer.elapsedMillis() << " ms\n"; - llvm::errs() << "optimization time = " << (size_t) optTimer.elapsedMillis() << " ms\n"; - llvm::errs() << "codegen time = " << (size_t) outputTimer.elapsedMillis() << " ms\n"; + llvm::errs() << "load time = " << static_cast(loadTimer.elapsedMillis()) << " ms\n"; + llvm::errs() << "compile time = " << static_cast(compileTimer.elapsedMillis()) << " ms\n"; + llvm::errs() << "optimization time = " << static_cast(optTimer.elapsedMillis()) << " ms\n"; + llvm::errs() << "codegen time = " << static_cast(outputTimer.elapsedMillis()) << " ms\n"; llvm::errs().flush(); } From 9016c7198360f050f3ca58335c18f861519ab188 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Wed, 10 Dec 2025 22:31:24 -0500 Subject: [PATCH 09/56] Remove namespace to std and use C++ iostream --- compiler/ut_main.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/compiler/ut_main.cpp b/compiler/ut_main.cpp index 6ba1cfb8..f91ae7aa 100644 --- a/compiler/ut_main.cpp +++ b/compiler/ut_main.cpp @@ -1,36 +1,35 @@ +#include #include #include "ut.hpp" #include "parachute.hpp" -using namespace std; - namespace clay { struct Test { const char *name; TestFunc func; }; - static vector *tests; + static std::vector *tests; void register_test(const char *name, const TestFunc func) { if (tests == nullptr) { - tests = new vector; + tests = new std::vector; } - tests->push_back(Test()); + tests->emplace_back(); tests->back().name = name; tests->back().func = func; } int real_main(int argc, char **argv, char const *const *envp) { for (const auto test : *tests) { - printf("%s...\n", test.name); + std::cout << test.name << "...\n"; try { test.func(); - printf("%s OK\n", test.name); + std::cout << test.name << " OK\n"; } catch (const AssertionError &) { - printf("%s FAILED\n", test.name); + std::cout << test.name << " FAILED\n"; } } return 0; From fae00b5a23285cf47143ee6d2cee863f86a3e1d7 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Wed, 10 Dec 2025 22:31:52 -0500 Subject: [PATCH 10/56] Remove unused header files. Define them in each transition unit. --- compiler/clay.hpp | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/compiler/clay.hpp b/compiler/clay.hpp index cd467c93..778ed0eb 100644 --- a/compiler/clay.hpp +++ b/compiler/clay.hpp @@ -23,38 +23,17 @@ #include #include #include -#include #include -#include -#include #include -#include #include #include #include #include -#include #include -#include -#include -#include #include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include +#include #include From f690e770c9e3e908ceb7c664eca735b1b21d0e92 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Wed, 10 Dec 2025 22:36:31 -0500 Subject: [PATCH 11/56] Specify a minimum version (a guess?) --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8388526f..1422db4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,9 @@ if(UNIX) if (NOT ${LLVM_CONFIG_VERSION_RESULT} EQUAL 0) message(FATAL_ERROR "${LLVM_CONFIG} failed") endif() + if(LLVM_VERSION VERSION_LESS 18.0) + message(FATAL_ERROR "LLVM 18 or newer is required. Found ${LLVM_VERSION}") + endif() execute_process( COMMAND ${LLVM_CONFIG} --cxxflags From 26c0d39bf0c898f93a464911589442b7e591d290 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Wed, 10 Dec 2025 22:41:48 -0500 Subject: [PATCH 12/56] Don't create unnecessary object --- compiler/profiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/profiler.cpp b/compiler/profiler.cpp index d473fdb5..b91f8aa5 100644 --- a/compiler/profiler.cpp +++ b/compiler/profiler.cpp @@ -22,7 +22,7 @@ namespace clay { vector > counts; llvm::StringMap::iterator cmi = countsMap.begin(); while (cmi != countsMap.end()) { - counts.push_back(vector>::value_type(make_pair(cmi->getValue(), cmi->getKey()))); + counts.emplace_back(cmi->getValue(), cmi->getKey()); ++cmi; } sort(counts.begin(), counts.end()); From e9b63a68510ad12c1dc28ea274db7804014f604f Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Thu, 11 Dec 2025 00:59:04 -0500 Subject: [PATCH 13/56] Use standard error_code to fix F_Binary --- compiler/clay.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compiler/clay.cpp b/compiler/clay.cpp index 7f562c7b..5cdc7fdc 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -1113,12 +1113,13 @@ namespace clay { linkLibraries(llvmModule, libSearchPath, libraries); runInteractive(llvmModule, m); } else if (emitLLVM || emitAsm || emitObject) { - string errorInfo; + std::error_code ec; + llvm::raw_fd_ostream out(outputFile.c_str(), - errorInfo, - llvm::raw_fd_ostream::F_Binary); - if (!errorInfo.empty()) { - llvm::errs() << "error: " << errorInfo << '\n'; + ec, + llvm::sys::fs::OF_None); + if (ec) { + llvm::errs() << "error creating output file: " << ec.message() << '\n'; return 1; } outputTimer.start(); @@ -1132,8 +1133,12 @@ namespace clay { llvm::sys::Path clangPath = llvm::sys::Program::FindProgramByName("clang"); if (!clangPath.isValid()) { llvm::errs() << "error: unable to find clang on the path\n"; + llvm::ErrorOr clangPathOrErr = llvm::sys::findProgramByName("clang"); + if (std::error_code ec = clangPathOrErr.getError()) { + llvm::errs() << "error: unable to find clang on the path: " << ec.message() << "\n"; return 1; } + std::string clangPath = clangPathOrErr.get(); vector arguments; #ifdef __APPLE__ From 22cc213a0eaf283d4a43004d5491c1acf4e38bb1 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Thu, 11 Dec 2025 01:00:12 -0500 Subject: [PATCH 14/56] Add all missing LLVM related header files from clay.cpp --- compiler/clay.cpp | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/compiler/clay.cpp b/compiler/clay.cpp index 5cdc7fdc..a088af33 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -1,16 +1,33 @@ #include -#include #include #include #include -#include "llvm/Support/DynamicLibrary.h" #include #include #include #include #include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -1130,9 +1147,6 @@ namespace clay { outputTimer.stop(); } else { bool result; - llvm::sys::Path clangPath = llvm::sys::Program::FindProgramByName("clang"); - if (!clangPath.isValid()) { - llvm::errs() << "error: unable to find clang on the path\n"; llvm::ErrorOr clangPathOrErr = llvm::sys::findProgramByName("clang"); if (std::error_code ec = clangPathOrErr.getError()) { llvm::errs() << "error: unable to find clang on the path: " << ec.message() << "\n"; From cd1ca33d30ae2a69639e84dcf354c9d29d80f054 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Thu, 11 Dec 2025 01:00:57 -0500 Subject: [PATCH 15/56] Rename the dsymutilPath to camelCase --- compiler/clay.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/clay.cpp b/compiler/clay.cpp index a088af33..fe021009 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -395,11 +395,11 @@ namespace clay { int result = llvm::sys::ExecuteAndWait(clangPath, clangArgs); if (debug && triple.isOSDarwin()) { - llvm::ErrorOr DsymutilPathOrErr = llvm::sys::findProgramByName("dsymutil"); - if (std::error_code EC = DsymutilPathOrErr.getError()) - llvm::errs() << "error creating dsymutil: " << EC.message() << '\n'; + llvm::ErrorOr dsymutilPathOrErr = llvm::sys::findProgramByName("dsymutil"); + if (std::error_code ec = dsymutilPathOrErr.getError()) + llvm::errs() << "error creating dsymutil: " << ec.message() << '\n'; - std::string dsymutilPath = DsymutilPathOrErr ? *DsymutilPathOrErr : ""; + std::string dsymutilPath = dsymutilPathOrErr ? *dsymutilPathOrErr : ""; if (!dsymutilPath.empty()) { string outputDSYMPath = outputFilePathStr; From cddbd9d35dd2e14ee22b40b76dd45dda1bf15305 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Thu, 11 Dec 2025 01:01:35 -0500 Subject: [PATCH 16/56] Use standard error_code to fix F_Binary --- compiler/clay.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/clay.cpp b/compiler/clay.cpp index fe021009..a1ad6607 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -1089,17 +1089,17 @@ namespace clay { compileTimer.stop(); if (generateDeps) { - string errorInfo; + std::error_code ec; if (verbose) { llvm::errs() << "generating dependencies into " << dependenciesOutputFile << "\n"; } llvm::raw_fd_ostream dependenciesOut(dependenciesOutputFile.c_str(), - errorInfo, - llvm::raw_fd_ostream::F_Binary); - if (!errorInfo.empty()) { - llvm::errs() << "error: " << errorInfo << '\n'; + ec, + llvm::sys::fs::OF_None); + if (ec) { + llvm::errs() << "error creating dependencies file: " << ec.message() << '\n'; return 1; } dependenciesOut << outputFile << ": \\\n"; From 23e2eee784e0f54f6fafd17c8b2e184834386fc9 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Thu, 11 Dec 2025 01:09:11 -0500 Subject: [PATCH 17/56] Update clay.cpp: modern llvm migration - moved to orc jit for dynamic execution - moved to new pass manager (npm) for optimization - updated ir and assembly generation pass manager objects --- compiler/clay.cpp | 306 ++++++++++++++-------------------------------- 1 file changed, 93 insertions(+), 213 deletions(-) diff --git a/compiler/clay.cpp b/compiler/clay.cpp index a1ad6607..61197b88 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -30,7 +30,10 @@ #include #include +#include #include +#include +#include #include "clay.hpp" #include "hirestimer.hpp" @@ -40,6 +43,9 @@ #include "invoketables.hpp" #include "parachute.hpp" +using std::string; +using std::vector; + // for _exit #ifdef _WIN32 # include @@ -60,254 +66,128 @@ namespace clay { #define ENV_SEPARATOR ':' #endif - using namespace std; - - static void addOptimizationPasses(llvm::PassManager &passes, - llvm::FunctionPassManager &fpasses, - unsigned optLevel, - bool internalize) { - llvm::Pass *inliningPass = nullptr; - if (optLevel > 1) { - int threshold = 225; - if (optLevel > 2) - threshold = 275; - inliningPass = llvm::createFunctionInliningPass(threshold); - } else { - inliningPass = llvm::createAlwaysInlinerPass(); + static bool runModule(llvm::Module *module, + const std::vector &argv, + char const *const*envp, + llvm::ArrayRef libSearchPaths, + llvm::ArrayRef libs) { + auto JIT_expected = llvm::orc::LLJITBuilder().create(); + if (!JIT_expected) { + llvm::errs() << "error creating JIT: " << llvm::toString(JIT_expected.takeError()) << "\n"; + return false; } + auto JIT = std::move(JIT_expected.get()); + llvm::orc::LLJIT &jit = *JIT; - llvm::PassManagerBuilder builder; - builder.OptLevel = optLevel; - builder.Inliner = inliningPass; - - builder.populateFunctionPassManager(fpasses); - - // If all optimizations are disabled, just run the always-inline pass. - if (optLevel == 0) { - if (builder.Inliner) { - passes.add(builder.Inliner); - builder.Inliner = 0; - } - } else { - passes.add(llvm::createTypeBasedAliasAnalysisPass()); - passes.add(llvm::createBasicAliasAnalysisPass()); + llvm::orc::JITDylib& mainDylib = jit.getMainJITDylib(); - passes.add(llvm::createGlobalOptimizerPass()); // Optimize out global vars + auto Generator_expected = llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( + jit.getDataLayout().getGlobalPrefix() + ); - passes.add(llvm::createIPSCCPPass()); // IP SCCP - passes.add(llvm::createDeadArgEliminationPass()); // Dead argument elimination + if (!Generator_expected) { + llvm::errs() << "error creating generator: " << llvm::toString(Generator_expected.takeError()) << "\n"; + return false; + } - passes.add(llvm::createInstructionCombiningPass()); // Clean up after IPCP & DAE - passes.add(llvm::createCFGSimplificationPass()); // Clean up after IPCP & DAE + std::unique_ptr Generator = + std::move(*Generator_expected); - // Start of CallGraph SCC passes. - if (builder.Inliner) { - passes.add(builder.Inliner); - builder.Inliner = 0; - } - if (optLevel > 2) - passes.add(llvm::createArgumentPromotionPass()); // Scalarize uninlined fn args - - // Start of function pass. - // Break up aggregate allocas, using SSAUpdater. - passes.add(llvm::createScalarReplAggregatesPass(-1, false)); - passes.add(llvm::createEarlyCSEPass()); // Catch trivial redundancies - - passes.add(llvm::createJumpThreadingPass()); // Thread jumps. - // Disable Value Propagation pass until fixed LLVM bug #12503 - // passes.add(llvm::createCorrelatedValuePropagationPass()); // Propagate conditionals - passes.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs - passes.add(llvm::createInstructionCombiningPass()); // Combine silly seq's - - passes.add(llvm::createTailCallEliminationPass()); // Eliminate tail calls - passes.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs - passes.add(llvm::createReassociatePass()); // Reassociate expressions - passes.add(llvm::createLoopRotatePass()); // Rotate Loop - passes.add(llvm::createLICMPass()); // Hoist loop invariants - passes.add(llvm::createLoopUnswitchPass(builder.SizeLevel || optLevel < 3)); - passes.add(llvm::createInstructionCombiningPass()); - passes.add(llvm::createIndVarSimplifyPass()); // Canonicalize indvars - passes.add(llvm::createLoopIdiomPass()); // Recognize idioms like memset. - passes.add(llvm::createLoopDeletionPass()); // Delete dead loops - - if (optLevel > 1) - passes.add(llvm::createGVNPass()); // Remove redundancies - passes.add(llvm::createMemCpyOptPass()); // Remove memcpy / form memset - passes.add(llvm::createSCCPPass()); // Constant prop with SCCP - - // Run instcombine after redundancy elimination to exploit opportunities - // opened up by them. - passes.add(llvm::createInstructionCombiningPass()); - passes.add(llvm::createJumpThreadingPass()); // Thread jumps - // Disable Value Propagation pass until fixed LLVM bug #12503 - // passes.add(llvm::createCorrelatedValuePropagationPass()); - passes.add(llvm::createDeadStoreEliminationPass()); // Delete dead stores - - if (builder.Vectorize) { - passes.add(llvm::createBBVectorizePass()); - passes.add(llvm::createInstructionCombiningPass()); - if (optLevel > 1) - passes.add(llvm::createGVNPass()); // Remove redundancies - } + mainDylib.addGenerator(std::move(Generator)); - passes.add(llvm::createAggressiveDCEPass()); // Delete dead instructions - passes.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs - passes.add(llvm::createInstructionCombiningPass()); // Clean up after everything. + module->setDataLayout(jit.getDataLayout()); - // GlobalOpt already deletes dead functions and globals, at -O3 try a - // late pass of GlobalDCE. It is capable of deleting dead cycles. - if (optLevel > 2) - passes.add(llvm::createGlobalDCEPass()); // Remove dead fns and globals. + auto TSM = llvm::orc::ThreadSafeModule(std::unique_ptr(module), + std::make_unique()); - if (optLevel > 1) - passes.add(llvm::createConstantMergePass()); // Merge dup global constants + if (llvm::Error AddIRErr = jit.addIRModule(std::move(TSM))) { + llvm::errs() << "error adding module to JIT: " << llvm::toString(std::move(AddIRErr)) << "\n"; + return false; } - if (optLevel > 2) { - if (internalize) { - vector do_not_internalize; - do_not_internalize.push_back("main"); - passes.add(llvm::createInternalizePass(do_not_internalize)); - } - builder.populateLTOPassManager(passes, false, true); + auto mainAddr_expected = jit.lookup("main"); + if (!mainAddr_expected) { + llvm::errs() << "error resolving main: " << llvm::toString(mainAddr_expected.takeError()) << "\n"; + return false; } - } - static bool linkLibraries(llvm::Module *module, llvm::ArrayRef libSearchPaths, - llvm::ArrayRef libs) { - if (libs.empty()) - return true; - - llvm::Linker linker("clay", llvmModule, llvm::Linker::Verbose); - linker.addSystemPaths(); - linker.addPaths(libSearchPaths); - for (auto lib : libs) { - llvmModule->addLibrary(lib); - //as in cling/lib/Interpreter/Interpreter.cpp - bool isNative = true; - if (linker.LinkInLibrary(lib, isNative)) { - // that didn't work, try bitcode: - llvm::sys::Path FilePath(lib); - std::string Magic; - if (!FilePath.getMagicNumber(Magic, 64)) { - // filename doesn't exist... - linker.releaseModule(); - return false; - } - if (llvm::sys::IdentifyFileType(Magic.c_str(), 64) - == llvm::sys::Bitcode_FileType) { - // We are promised a bitcode file, complain if it fails - linker.setFlags(0); - if (linker.LinkInFile(llvm::sys::Path(lib), isNative)) { - linker.releaseModule(); - return false; - } - } else { - // Nothing the linker can handle - linker.releaseModule(); - return false; - } - } else if (isNative) { - // native shared library, load it! - llvm::sys::Path SoFile = linker.FindLib(lib); - if (SoFile.isEmpty()) { - llvm::errs() << "Couldn't find shared library " << lib << "\n"; - linker.releaseModule(); - return false; - } - std::string errMsg; - bool hasError = llvm::sys::DynamicLibrary - ::LoadLibraryPermanently(SoFile.str().c_str(), &errMsg); - if (hasError) { - llvm::errs() << "Couldn't load shared library " << lib << "\n" << errMsg.c_str(); - linker.releaseModule(); - return false; - } - } - } - linker.releaseModule(); - return true; - } + using MainPtr = int (*)(int, char *[], char *[]); - static bool runModule(llvm::Module *module, - vector &argv, - char const *const*envp, - llvm::ArrayRef libSearchPaths, - llvm::ArrayRef libs) { - if (!linkLibraries(module, libSearchPaths, libs)) { - return false; - } - llvm::EngineBuilder eb(llvmModule); - llvm::ExecutionEngine *engine = eb.create(); - llvm::Function *mainFunc = module->getFunction("main"); - if (!mainFunc) { - llvm::errs() << "no main function to -run\n"; - delete engine; - return false; + llvm::orc::ExecutorAddr mainAddr = mainAddr_expected.get(); + MainPtr mainFunc = reinterpret_cast(mainAddr.getValue()); + + std::vector c_argv; + for (const auto& arg : argv) { + c_argv.push_back(arg.c_str()); } - engine->runStaticConstructorsDestructors(false); - engine->runFunctionAsMain(mainFunc, argv, envp); - engine->runStaticConstructorsDestructors(true); + c_argv.push_back(nullptr); + + mainFunc(c_argv.size() - 1, const_cast(c_argv.data()), const_cast(envp)); - delete engine; return true; } static void optimizeLLVM(llvm::Module *module, unsigned optLevel, bool internalize) { - llvm::PassManager passes; - - string moduleDataLayout = module->getDataLayout(); - auto *dl = new llvm::DataLayout(moduleDataLayout); - passes.add(dl); - - llvm::FunctionPassManager fpasses(module); - - fpasses.add(new llvm::DataLayout(*dl)); - - addOptimizationPasses(passes, fpasses, optLevel, internalize); - - fpasses.doInitialization(); - for (auto & i : *module) { - fpasses.run(i); + llvm::LoopAnalysisManager LAM; + llvm::FunctionAnalysisManager FAM; + llvm::CGSCCAnalysisManager CGAM; + llvm::ModuleAnalysisManager MAM; + llvm::PassBuilder PB; + + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + llvm::OptimizationLevel O = llvm::OptimizationLevel::O0; + if (optLevel == 1) O = llvm::OptimizationLevel::O1; + else if (optLevel == 2) O = llvm::OptimizationLevel::O2; + else if (optLevel >= 3) O = llvm::OptimizationLevel::O3; + + llvm::ModulePassManager MPM = PB.buildPerModuleDefaultPipeline(O); + + if (optLevel > 2 && internalize) { + MPM.addPass(llvm::InternalizePass([=](const llvm::GlobalValue &GV) { + return GV.getName() == "main"; + })); } - passes.add(llvm::createVerifierPass()); - passes.run(*module); + MPM.addPass(llvm::VerifierPass()); + + MPM.run(*module, MAM); } static void generateLLVM(llvm::Module *module, bool emitAsm, llvm::raw_ostream *out) { - llvm::PassManager passes; + llvm::ModuleAnalysisManager MAM; + llvm::ModulePassManager passes; + if (emitAsm) - passes.add(llvm::createPrintModulePass(out)); + passes.addPass(llvm::PrintModulePass(*out)); else - passes.add(llvm::createBitcodeWriterPass(*out)); - passes.run(*module); + passes.addPass(llvm::BitcodeWriterPass(*out)); + + passes.run(*module, MAM); } static void generateAssembly(llvm::Module *module, llvm::TargetMachine *targetMachine, - llvm::raw_ostream *out, + llvm::raw_pwrite_stream *out, bool emitObject) { - llvm::FunctionPassManager fpasses(module); - - fpasses.add(new llvm::DataLayout(module)); - fpasses.add(llvm::createVerifierPass()); - - targetMachine->setAsmVerbosityDefault(true); + llvm::legacy::PassManager passes; - llvm::formatted_raw_ostream fout(*out); - llvm::TargetMachine::CodeGenFileType fileType = emitObject - ? llvm::TargetMachine::CGFT_ObjectFile - : llvm::TargetMachine::CGFT_AssemblyFile; + passes.add(llvm::createVerifierPass()); - bool result = targetMachine->addPassesToEmitFile(fpasses, fout, fileType); - assert(!result); + llvm::CodeGenFileType fileType = emitObject + ? llvm::CodeGenFileType::ObjectFile + : llvm::CodeGenFileType::AssemblyFile; - fpasses.doInitialization(); - for (auto & i : *module) { - fpasses.run(i); + if (targetMachine->addPassesToEmitFile(passes, *out, nullptr, fileType)) { + llvm::errs() << "error: adding codegen passes failed\n"; + return; } - fpasses.doFinalization(); + + passes.run(*module); } [[maybe_unused]] static std::string joinCmdArgs(llvm::ArrayRef args) @@ -1127,7 +1007,7 @@ namespace clay { runArgs.push_back(clayFile); runModule(llvmModule, runArgs, envp, libSearchPath, libraries); } else if (repl) { - linkLibraries(llvmModule, libSearchPath, libraries); + // TODO: future me task runInteractive(llvmModule, m); } else if (emitLLVM || emitAsm || emitObject) { std::error_code ec; From aa6c3665b5b2865ab5bb97b9031fd5dfe3cad78b Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Thu, 11 Dec 2025 05:55:12 -0500 Subject: [PATCH 18/56] Remove quotes and export compile commands --- CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1422db4b..eb6cecba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") find_package(Git) @@ -44,11 +45,11 @@ if(UNIX) OUTPUT_VARIABLE LLVM_CXXFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE ) - set(LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") + set(LLVM_CXXFLAGS ${LLVM_CXXFLAGS}) separate_arguments(LLVM_CXXFLAGS) if(CMAKE_BUILD_TYPE STREQUAL "Debug") - set(LLVM_CXXFLAGS "${LLVM_CXXFLAGS} -O0") + list(APPEND LLVM_CXXFLAGS -O0) endif() execute_process( @@ -82,7 +83,7 @@ if(UNIX) OUTPUT_VARIABLE LLVM_INCLUDEDIR OUTPUT_STRIP_TRAILING_WHITESPACE ) - set(LLVM_INCLUDEDIR "${LLVM_INCLUDEDIR}") + set(LLVM_INCLUDEDIR ${LLVM_INCLUDEDIR}) message("-- Using LLVM: ${LLVM_DIR}") message("-- LLVM include dir: ${LLVM_INCLUDEDIR}") From be072f4be7bd4f5bed85524970d0c3236781c073 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Thu, 11 Dec 2025 05:56:13 -0500 Subject: [PATCH 19/56] Pass through with clang-tidy on clay.cpp --- compiler/clay.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/clay.cpp b/compiler/clay.cpp index 61197b88..8761286f 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -1,9 +1,7 @@ #include #include -#include #include #include -#include #include #include #include @@ -114,7 +112,7 @@ namespace clay { using MainPtr = int (*)(int, char *[], char *[]); llvm::orc::ExecutorAddr mainAddr = mainAddr_expected.get(); - MainPtr mainFunc = reinterpret_cast(mainAddr.getValue()); + auto mainFunc = reinterpret_cast(mainAddr.getValue()); std::vector c_argv; for (const auto& arg : argv) { @@ -122,7 +120,7 @@ namespace clay { } c_argv.push_back(nullptr); - mainFunc(c_argv.size() - 1, const_cast(c_argv.data()), const_cast(envp)); + mainFunc(static_cast(c_argv.size() - 1), const_cast(c_argv.data()), const_cast(envp)); return true; } @@ -242,7 +240,7 @@ namespace clay { assert(false); } - llvm::Triple triple(llvmModule->getTargetTriple()); + const llvm::Triple& triple(llvmModule->getTargetTriple()); if (sharedLib) { clangArgs.emplace_back("-shared"); @@ -583,7 +581,7 @@ namespace clay { llvm::errs() << "error: framework name missing after -framework\n"; return 1; } - frameworks.push_back("-framework"); + frameworks.emplace_back("-framework"); frameworks.push_back(framework); } else if (strcmp(argv[i], "-arch") == 0) { if (i + 1 == argc) { @@ -975,7 +973,7 @@ namespace clay { llvm::errs() << "generating dependencies into " << dependenciesOutputFile << "\n"; } - llvm::raw_fd_ostream dependenciesOut(dependenciesOutputFile.c_str(), + llvm::raw_fd_ostream dependenciesOut(dependenciesOutputFile, ec, llvm::sys::fs::OF_None); if (ec) { @@ -1012,7 +1010,7 @@ namespace clay { } else if (emitLLVM || emitAsm || emitObject) { std::error_code ec; - llvm::raw_fd_ostream out(outputFile.c_str(), + llvm::raw_fd_ostream out(outputFile, ec, llvm::sys::fs::OF_None); if (ec) { @@ -1032,12 +1030,12 @@ namespace clay { llvm::errs() << "error: unable to find clang on the path: " << ec.message() << "\n"; return 1; } - std::string clangPath = clangPathOrErr.get(); + const std::string& clangPath = clangPathOrErr.get(); vector arguments; #ifdef __APPLE__ if (!arch.empty()) { - arguments.push_back("-arch"); + arguments.emplace_back("-arch"); arguments.push_back(arch); } #endif From 7ea75094608202a4238b29a95a15bf207f87c387 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Thu, 11 Dec 2025 05:56:29 -0500 Subject: [PATCH 20/56] Remove CLAY_CXXFLAGS --- compiler/CMakeLists.txt | 63 +++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/compiler/CMakeLists.txt b/compiler/CMakeLists.txt index 2868281a..2b750204 100644 --- a/compiler/CMakeLists.txt +++ b/compiler/CMakeLists.txt @@ -54,41 +54,56 @@ if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") COMPILE_DEFINITIONS "GIT_ID=\"${GIT_WC_ID}\"") endif() -# Compiler flags +# Targets +add_library(compiler STATIC ${COMPILER_SOURCES}) +add_executable(clay ${CLAY_SOURCES}) +add_executable(claydoc ${CLAYDOC_SOURCES}) +add_executable(ut ${UT_SOURCES}) + +# compiler flags +target_compile_options(compiler PRIVATE ${LLVM_CXXFLAGS}) +target_compile_options(clay PRIVATE ${LLVM_CXXFLAGS}) +target_compile_options(claydoc PRIVATE ${LLVM_CXXFLAGS}) +target_compile_options(ut PRIVATE ${LLVM_CXXFLAGS}) + +# include directories +target_include_directories(compiler PRIVATE ${LLVM_INCLUDEDIR}) +target_include_directories(clay PRIVATE ${LLVM_INCLUDEDIR}) +target_include_directories(claydoc PRIVATE ${LLVM_INCLUDEDIR}) +target_include_directories(ut PRIVATE ${LLVM_INCLUDEDIR}) + if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") - set(CLAY_CXXFLAGS "${LLVM_CXXFLAGS} -UNDEBUG") + target_compile_definitions(compiler PRIVATE UNDEBUG) + target_compile_definitions(clay PRIVATE UNDEBUG) + target_compile_definitions(claydoc PRIVATE UNDEBUG) + target_compile_definitions(ut PRIVATE UNDEBUG) else() - set(CLAY_CXXFLAGS "${LLVM_CXXFLAGS} -DNDEBUG") + target_compile_definitions(compiler PRIVATE NDEBUG) + target_compile_definitions(clay PRIVATE NDEBUG) + target_compile_definitions(claydoc PRIVATE NDEBUG) + target_compile_definitions(ut PRIVATE NDEBUG) endif() -if (NOT MSVC) - set(CLAY_CXXFLAGS "${CLAY_CXXFLAGS} -fexceptions") + +if(NOT MSVC) + target_compile_options(compiler PRIVATE -fexceptions) + target_compile_options(clay PRIVATE -fexceptions) + target_compile_options(claydoc PRIVATE -fexceptions) + target_compile_options(ut PRIVATE -fexceptions) endif() set(ENABLE_PCH False CACHE BOOL - "Use precompiled headers when building the compiler. (experimental)") + "Use precompiled headers when building the compiler. (experimental)") if(ENABLE_PCH) - precompile_header(clay.hpp SOURCES pch.cpp "${CLAY_CXXFLAGS}") + precompile_header(clay.hpp SOURCES pch.cpp ${LLVM_CXXFLAGS}) endif(ENABLE_PCH) -# Targets -add_library(compiler STATIC ${COMPILER_SOURCES}) -add_executable(clay ${CLAY_SOURCES}) -add_executable(claydoc ${CLAYDOC_SOURCES}) -add_executable(ut ${UT_SOURCES}) - -# compiler flags -target_compile_options(compiler PRIVATE "${CLAY_CXXFLAGS}") -target_compile_options(clay PRIVATE "${CLAY_CXXFLAGS}") -target_compile_options(claydoc PRIVATE "${CLAY_CXXFLAGS}") -target_compile_options(ut PRIVATE "${CLAY_CXXFLAGS}") - if (UNIX) - target_link_options(compiler PRIVATE "${LLVM_LDFLAGS}") - target_link_options(clay PRIVATE "${LLVM_LDFLAGS}") - target_link_options(claydoc PRIVATE "${LLVM_LDFLAGS}") - target_link_options(ut PRIVATE "${LLVM_LDFLAGS}") -endif(UNIX) + target_link_options(compiler PRIVATE ${LLVM_LDFLAGS}) + target_link_options(clay PRIVATE ${LLVM_LDFLAGS}) + target_link_options(claydoc PRIVATE ${LLVM_LDFLAGS}) + target_link_options(ut PRIVATE ${LLVM_LDFLAGS}) +endif() # Libraries target_link_libraries(clay PRIVATE compiler ${LLVM_LIBS}) From a2e97abb275c589703b20c01930be4969f697ec2 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Thu, 11 Dec 2025 09:30:32 -0500 Subject: [PATCH 21/56] Fix the issues with error.cpp (getDebugLineCol still needs work) --- compiler/clay.hpp | 14 +++--- compiler/error.cpp | 118 +++++++++++++++++++++++---------------------- compiler/error.hpp | 44 ++++++++--------- 3 files changed, 90 insertions(+), 86 deletions(-) diff --git a/compiler/clay.hpp b/compiler/clay.hpp index 778ed0eb..83433e3c 100644 --- a/compiler/clay.hpp +++ b/compiler/clay.hpp @@ -549,14 +549,16 @@ namespace clay { Source(llvm::StringRef lineOfCode, int dummy); Source(llvm::StringRef fileName, llvm::MemoryBuffer *buffer) - : Object(SOURCE), fileName(fileName), buffer(buffer), debugInfo(nullptr) { + : Object(SOURCE), fileName(fileName), buffer(buffer) { } - const char *data() const { return buffer->getBufferStart(); } - const char *endData() const { return buffer->getBufferEnd(); } - size_t size() const { return buffer->getBufferSize(); } + [[nodiscard]] const char *data() const { return buffer->getBufferStart(); } + [[nodiscard]] const char *endData() const { return buffer->getBufferEnd(); } + [[nodiscard]] size_t size() const { return buffer->getBufferSize(); } - llvm::DIFile getDebugInfo() const { return llvm::DIFile(debugInfo); } + [[nodiscard]] llvm::DIFile *getDebugInfo() const { + // TODO: implement this... + } }; struct Location { @@ -670,7 +672,7 @@ namespace clay { unsigned &column, unsigned &tabColumn); - llvm::DIFile getDebugLineCol(Location const &location, unsigned &line, unsigned &column); + llvm::DIFile *getDebugLineCol(Location const &location, unsigned &line, unsigned &column); void printFileLineCol(llvm::raw_ostream &out, Location const &location); diff --git a/compiler/error.cpp b/compiler/error.cpp index ddb0ae0f..d0f8cc2d 100644 --- a/compiler/error.cpp +++ b/compiler/error.cpp @@ -4,6 +4,7 @@ #include "matchinvoke.hpp" #include "invoketables.hpp" #include "error.hpp" +#include "printer.hpp" namespace clay { bool shouldPrintFullMatchErrors; @@ -17,28 +18,28 @@ namespace clay { static constexpr unsigned RECURSION_WARNING_LEVEL = 1000; - void pushCompileContext(ObjectPtr obj) { + void pushCompileContext(const ObjectPtr &obj) { if (contextStack.size() >= RECURSION_WARNING_LEVEL) warning("potential runaway recursion"); if (!contextStack.empty()) contextStack.back().location = topLocation(); - contextStack.push_back(CompileContextEntry(obj)); + contextStack.emplace_back(obj); } - void pushCompileContext(ObjectPtr obj, llvm::ArrayRef params) { + void pushCompileContext(const ObjectPtr &obj, const llvm::ArrayRef params) { if (contextStack.size() >= RECURSION_WARNING_LEVEL) warning("potential runaway recursion"); if (!contextStack.empty()) contextStack.back().location = topLocation(); - contextStack.push_back(CompileContextEntry(obj, params)); + contextStack.emplace_back(obj, params); } - void pushCompileContext(ObjectPtr obj, llvm::ArrayRef params, llvm::ArrayRef dispatchIndices) { + void pushCompileContext(const ObjectPtr &obj, llvm::ArrayRef params, llvm::ArrayRef dispatchIndices) { if (contextStack.size() >= RECURSION_WARNING_LEVEL) warning("potential runaway recursion"); if (!contextStack.empty()) contextStack.back().location = topLocation(); - contextStack.push_back(CompileContextEntry(obj, params, dispatchIndices)); + contextStack.emplace_back(obj, params, dispatchIndices); } void popCompileContext() { @@ -53,11 +54,11 @@ namespace clay { contextStack = x; } - CompileContextPusher::CompileContextPusher(ObjectPtr obj, llvm::ArrayRef params, + CompileContextPusher::CompileContextPusher(const ObjectPtr &obj, llvm::ArrayRef params, llvm::ArrayRef dispatchIndices) { vector params2; - for (unsigned i = 0; i < params.size(); ++i) { - params2.push_back(params[i].type.ptr()); + for (const auto & param : params) { + params2.emplace_back(param.type.ptr()); } pushCompileContext(obj, params2, dispatchIndices); } @@ -77,14 +78,13 @@ namespace clay { } Location topLocation() { - vector::iterator i, begin; - i = errorLocations.end(); - begin = errorLocations.begin(); + auto i = errorLocations.end(); + auto begin = errorLocations.begin(); while (i != begin) { --i; if (i->ok()) return *i; } - return Location(); + return {}; } // @@ -95,7 +95,7 @@ namespace clay { int DebugPrinter::indent = 0; - DebugPrinter::DebugPrinter(ObjectPtr obj) + DebugPrinter::DebugPrinter(const ObjectPtr &obj) : obj(obj) { for (int i = 0; i < indent; ++i) llvm::outs() << ' '; @@ -133,11 +133,11 @@ namespace clay { } } - llvm::DIFile getDebugLineCol(Location const &location, unsigned &line, unsigned &column) { + llvm::DIFile *getDebugLineCol(Location const &location, unsigned &line, unsigned &column) { if (!location.ok()) { line = 0; column = 0; - return llvm::DIFile(); + return nullptr; } unsigned tabColumn; @@ -158,14 +158,18 @@ namespace clay { computeLineCol(location, line, column, tabColumn); } - static void splitLines(SourcePtr source, vector &lines) { - lines.push_back(string()); - const char *p = source->data(); - const char *end = source->endData(); - for (; p != end; ++p) { - lines.back().push_back(*p); - if (*p == '\n') - lines.push_back(string()); + static void splitLines(const SourcePtr &source, vector &lines) { + lines.clear(); + if (!source || source->data() == source->endData()) { + return; + } + const std::string_view sourceView(source->data(), source->endData() - source->data()); + lines.emplace_back(); + + for (const char c : sourceView) { + lines.back().push_back(c); + if (c == '\n') + lines.emplace_back(); } } @@ -242,7 +246,7 @@ namespace clay { return; llvm::errs() << "\ndebug stack:\n"; for (size_t i = debugStack.size(); i > 0; --i) { - llvm::errs() << " " << debugStack[i - 1] << "\n"; + llvm::errs() << " " << debugStack[i - 1]->toString() << "\n"; } } @@ -321,22 +325,22 @@ namespace clay { error(sout.str()); } - void ensureArity(MultiStaticPtr args, size_t size) { + void ensureArity(const MultiStaticPtr &args, size_t size) { if (args->size() != size) arityError(size, args->size()); } - void ensureArity(MultiEValuePtr args, size_t size) { + void ensureArity(const MultiEValuePtr &args, size_t size) { if (args->size() != size) arityError(size, args->size()); } - void ensureArity(MultiPValuePtr args, size_t size) { + void ensureArity(const MultiPValuePtr &args, size_t size) { if (args->size() != size) arityError(size, args->size()); } - void ensureArity(MultiCValuePtr args, size_t size) { + void ensureArity(const MultiCValuePtr &args, size_t size) { if (args->size() != size) arityError(size, args->size()); } @@ -354,45 +358,45 @@ namespace clay { } static string typeErrorMessage(llvm::StringRef expected, - TypePtr receivedType) { + const TypePtr &receivedType) { string buf; llvm::raw_string_ostream sout(buf); sout << "expected " << expected << ", " - << "but received " << receivedType << " type"; + << "but received " << receivedType->toString() << " type"; return sout.str(); } - static string typeErrorMessage(TypePtr expectedType, - TypePtr receivedType) { + static string typeErrorMessage(const TypePtr &expectedType, + const TypePtr &receivedType) { string buf; llvm::raw_string_ostream sout(buf); - sout << expectedType << " type"; + sout << expectedType->toString() << " type"; return typeErrorMessage(sout.str(), receivedType); } - void typeError(llvm::StringRef expected, TypePtr receivedType) { + void typeError(const llvm::StringRef expected, const TypePtr &receivedType) { error(typeErrorMessage(expected, receivedType)); } - void typeError(TypePtr expectedType, TypePtr receivedType) { + void typeError(const TypePtr &expectedType, const TypePtr &receivedType) { error(typeErrorMessage(expectedType, receivedType)); } - void argumentTypeError(unsigned index, - llvm::StringRef expected, - TypePtr receivedType) { + void argumentTypeError(const unsigned index, + const llvm::StringRef expected, + const TypePtr &receivedType) { argumentError(index, typeErrorMessage(expected, receivedType)); } - void argumentTypeError(unsigned index, - TypePtr expectedType, - TypePtr receivedType) { + void argumentTypeError(const unsigned index, + const TypePtr &expectedType, + const TypePtr &receivedType) { argumentError(index, typeErrorMessage(expectedType, receivedType)); } - void indexRangeError(llvm::StringRef kind, - size_t value, - size_t maxValue) { + void indexRangeError(const llvm::StringRef kind, + const size_t value, + const size_t maxValue) { string buf; llvm::raw_string_ostream sout(buf); sout << kind << " " << value << " is out of range. "; @@ -400,10 +404,10 @@ namespace clay { error(sout.str()); } - void argumentIndexRangeError(unsigned index, - llvm::StringRef kind, - size_t value, - size_t maxValue) { + void argumentIndexRangeError(const unsigned index, + const llvm::StringRef kind, + const size_t value, + const size_t maxValue) { string buf; llvm::raw_string_ostream sout(buf); sout << kind << " " << value << " is out of range. "; @@ -411,17 +415,17 @@ namespace clay { argumentError(index, sout.str()); } - void invalidStaticObjectError(ObjectPtr obj) { + void invalidStaticObjectError(const ObjectPtr &obj) { string buf; llvm::raw_string_ostream sout(buf); - sout << "invalid static object: " << obj; + sout << "invalid static object: " << obj->toString(); error(sout.str()); } - void argumentInvalidStaticObjectError(unsigned index, ObjectPtr obj) { + void argumentInvalidStaticObjectError(const unsigned index, const ObjectPtr &obj) { string buf; llvm::raw_string_ostream sout(buf); - sout << "invalid static object: " << obj; + sout << "invalid static object: " << obj->toString(); argumentError(index, sout.str()); } @@ -436,10 +440,8 @@ namespace clay { llvm::raw_string_ostream sout(outBuf); int hiddenPatternOverloads = 0; - for (MatchFailureVector::const_iterator i = err.failures.begin(); - i != err.failures.end(); - ++i) { - OverloadPtr overload = i->first; + for (const auto & failure : err.failures) { + OverloadPtr overload = failure.first; if (!shouldPrintFullMatchErrors && overload->nameIsPattern) { ++hiddenPatternOverloads; continue; @@ -451,7 +453,7 @@ namespace clay { sout << location.source->fileName.c_str() << "(" << line + 1 << "," << column << ")" << "\n "; - printMatchError(sout, i->second); + printMatchError(sout, failure.second); } if (hiddenPatternOverloads > 0) sout << "\n " << hiddenPatternOverloads << diff --git a/compiler/error.hpp b/compiler/error.hpp index ef3d882e..247d53dd 100644 --- a/compiler/error.hpp +++ b/compiler/error.hpp @@ -1,8 +1,8 @@ #pragma once #include "clay.hpp" -#include "invoketables.hpp" -#include "printer.hpp" +// #include "invoketables.hpp" +// #include "printer.hpp" #if defined(__GNUC__) || defined(__clang__) #define CLAY_NORETURN __attribute__((noreturn)) @@ -21,20 +21,20 @@ namespace clay { void fmtError(const char *fmt, ...) CLAY_NORETURN; template - inline void error(Pointer context, llvm::Twine const &msg) CLAY_NORETURN; + void error(Pointer context, llvm::Twine const &msg) CLAY_NORETURN; template - inline void error(Pointer context, llvm::Twine const &msg) { + void error(Pointer context, llvm::Twine const &msg) { if (context->location.ok()) pushLocation(context->location); error(msg); } template - inline void error(T const *context, llvm::Twine const &msg) CLAY_NORETURN; + void error(T const *context, llvm::Twine const &msg) CLAY_NORETURN; template - inline void error(T const *context, llvm::Twine const &msg) { + void error(T const *context, llvm::Twine const &msg) { error(context->location, msg); } @@ -44,7 +44,7 @@ namespace clay { void argumentError(size_t index, llvm::StringRef msg, const T &argument) CLAY_NORETURN; template - void argumentError(size_t index, llvm::StringRef msg, const T &argument) { + void argumentError(const size_t index, const llvm::StringRef msg, const T &argument) { string buf; llvm::raw_string_ostream sout(buf); sout << "argument " << (index + 1) << ": " << msg << ", actual " << argument; @@ -55,38 +55,38 @@ namespace clay { void arityError2(size_t minExpected, size_t received) CLAY_NORETURN; template - inline void arityError(Pointer context, size_t expected, size_t received) CLAY_NORETURN; + void arityError(Pointer context, size_t expected, size_t received) CLAY_NORETURN; template - inline void arityError(Pointer context, size_t expected, size_t received) { + void arityError(Pointer context, size_t expected, size_t received) { if (context->location.ok()) pushLocation(context->location); arityError(expected, received); } template - inline void arityError2(Pointer context, size_t minExpected, size_t received) CLAY_NORETURN; + void arityError2(Pointer context, size_t minExpected, size_t received) CLAY_NORETURN; template - inline void arityError2(Pointer context, size_t minExpected, size_t received) { + void arityError2(Pointer context, size_t minExpected, size_t received) { if (context->location.ok()) pushLocation(context->location); arityError2(minExpected, received); } - void ensureArity(MultiStaticPtr args, size_t size); - void ensureArity(MultiEValuePtr args, size_t size); - void ensureArity(MultiPValuePtr args, size_t size); - void ensureArity(MultiCValuePtr args, size_t size); + void ensureArity(const MultiStaticPtr &args, size_t size); + void ensureArity(const MultiEValuePtr &args, size_t size); + void ensureArity(const MultiPValuePtr &args, size_t size); + void ensureArity(const MultiCValuePtr &args, size_t size); template - inline void ensureArity(T const &args, size_t size) { + void ensureArity(T const &args, size_t size) { if (args.size() != size) arityError(size, args.size()); } template - inline void ensureArity2(T const &args, size_t size, bool hasVarArgs) { + void ensureArity2(T const &args, size_t size, bool hasVarArgs) { if (!hasVarArgs) ensureArity(args, size); else if (args.size() < size) @@ -95,16 +95,16 @@ namespace clay { void arityMismatchError(size_t leftArity, size_t rightArity, bool hasVarArg) CLAY_NORETURN; - void typeError(llvm::StringRef expected, TypePtr receivedType) CLAY_NORETURN; - void typeError(TypePtr expectedType, TypePtr receivedType) CLAY_NORETURN; + void typeError(llvm::StringRef expected, const TypePtr &receivedType) CLAY_NORETURN; + void typeError(const TypePtr &expectedType, const TypePtr &receivedType) CLAY_NORETURN; void argumentTypeError(unsigned index, llvm::StringRef expected, - TypePtr receivedType) CLAY_NORETURN; + const TypePtr &receivedType) CLAY_NORETURN; void argumentTypeError(unsigned index, - TypePtr expectedType, - TypePtr receivedType) CLAY_NORETURN; + const TypePtr &expectedType, + const TypePtr &receivedType) CLAY_NORETURN; void indexRangeError(llvm::StringRef kind, size_t value, From a8c074712b49df4c9df18aaf6c791e0405642e98 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Thu, 11 Dec 2025 09:31:00 -0500 Subject: [PATCH 22/56] Fix formatting --- compiler/lambdas.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/lambdas.hpp b/compiler/lambdas.hpp index f2386831..faf80384 100644 --- a/compiler/lambdas.hpp +++ b/compiler/lambdas.hpp @@ -3,7 +3,5 @@ #include "clay.hpp" namespace clay { - -void initializeLambda(LambdaPtr x, EnvPtr env); - + void initializeLambda(LambdaPtr x, EnvPtr env); } From 3c3392ba8da8d9ec526ede0e7e4f8287134259d9 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Thu, 11 Dec 2025 19:30:10 -0500 Subject: [PATCH 23/56] Remove const ref from llvm::Tripe in clay.cpp --- compiler/clay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/clay.cpp b/compiler/clay.cpp index 8761286f..2561a6ab 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -240,7 +240,7 @@ namespace clay { assert(false); } - const llvm::Triple& triple(llvmModule->getTargetTriple()); + llvm::Triple triple(llvmModule->getTargetTriple()); if (sharedLib) { clangArgs.emplace_back("-shared"); From ebcf8844558fa42f83d3ee866916b008fe15da5a Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Thu, 11 Dec 2025 20:33:11 -0500 Subject: [PATCH 24/56] Refactor REPL JIT from ExecutionEngine to LLJit framework --- compiler/interactive.cpp | 110 ++++++++++++++++++++++++++++----------- 1 file changed, 79 insertions(+), 31 deletions(-) diff --git a/compiler/interactive.cpp b/compiler/interactive.cpp index d3f25926..fd055101 100644 --- a/compiler/interactive.cpp +++ b/compiler/interactive.cpp @@ -1,3 +1,6 @@ +#include +#include + #include "clay.hpp" #include "lexer.hpp" #include "parser.hpp" @@ -7,9 +10,9 @@ #include "invoketables.hpp" #include "env.hpp" -#include -#include -#include +#include +#include +#include namespace clay { typedef llvm::SmallString<16U> Str; @@ -17,13 +20,13 @@ namespace clay { const char *replAnonymousFunctionName = "__replAnonymousFunction__"; static ModulePtr module; - static llvm::ExecutionEngine *engine; + static std::unique_ptr jit; jmp_buf recovery; static bool printAST = false; - static void eval(llvm::StringRef code); + static void eval(llvm::StringRef line); string newFunctionName() { static int funNum = 0; @@ -105,7 +108,7 @@ namespace clay { for (size_t k = 0; k < sets.size(); ++k) { llvm::errs() << " "; for (size_t l = 0; l < sets[k]->argsKey.size(); ++l) { - llvm::errs() << sets[k]->argsKey[l] << " : "; + llvm::errs() << sets[k]->argsKey[l]->toString() << " : "; } llvm::errs() << "\n"; } @@ -122,7 +125,7 @@ namespace clay { llvm::errs() << "Can't find identifier " << identifier.c_str(); } else { for (size_t i = 0; i < iter->second.size(); ++i) { - llvm::errs() << iter->second[i] << "\n"; + llvm::errs() << iter->second[i]->toString() << "\n"; } } } @@ -156,15 +159,15 @@ namespace clay { } } - static void loadImports(llvm::ArrayRef imports) { - for (size_t i = 0; i < imports.size(); ++i) { - module->imports.push_back(imports[i]); + static void loadImports(const llvm::ArrayRef imports) { + for (const auto & import : imports) { + module->imports.push_back(import); } - for (size_t i = 0; i < imports.size(); ++i) { - loadDependent(module, nullptr, imports[i], false); + for (const auto & import : imports) { + loadDependent(module, nullptr, import, false); } - for (size_t i = 0; i < imports.size(); ++i) { - initModule(imports[i]->module); + for (const auto & import : imports) { + initModule(import->module); } } @@ -174,7 +177,7 @@ namespace clay { } if (printAST) { for (size_t i = 0; i < toplevels.size(); ++i) { - llvm::errs() << i << ": " << toplevels[i] << "\n"; + llvm::errs() << i << ": " << toplevels[i]->toString() << "\n"; } } addGlobals(module, toplevels); @@ -186,8 +189,8 @@ namespace clay { } if (printAST) { - for (size_t i = 0; i < statements.size(); ++i) { - llvm::errs() << statements[i] << "\n"; + for (const auto & statement : statements) { + llvm::errs() << statement->toString() << "\n"; } } @@ -217,12 +220,34 @@ namespace clay { llvm::Function *dtor; codegenAfterRepl(ctor, dtor); - engine->runFunction(ctor, std::vector()); + // hacky voodoo raw memory address returned by LLJIT symbol lookup + // https://llvm.org/docs/ORCv2.html + using CtorPtr = void (*)(); + using PFN = void (*)(); + + auto ctorAddExpected = jit->lookup(ctor->getName()); + if (!ctorAddExpected) { + llvm::errs() << "error: cannot look up constructor: " << llvm::toString(ctorAddExpected.takeError()) << "\n"; + return; + } + CtorPtr ctorFunc = reinterpret_cast(ctorAddExpected->getValue()); + ctorFunc(); - void *dtorLlvmFun = engine->getPointerToFunction(dtor); - typedef void (*PFN)(); + auto dtorAddExpected = jit->lookup(dtor->getName()); + if (!dtorAddExpected) { + llvm::errs() << "error: cannot look up destructor: " << llvm::toString(dtorAddExpected.takeError()) << "\n"; + return; + } + void *dtorLlvmFun = reinterpret_cast(dtorAddExpected->getValue()); atexit((PFN) (uintptr_t) dtorLlvmFun); - engine->runFunction(entryProc->llvmFunc, std::vector()); + + auto entryAddrExpected = jit->lookup(entryProc->llvmFunc->getName()); + if (!entryAddrExpected) { + llvm::errs() << "error: cannot look up entry function: " << llvm::toString(entryAddrExpected.takeError()) << "\n"; + return; + } + PFN entryFunc = reinterpret_cast(entryAddrExpected->getValue()); + entryFunc(); } static void jitAndPrintExpr(ExprPtr expr) { @@ -249,14 +274,13 @@ namespace clay { } } - static void interactiveLoop() { + [[noreturn]] static void interactiveLoop() { setjmp(recovery); - string line; while (true) { llvm::errs().flush(); llvm::errs() << "clay>"; char buf[255]; - line = fgets(buf, 255, stdin); + string line = fgets(buf, 255, stdin); line = stripSpaces(line); if (line[0] == ':') { replCommand(line.substr(1, line.size() - 1)); @@ -264,7 +288,6 @@ namespace clay { eval(line); } } - engine->runStaticConstructorsDestructors(true); } static void exceptionHandler(int i) { @@ -284,12 +307,37 @@ namespace clay { llvm::errs() << ":globals to list globals\n"; llvm::errs() << "In multi-line mode empty line to exit\n"; - llvm::EngineBuilder eb(llvmModule); - llvm::TargetOptions targetOptions; - targetOptions.JITExceptionHandling = true; - eb.setTargetOptions(targetOptions); - engine = eb.create(); - engine->runStaticConstructorsDestructors(false); + auto expectedJIT = llvm::orc::LLJITBuilder().create(); + if (!expectedJIT) { + llvm::errs() << "error: could not create JIT: " << llvm::toString(expectedJIT.takeError()) << "\n"; + return; + } + jit = std::move(*expectedJIT); + + llvm::orc::JITDylib& mainDylib = jit->getMainJITDylib(); + + auto generatorExpected = llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( + jit->getDataLayout().getGlobalPrefix() + ); + + if (!generatorExpected) { + llvm::errs() << "error: setting up symbol" << llvm::toString(generatorExpected.takeError()) << "\n"; + } else { + std::unique_ptr generator = + std::move(*generatorExpected); + mainDylib.addGenerator(std::move(generator)); + } + + llvmModule->setDataLayout(jit->getDataLayout()); + + auto tsm = llvm::orc::ThreadSafeModule( + std::unique_ptr(llvmModule), + std::make_unique()); + + if (llvm::Error addIRErr = jit->addIRModule(std::move(tsm))) { + llvm::errs() << "error: " << addIRErr << "\n"; + return; + } setAddTokens(&addTokens); From 060cf372d06d8aad1489e42b96681c7e663c4056 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 06:01:53 -0500 Subject: [PATCH 25/56] Complete AssertionError --- compiler/ut.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/ut.hpp b/compiler/ut.hpp index 51e01da7..bbb6cb11 100644 --- a/compiler/ut.hpp +++ b/compiler/ut.hpp @@ -1,5 +1,7 @@ #pragma once +#include + namespace clay { typedef void (*TestFunc)(); @@ -15,7 +17,8 @@ namespace clay { static TestRegistrator_ ## NAME testRegistrator_ ## NAME; \ void NAME ## _testImpl() - struct AssertionError { + struct AssertionError : std::runtime_error { + AssertionError() : std::runtime_error("AssertionError") {} }; #define UT_FAIL() do { \ From 7fc94082c62202cb20376acef1abfde5af0985f4 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 06:06:38 -0500 Subject: [PATCH 26/56] Fix warnings with refcounted_ut.cpp --- compiler/refcounted_ut.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/refcounted_ut.cpp b/compiler/refcounted_ut.cpp index 05582979..0d61a641 100644 --- a/compiler/refcounted_ut.cpp +++ b/compiler/refcounted_ut.cpp @@ -1,13 +1,14 @@ -#include "refcounted.hpp" +#include +#include "refcounted.hpp" #include "ut.hpp" namespace clay { CLAY_UNITTEST(RefCounted_copy_constructor) { - Pointer p(new RefCounted); + Pointer p(new RefCounted); UT_ASSERT(p->getRefCount() == 1); - Pointer p2(new RefCounted(*p)); + Pointer p2(new RefCounted(*p)); UT_ASSERT(p->getRefCount() == 1); UT_ASSERT(p2->getRefCount() == 1); } From 4d1531be6f416b091aaa248e9725704942703f75 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 06:08:57 -0500 Subject: [PATCH 27/56] Mark getRefCount() with [[nodiscard]] --- compiler/refcounted.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/refcounted.hpp b/compiler/refcounted.hpp index 3ec490b4..286310a2 100644 --- a/compiler/refcounted.hpp +++ b/compiler/refcounted.hpp @@ -73,7 +73,7 @@ namespace clay { } } - int getRefCount() const { return refCount; } + [[nodiscard]] int getRefCount() const { return refCount; } virtual ~RefCounted() = default; }; From 3b5e594ee573df07d7fa62da585cc4478ad689ca Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 07:26:23 -0500 Subject: [PATCH 28/56] Add missing header for analyzer_op.cpp --- compiler/analyzer_op.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/analyzer_op.cpp b/compiler/analyzer_op.cpp index 792e28b5..0448f604 100644 --- a/compiler/analyzer_op.cpp +++ b/compiler/analyzer_op.cpp @@ -6,8 +6,9 @@ #include "env.hpp" #include "analyzer.hpp" - #include "analyzer_op.hpp" +#include "invoketables.hpp" +#include "printer.hpp" namespace clay { static size_t staticToSizeTOrIntValue(MultiPValue *args, size_t index) { From c26ef44f3a5f239ab6202b42854d2cb1d4ae19b9 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 08:07:08 -0500 Subject: [PATCH 29/56] Fix errors in claydoc.cpp --- compiler/claydoc.cpp | 56 +++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/compiler/claydoc.cpp b/compiler/claydoc.cpp index b9603319..a18fbba0 100644 --- a/compiler/claydoc.cpp +++ b/compiler/claydoc.cpp @@ -1,37 +1,40 @@ +#include +#include + #include "claydoc.hpp" #include "parser.hpp" + #include #include using namespace std; using namespace clay; -static void usage(char *argv0) { +static void usage(const char *argv0) { llvm::errs() << "usage: " << argv0 << " \n"; } -DocModule *docParseModule(string fileName, DocState *state, std::string fqn) { +DocModule *docParseModule(const string &fileName, DocState *state, const std::string& fqn) { SourcePtr src = new Source(fileName); ModulePtr m = parse(fileName, src, ParserKeepDocumentation); - DocModule *docMod = new DocModule; + auto *docMod = new DocModule; docMod->fileName = fileName; docMod->fqn = fqn; - DocSection *section = new DocSection; + auto *section = new DocSection; docMod->sections.push_back(section); DocumentationPtr lastAttachment; - for (vector::iterator i = m->topLevelItems.begin(); i != m->topLevelItems.end(); i++) { - TopLevelItemPtr item = *i; + for (const auto& item : m->topLevelItems) { if (!item) continue; std::string name = identifierString(item->name); switch (item->objKind) { case DOCUMENTATION: { - DocumentationPtr doc = ((Documentation *) item.ptr()); + DocumentationPtr doc = dynamic_cast(item.ptr()); if (doc->annotation.count(ModuleAnnotation)) { docMod->name = doc->annotation.find(ModuleAnnotation)->second; docMod->description = doc->text; @@ -46,16 +49,16 @@ DocModule *docParseModule(string fileName, DocState *state, std::string fqn) { break; } case OVERLOAD: - if (!!((clay::Overload *) item.ptr())->target) - name = ((clay::Overload *) item.ptr())->target->asString(); + if (!!dynamic_cast(item.ptr())->target) + name = dynamic_cast(item.ptr())->target->asString(); case RECORD_DECL: case PROCEDURE: { - DocObject *obj = new DocObject; + auto *obj = new DocObject; obj->item = item; obj->name = name; if (!!lastAttachment) { obj->description = lastAttachment->text; - lastAttachment = 0; + lastAttachment = nullptr; } section->objects.push_back(obj); @@ -109,28 +112,37 @@ int main(int argc, char **argv) { return 1; } - bool whatever; - if (llvm::sys::fs::create_directories(outputDir, whatever) != 0) { + bool whatever = false; + std::error_code ec; + + ec = llvm::sys::fs::create_directories(outputDir, whatever); + if (ec) { llvm::errs() << "cannot create output directory " << outputDir << "\n"; return 4; } - DocState *state = new DocState; + std::error_code ec2; + auto *state = new DocState; state->name = llvm::sys::path::filename(inputDir).str(); - llvm::error_code ec; - for (llvm::sys::fs::recursive_directory_iterator it(inputDir, ec), ite; it != ite; it.increment(ec)) { + for (llvm::sys::fs::recursive_directory_iterator it(inputDir, ec2), ite; it != ite; it.increment(ec)) { llvm::sys::fs::file_status status; - if (!it->status(status) && is_regular_file(status) && endsWith(it->path(), ".clay")) { + if (!it->status() && is_regular_file(status) && endsWith(it->path(), ".clay")) { std::string fqn; llvm::sys::path::const_iterator word = llvm::sys::path::begin(it->path()); - ++word; + llvm::sys::path::const_iterator path_end = llvm::sys::path::end(it->path()); + + if (word != path_end) + ++word; + + for (; word != path_end; ++word) { + llvm::sys::path::const_iterator next_word = word; + ++next_word; - llvm::sys::path::const_iterator worde = llvm::sys::path::end(it->path()); - --worde; + if (next_word == path_end) + break; - for (; word != worde; ++word) { fqn.append(*word); fqn.append("."); } @@ -148,7 +160,7 @@ int main(int argc, char **argv) { emitHtmlIndex(outputDir, state); } -std::string identifierString(clay::IdentifierPtr id) { +std::string identifierString(const IdentifierPtr& id) { if (!id) return {""}; return {id->str.str().begin(), id->str.str().end()}; From 8cd3c1586a20189761dc6a5b05ebbfbf66ecbff8 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 08:07:32 -0500 Subject: [PATCH 30/56] Small edit in claydoc.hpp with `const` --- compiler/claydoc.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/claydoc.hpp b/compiler/claydoc.hpp index e0b82d36..48ba7d8a 100644 --- a/compiler/claydoc.hpp +++ b/compiler/claydoc.hpp @@ -32,7 +32,7 @@ struct DocState { std::map modules; }; -std::string identifierString(clay::IdentifierPtr id); +std::string identifierString(const clay::IdentifierPtr& id); void emitHtmlModule(std::string outpath, DocModule *mod, std::string fqn); void emitHtmlIndex(std::string outpath, DocState *); From 57428116bc73472ce7dfbdabbe946ef6e1074608 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 09:08:04 -0500 Subject: [PATCH 31/56] Fix errors with strings in lambdas.cpp --- compiler/lambdas.cpp | 198 ++++++++++++++++++++----------------------- 1 file changed, 94 insertions(+), 104 deletions(-) diff --git a/compiler/lambdas.cpp b/compiler/lambdas.cpp index 95b8ed8b..f2f97e6b 100644 --- a/compiler/lambdas.cpp +++ b/compiler/lambdas.cpp @@ -7,6 +7,7 @@ #include "loader.hpp" #include "env.hpp" #include "error.hpp" +#include "printer.hpp" namespace clay { struct LambdaContext { @@ -16,7 +17,7 @@ namespace clay { vector &freeVars; LambdaContext(LambdaCapture captureBy, - EnvPtr nonLocalEnv, + const EnvPtr& nonLocalEnv, llvm::StringRef closureDataName, vector &freeVars) : captureBy(captureBy), nonLocalEnv(nonLocalEnv), @@ -24,40 +25,39 @@ namespace clay { } }; - void convertFreeVars(LambdaPtr x, EnvPtr env, + void convertFreeVars(const LambdaPtr &x, const EnvPtr &env, llvm::StringRef closureDataName, vector &freeVars); - void convertFreeVars(StatementPtr x, EnvPtr env, LambdaContext &ctx); + void convertFreeVars(const StatementPtr &x, EnvPtr env, LambdaContext &ctx); - void convertFreeVars(ExprPtr &x, EnvPtr env, LambdaContext &ctx); + void convertFreeVars(ExprPtr &x, const EnvPtr &env, LambdaContext &ctx); - void convertFreeVars(ExprList *x, EnvPtr env, LambdaContext &ctx); + void convertFreeVars(ExprList *x, const EnvPtr &env, LambdaContext &ctx); // // initializeLambda // - static TypePtr typeOfValue(ObjectPtr obj) { + static TypePtr typeOfValue(const ObjectPtr& obj) { switch (obj->objKind) { - case PVALUE: return ((PValue *) obj.ptr())->data.type; - case CVALUE: return ((CValue *) obj.ptr())->type; + case PVALUE: return dynamic_cast(obj.ptr())->data.type; + case CVALUE: return dynamic_cast(obj.ptr())->type; default: assert(false); - return nullptr; } } - static vector typesOfValues(ObjectPtr obj) { + static vector typesOfValues(const ObjectPtr &obj) { vector types; switch (obj->objKind) { case MULTI_PVALUE: { - MultiPValue *mpv = (MultiPValue *) obj.ptr(); + auto mpv = dynamic_cast(obj.ptr()); for (unsigned i = 0; i < mpv->size(); ++i) types.push_back(mpv->values[i].type); break; } case MULTI_CVALUE: { - MultiCValue *mcv = (MultiCValue *) obj.ptr(); + auto mcv = dynamic_cast(obj.ptr()); for (unsigned i = 0; i < mcv->size(); ++i) types.push_back(mcv->values[i]->type); break; @@ -68,13 +68,13 @@ namespace clay { return types; } - static void initializeLambdaWithFreeVars(LambdaPtr x, EnvPtr env, + static void initializeLambdaWithFreeVars(const LambdaPtr &x, const EnvPtr &env, llvm::StringRef closureDataName, llvm::StringRef lname); - static void initializeLambdaWithoutFreeVars(LambdaPtr x, EnvPtr env, + static void initializeLambdaWithoutFreeVars(const LambdaPtr &x, const EnvPtr &env, llvm::StringRef lname); - static string lambdaName(LambdaPtr x) { + static string lambdaName(const LambdaPtr &x) { string fullName = shortString(x->asString()); if (fullName.size() <= 80) @@ -86,11 +86,11 @@ namespace clay { printFileLineCol(shortName, x->location); shortName << ">"; - return shortName.str(); + return shortName.str().str(); // what is this abomination } } - void initializeLambda(LambdaPtr x, EnvPtr env) { + void initializeLambda(const LambdaPtr& x, const EnvPtr &env) { assert(!x->initialized); x->initialized = true; @@ -99,7 +99,7 @@ namespace clay { llvm::SmallString<128> buf; llvm::raw_svector_ostream ostr(buf); ostr << "%closureData:" << lname; - string closureDataName = ostr.str(); + string closureDataName = ostr.str().str(); // again convertFreeVars(x, env, closureDataName, x->freeVars); getProcedureMonoTypes(x->mono, env, x->formalArgs, x->hasVarArg); @@ -124,15 +124,15 @@ namespace clay { } } - static void checkForeignExpr(ObjectPtr &obj, EnvPtr env) { + static void checkForeignExpr(ObjectPtr &obj, const EnvPtr &env) { if (obj->objKind == EXPRESSION) { - ExprPtr expr = (Expr *) obj.ptr(); + ExprPtr expr = dynamic_cast(obj.ptr()); if (expr->exprKind == FOREIGN_EXPR) { MultiPValuePtr mpv = safeAnalyzeMulti(new ExprList(expr), env, 0); obj = mpv.ptr(); } } else if (obj->objKind == EXPR_LIST) { - ExprListPtr expr = (ExprList *) obj.ptr(); + ExprListPtr expr = dynamic_cast(obj.ptr()); switch (expr->exprs[0]->exprKind) { case FOREIGN_EXPR: case UNPACK: { @@ -146,7 +146,7 @@ namespace clay { } } - static void initializeLambdaWithFreeVars(LambdaPtr x, EnvPtr env, + static void initializeLambdaWithFreeVars(const LambdaPtr &x, const EnvPtr &env, llvm::StringRef closureDataName, llvm::StringRef lname) { RecordDeclPtr r = new RecordDecl(nullptr, PRIVATE); r->location = x->location; @@ -181,8 +181,7 @@ namespace clay { case MULTI_CVALUE: { vector types = typesOfValues(obj); vector elementTypes; - for (size_t j = 0; j < types.size(); ++j) { - TypePtr t = types[j]; + for (auto t : types) { if (x->captureBy == REF_CAPTURE) t = pointerType(t); elementTypes.push_back(t); @@ -221,9 +220,9 @@ namespace clay { code->location = x->location; IdentifierPtr closureDataIdent = Identifier::get(closureDataName); FormalArgPtr closureDataArg = new FormalArg(closureDataIdent, typeExpr); - code->formalArgs.push_back(closureDataArg.ptr()); - for (size_t i = 0; i < x->formalArgs.size(); ++i) { - code->formalArgs.push_back(x->formalArgs[i]); + code->formalArgs.emplace_back(closureDataArg.ptr()); + for (const auto & formalArg : x->formalArgs) { + code->formalArgs.push_back(formalArg); } code->hasVarArg = x->hasVarArg; code->body = x->body; @@ -236,11 +235,11 @@ namespace clay { ObjectPtr obj = operator_call(); if (obj->objKind != PROCEDURE) error("'call' operator not found!"); - Procedure *callObj = (Procedure *) obj.ptr(); + auto *callObj = dynamic_cast(obj.ptr()); addOverload(callObj->overloads, overload); } - static void initializeLambdaWithoutFreeVars(LambdaPtr x, EnvPtr env, + static void initializeLambdaWithoutFreeVars(const LambdaPtr &x, const EnvPtr &env, llvm::StringRef lname) { IdentifierPtr name = Identifier::get(lname, x->location); x->lambdaProc = new Procedure(nullptr, name, PRIVATE, false); @@ -248,8 +247,8 @@ namespace clay { CodePtr code = new Code(); code->location = x->location; - for (size_t i = 0; i < x->formalArgs.size(); ++i) { - code->formalArgs.push_back(x->formalArgs[i]); + for (const auto & formalArg : x->formalArgs) { + code->formalArgs.push_back(formalArg); } code->hasVarArg = x->hasVarArg; code->body = x->body; @@ -268,11 +267,10 @@ namespace clay { // addFreeVar, typeOfValue, typesOfValues // - static void addFreeVar(LambdaContext &ctx, llvm::StringRef str) { - vector::iterator i; - i = std::find(ctx.freeVars.begin(), ctx.freeVars.end(), str); + static void addFreeVar(const LambdaContext &ctx, llvm::StringRef str) { + auto i = std::find(ctx.freeVars.begin(), ctx.freeVars.end(), str); if (i == ctx.freeVars.end()) { - ctx.freeVars.push_back(str); + ctx.freeVars.push_back(str.str()); } } @@ -280,62 +278,57 @@ namespace clay { // convertFreeVars // - void convertFreeVars(LambdaPtr x, EnvPtr env, + void convertFreeVars(const LambdaPtr &x, const EnvPtr &env, llvm::StringRef closureDataName, vector &freeVars) { EnvPtr env2 = new Env(env); - for (size_t i = 0; i < x->formalArgs.size(); ++i) { - FormalArgPtr arg = x->formalArgs[i]; + for (const auto& arg : x->formalArgs) { addLocal(env2, arg->name, arg->name.ptr()); } LambdaContext ctx(x->captureBy, env, closureDataName, freeVars); convertFreeVars(x->body, env2, ctx); } - static EnvPtr convertFreeVarsFromBinding(BindingPtr binding, EnvPtr env, LambdaContext &ctx) { + static EnvPtr convertFreeVarsFromBinding(const BindingPtr &binding, const EnvPtr &env, LambdaContext &ctx) { convertFreeVars(binding->values.ptr(), env, ctx); EnvPtr env2 = new Env(env); - for (size_t j = 0; j < binding->args.size(); ++j) - addLocal(env2, binding->args[j]->name, binding->args[j]->name.ptr()); + for (const auto & arg : binding->args) + addLocal(env2, arg->name, arg->name.ptr()); return env2; } static EnvPtr convertFreeVarsFromStatementExpressionStatements( llvm::ArrayRef stmts, - EnvPtr env, + const EnvPtr &env, LambdaContext &ctx) { EnvPtr env2 = env; - for (StatementPtr const *i = stmts.begin(), *end = stmts.end(); - i != end; - ++i) { - switch ((*i)->stmtKind) { + for (const auto & stmt : stmts) { + switch (stmt->stmtKind) { case BINDING: - env2 = convertFreeVarsFromBinding((Binding *) i->ptr(), env2, ctx); + env2 = convertFreeVarsFromBinding(dynamic_cast(stmt.ptr()), env2, ctx); break; case ASSIGNMENT: case VARIADIC_ASSIGNMENT: case INIT_ASSIGNMENT: case EXPR_STATEMENT: - convertFreeVars(*i, env2, ctx); + convertFreeVars(stmt, env2, ctx); break; default: assert(false); - return nullptr; } } return env2; } - void convertFreeVars(StatementPtr x, EnvPtr env, LambdaContext &ctx) { + void convertFreeVars(const StatementPtr &x, EnvPtr env, LambdaContext &ctx) { switch (x->stmtKind) { case BLOCK: { - Block *y = (Block *) x.ptr(); - for (size_t i = 0; i < y->statements.size(); ++i) { - StatementPtr z = y->statements[i]; + auto y = dynamic_cast(x.ptr()); + for (const auto& z : y->statements) { if (z->stmtKind == BINDING) - env = convertFreeVarsFromBinding((Binding *) z.ptr(), env, ctx); + env = convertFreeVarsFromBinding(dynamic_cast(z.ptr()), env, ctx); else convertFreeVars(z, env, ctx); } @@ -348,21 +341,21 @@ namespace clay { } case ASSIGNMENT: { - Assignment *y = (Assignment *) x.ptr(); + auto *y = dynamic_cast(x.ptr()); convertFreeVars(y->left.ptr(), env, ctx); convertFreeVars(y->right.ptr(), env, ctx); break; } case INIT_ASSIGNMENT: { - InitAssignment *y = (InitAssignment *) x.ptr(); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->left.ptr(), env, ctx); convertFreeVars(y->right.ptr(), env, ctx); break; } case VARIADIC_ASSIGNMENT: { - VariadicAssignment *y = (VariadicAssignment *) x.ptr(); + auto *y = dynamic_cast(x.ptr()); convertFreeVars(y->exprs.ptr(), env, ctx); break; } @@ -372,13 +365,13 @@ namespace clay { } case RETURN: { - Return *y = (Return *) x.ptr(); + auto *y = dynamic_cast(x.ptr()); convertFreeVars(y->values.ptr(), env, ctx); break; } case IF: { - If *y = (If *) x.ptr(); + If *y = dynamic_cast(x.ptr()); env = convertFreeVarsFromStatementExpressionStatements(y->conditionStatements, env, ctx); convertFreeVars(y->condition, env, ctx); convertFreeVars(y->thenPart, env, ctx); @@ -388,11 +381,10 @@ namespace clay { } case SWITCH: { - Switch *y = (Switch *) x.ptr(); + auto y = dynamic_cast(x.ptr()); env = convertFreeVarsFromStatementExpressionStatements(y->exprStatements, env, ctx); convertFreeVars(y->expr, env, ctx); - for (size_t i = 0; i < y->caseBlocks.size(); ++i) { - CaseBlockPtr z = y->caseBlocks[i]; + for (const auto& z : y->caseBlocks) { convertFreeVars(z->caseLabels.ptr(), env, ctx); convertFreeVars(z->body, env, ctx); } @@ -402,19 +394,19 @@ namespace clay { } case EVAL_STATEMENT: { - EvalStatement *eval = (EvalStatement *) x.ptr(); + auto eval = dynamic_cast(x.ptr()); convertFreeVars(eval->args.ptr(), env, ctx); break; } case EXPR_STATEMENT: { - ExprStatement *y = (ExprStatement *) x.ptr(); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->expr, env, ctx); break; } case WHILE: { - While *y = (While *) x.ptr(); + auto y = dynamic_cast(x.ptr()); env = convertFreeVarsFromStatementExpressionStatements(y->conditionStatements, env, ctx); convertFreeVars(y->condition, env, ctx); convertFreeVars(y->body, env, ctx); @@ -427,11 +419,11 @@ namespace clay { } case FOR: { - For *y = (For *) x.ptr(); + For *y = dynamic_cast(x.ptr()); convertFreeVars(y->expr, env, ctx); EnvPtr env2 = new Env(env); - for (size_t j = 0; j < y->variables.size(); ++j) - addLocal(env2, y->variables[j], y->variables[j].ptr()); + for (const auto & variable : y->variables) + addLocal(env2, variable, variable.ptr()); convertFreeVars(y->body, env2, ctx); break; } @@ -441,24 +433,24 @@ namespace clay { } case TRY: { - Try *y = (Try *) x.ptr(); + Try *y = dynamic_cast(x.ptr()); convertFreeVars(y->tryBlock, env, ctx); - for (size_t i = 0; i < y->catchBlocks.size(); ++i) { + for (const auto & catchBlock : y->catchBlocks) { EnvPtr env2 = new Env(env); addLocal(env2, - y->catchBlocks[i]->exceptionVar, - y->catchBlocks[i]->exceptionVar.ptr() + catchBlock->exceptionVar, + catchBlock->exceptionVar.ptr() ); - if (y->catchBlocks[i]->exceptionType.ptr()) - convertFreeVars(y->catchBlocks[i]->exceptionType, env, ctx); - convertFreeVars(y->catchBlocks[i]->body, env2, ctx); + if (catchBlock->exceptionType.ptr()) + convertFreeVars(catchBlock->exceptionType, env, ctx); + convertFreeVars(catchBlock->body, env2, ctx); } break; } case THROW: { - Throw *y = (Throw *) x.ptr(); + auto y = dynamic_cast(x.ptr()); desugarThrow(y); convertFreeVars(y->desugaredExpr, env, ctx); if (y->desugaredContext != nullptr) @@ -467,7 +459,7 @@ namespace clay { } case STATIC_FOR: { - StaticFor *y = (StaticFor *) x.ptr(); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->values.ptr(), env, ctx); EnvPtr env2 = new Env(env); addLocal(env2, y->variable, y->variable.ptr()); @@ -476,20 +468,18 @@ namespace clay { } case FINALLY: { - Finally *y = (Finally *) x.ptr(); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->body, env, ctx); break; } case ONERROR: { - OnError *y = (OnError *) x.ptr(); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->body, env, ctx); break; } case UNREACHABLE: - break; - case STATIC_ASSERT_STATEMENT: break; @@ -498,7 +488,7 @@ namespace clay { } } - void convertFreeVars(ExprPtr &x, EnvPtr env, LambdaContext &ctx) { + void convertFreeVars(ExprPtr &x, const EnvPtr &env, LambdaContext &ctx) { switch (x->exprKind) { case BOOL_LITERAL: case INT_LITERAL: @@ -508,7 +498,7 @@ namespace clay { break; case NAME_REF: { - NameRef *y = (NameRef *) x.ptr(); + auto y = dynamic_cast(x.ptr()); bool isNonLocal = false; bool isGlobal = false; ObjectPtr z = lookupEnvEx(env, y->name, ctx.nonLocalEnv, @@ -551,16 +541,16 @@ namespace clay { } else if ((z->objKind == MULTI_PVALUE) || (z->objKind == MULTI_CVALUE)) { vector types = typesOfValues(z); bool allStatic = true; - for (size_t i = 0; i < types.size(); ++i) { - if (!isStaticOrTupleOfStatics(types[i])) { + for (const auto & type : types) { + if (!isStaticOrTupleOfStatics(type)) { allStatic = false; break; } } if (allStatic) { ExprListPtr args = new ExprList(); - for (size_t i = 0; i < types.size(); ++i) - args->add(new ObjectExpr(types[i].ptr())); + for (const auto & type : types) + args->add(new ObjectExpr(type.ptr())); CallPtr call = new Call(operator_expr_typesToRValues(), args); call->location = y->location; x = call.ptr(); @@ -600,33 +590,33 @@ namespace clay { } case TUPLE: { - Tuple *y = (Tuple *) x.ptr(); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->args.ptr(), env, ctx); break; } case PAREN: { - Paren *y = (Paren *) x.ptr(); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->args.ptr(), env, ctx); break; } case INDEXING: { - Indexing *y = (Indexing *) x.ptr(); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->expr, env, ctx); convertFreeVars(y->args.ptr(), env, ctx); break; } case CALL: { - Call *y = (Call *) x.ptr(); + Call *y = dynamic_cast(x.ptr()); convertFreeVars(y->expr, env, ctx); convertFreeVars(y->parenArgs.ptr(), env, ctx); break; } case FIELD_REF: { - FieldRef *y = (FieldRef *) x.ptr(); + auto y = dynamic_cast(x.ptr()); if (y->desugared == nullptr) desugarFieldRef(y, safeLookupModule(env)); if (!y->isDottedModuleName) @@ -635,60 +625,60 @@ namespace clay { } case STATIC_INDEXING: { - StaticIndexing *y = (StaticIndexing *) x.ptr(); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->expr, env, ctx); break; } case VARIADIC_OP: { - VariadicOp *y = (VariadicOp *) x.ptr(); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->exprs.ptr(), env, ctx); break; } case AND: { - And *y = (And *) x.ptr(); + And *y = dynamic_cast(x.ptr()); convertFreeVars(y->expr1, env, ctx); convertFreeVars(y->expr2, env, ctx); break; } case OR: { - Or *y = (Or *) x.ptr(); + Or *y = dynamic_cast(x.ptr()); convertFreeVars(y->expr1, env, ctx); convertFreeVars(y->expr2, env, ctx); break; } case LAMBDA: { - Lambda *y = (Lambda *) x.ptr(); + auto y = dynamic_cast(x.ptr()); EnvPtr env2 = new Env(env); - for (size_t i = 0; i < y->formalArgs.size(); ++i) - addLocal(env2, y->formalArgs[i]->name, y->formalArgs[i]->name.ptr()); + for (const auto & formalArg : y->formalArgs) + addLocal(env2, formalArg->name, formalArg->name.ptr()); convertFreeVars(y->body, env2, ctx); break; } case UNPACK: { - Unpack *y = (Unpack *) x.ptr(); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->expr, env, ctx); break; } case STATIC_EXPR: { - StaticExpr *y = (StaticExpr *) x.ptr(); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->expr, env, ctx); break; } case DISPATCH_EXPR: { - DispatchExpr *y = (DispatchExpr *) x.ptr(); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->expr, env, ctx); break; } case EVAL_EXPR: { - EvalExpr *eval = (EvalExpr *) x.ptr(); + auto eval = dynamic_cast(x.ptr()); convertFreeVars(eval->args, env, ctx); break; } @@ -703,7 +693,7 @@ namespace clay { } } - void convertFreeVars(ExprList *x, EnvPtr env, LambdaContext &ctx) { + void convertFreeVars(ExprList *x, const EnvPtr &env, LambdaContext &ctx) { for (unsigned i = 0; i < x->size(); ++i) convertFreeVars(x->exprs[i], env, ctx); } From 56d5f3b3f813fa61f627fafd7f05352fdfe4bae2 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 09:08:33 -0500 Subject: [PATCH 32/56] Update const ref to lambdas.hpp --- compiler/lambdas.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/lambdas.hpp b/compiler/lambdas.hpp index faf80384..a9310232 100644 --- a/compiler/lambdas.hpp +++ b/compiler/lambdas.hpp @@ -3,5 +3,5 @@ #include "clay.hpp" namespace clay { - void initializeLambda(LambdaPtr x, EnvPtr env); + void initializeLambda(const LambdaPtr& x, EnvPtr env); } From 7c04e76bf4f3c5d4a35c91741740fdeedb361380 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 09:19:22 -0500 Subject: [PATCH 33/56] Add printer.hpp header file to analyzer.cpp --- compiler/analyzer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/analyzer.cpp b/compiler/analyzer.cpp index a64b5d81..31c42724 100644 --- a/compiler/analyzer.cpp +++ b/compiler/analyzer.cpp @@ -17,6 +17,7 @@ #include "clone.hpp" #include "objects.hpp" #include "analyzer_op.hpp" +#include "printer.hpp" #pragma clang diagnostic ignored "-Wcovered-switch-default" From 160c4a3cceb48b97c9aaaad34d0299b038c4fb06 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 09:41:10 -0500 Subject: [PATCH 34/56] Update the use of `auto` in lambdas.cpp --- compiler/lambdas.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/lambdas.cpp b/compiler/lambdas.cpp index f2f97e6b..c6ae9c0b 100644 --- a/compiler/lambdas.cpp +++ b/compiler/lambdas.cpp @@ -341,7 +341,7 @@ namespace clay { } case ASSIGNMENT: { - auto *y = dynamic_cast(x.ptr()); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->left.ptr(), env, ctx); convertFreeVars(y->right.ptr(), env, ctx); break; @@ -355,7 +355,7 @@ namespace clay { } case VARIADIC_ASSIGNMENT: { - auto *y = dynamic_cast(x.ptr()); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->exprs.ptr(), env, ctx); break; } @@ -365,13 +365,13 @@ namespace clay { } case RETURN: { - auto *y = dynamic_cast(x.ptr()); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->values.ptr(), env, ctx); break; } case IF: { - If *y = dynamic_cast(x.ptr()); + auto y = dynamic_cast(x.ptr()); env = convertFreeVarsFromStatementExpressionStatements(y->conditionStatements, env, ctx); convertFreeVars(y->condition, env, ctx); convertFreeVars(y->thenPart, env, ctx); @@ -419,7 +419,7 @@ namespace clay { } case FOR: { - For *y = dynamic_cast(x.ptr()); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->expr, env, ctx); EnvPtr env2 = new Env(env); for (const auto & variable : y->variables) @@ -433,7 +433,7 @@ namespace clay { } case TRY: { - Try *y = dynamic_cast(x.ptr()); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->tryBlock, env, ctx); for (const auto & catchBlock : y->catchBlocks) { EnvPtr env2 = new Env(env); @@ -609,7 +609,7 @@ namespace clay { } case CALL: { - Call *y = dynamic_cast(x.ptr()); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->expr, env, ctx); convertFreeVars(y->parenArgs.ptr(), env, ctx); break; @@ -637,14 +637,14 @@ namespace clay { } case AND: { - And *y = dynamic_cast(x.ptr()); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->expr1, env, ctx); convertFreeVars(y->expr2, env, ctx); break; } case OR: { - Or *y = dynamic_cast(x.ptr()); + auto y = dynamic_cast(x.ptr()); convertFreeVars(y->expr1, env, ctx); convertFreeVars(y->expr2, env, ctx); break; From f91cb78e032e1fdec5f3c9450c54429ed22968bb Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 09:49:46 -0500 Subject: [PATCH 35/56] Remove `const` from `setSearchPath` in loader.hpp --- compiler/loader.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/loader.hpp b/compiler/loader.hpp index 20a860df..8eaa5759 100644 --- a/compiler/loader.hpp +++ b/compiler/loader.hpp @@ -14,7 +14,7 @@ namespace clay { llvm::ArrayRef formalArgs, bool hasVarArg); void initLoader(); - void setSearchPath(const llvm::ArrayRef path); + void setSearchPath(llvm::ArrayRef path); ModulePtr loadProgram(llvm::StringRef fileName, vector *sourceFiles, bool verbose, bool repl); ModulePtr loadProgramSource(llvm::StringRef name, llvm::StringRef source, bool verbose, bool repl); ModulePtr loadedModule(llvm::StringRef module); From 924f194b6521c08ab160ff6a86941b6c5c8c44e9 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 09:53:03 -0500 Subject: [PATCH 36/56] Update `staticPValue` and remove unused header in analyzer.hpp --- compiler/analyzer.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/analyzer.hpp b/compiler/analyzer.hpp index f2ee6e91..ee73296b 100644 --- a/compiler/analyzer.hpp +++ b/compiler/analyzer.hpp @@ -2,7 +2,6 @@ #include "clay.hpp" -// #include "invoketables.hpp" #include "types.hpp" namespace clay { @@ -24,9 +23,9 @@ namespace clay { bool staticToCallingConv(ObjectPtr x, CallingConv &out); CallingConv staticToCallingConv(MultiStaticPtr x, unsigned index); - static inline PVData staticPValue(ObjectPtr x) { + static PVData staticPValue(const ObjectPtr& x) { const TypePtr t = staticType(x); - return PVData(t, true); + return {t, true}; } enum BoolKind { From 1fb70fd8273214c3f7a936b44031e50bdbc47c79 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 10:15:29 -0500 Subject: [PATCH 37/56] Fix warnings found in parser.cpp --- compiler/parser.cpp | 91 ++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/compiler/parser.cpp b/compiler/parser.cpp index 13698281..2d79761b 100644 --- a/compiler/parser.cpp +++ b/compiler/parser.cpp @@ -24,7 +24,7 @@ namespace clay { if (inRepl) { assert(addTokens != nullptr); vector toks = addTokens(); - if (toks.size() == 0) { + if (toks.empty()) { inRepl = false; return false; } @@ -50,7 +50,7 @@ namespace clay { static Location currentLocation() { if (position == tokens->size()) - return Location(); + return {}; return (*tokens)[position].location; } @@ -278,10 +278,9 @@ namespace clay { } static bool expressionList(ExprListPtr &x, bool = false) { - ExprListPtr a; ExprPtr b; if (!expression(b)) return false; - a = new ExprList(b); + ExprListPtr a = new ExprList(b); while (true) { unsigned p = save(); if (!symbol(",")) { @@ -481,30 +480,30 @@ namespace clay { return false; } - static void setSuffixBase(Expr *a, ExprPtr base) { + static void setSuffixBase(Expr *a, const ExprPtr &base) { switch (a->exprKind) { case INDEXING: { - Indexing *b = (Indexing *) a; + auto b = dynamic_cast(a); b->expr = base; break; } case CALL: { - Call *b = (Call *) a; + Call *b = dynamic_cast(a); b->expr = base; break; } case FIELD_REF: { - FieldRef *b = (FieldRef *) a; + auto b = dynamic_cast(a); b->expr = base; break; } case STATIC_INDEXING: { - StaticIndexing *b = (StaticIndexing *) a; + auto b = dynamic_cast(a); b->expr = base; break; } case VARIADIC_OP: { - VariadicOp *b = (VariadicOp *) a; + auto *b = dynamic_cast(a); assert(b->op == DEREFERENCE); b->exprs->add(base); break; @@ -1033,7 +1032,7 @@ namespace clay { static bool optPatternVarsWithCond(vector &x, ExprPtr &y); - static bool bindingsBody(vector &args, bool &hasVarArg); + static bool bindingsBody(vector &x, bool &hasVarArg); static bool localBinding(StatementPtr &x) { Location location = currentLocation(); @@ -1146,7 +1145,7 @@ namespace clay { if (!symbol(";")) return false; ExprListPtr exprs = new ExprList(new NameRef(Identifier::get(op, true))); if (z->exprKind == VARIADIC_OP) { - VariadicOp *y = (VariadicOp *) z.ptr(); + auto y = dynamic_cast(z.ptr()); exprs->add(y->exprs); } else { exprs->add(z); @@ -1167,8 +1166,8 @@ namespace clay { ExprListPtr exprs = new ExprList(new NameRef(Identifier::get(op, true))); exprs->add(y); if (z->exprKind == VARIADIC_OP) { - VariadicOp *y = (VariadicOp *) z.ptr(); - exprs->add(y->exprs); + auto variadic_op = dynamic_cast(z.ptr()); + exprs->add(variadic_op->exprs); } else { exprs->add(z); } @@ -1694,7 +1693,7 @@ namespace clay { return true; } - static FormalArgPtr makeStaticFormalArg(size_t index, ExprPtr expr, Location const &location) { + static FormalArgPtr makeStaticFormalArg(size_t index, const ExprPtr &expr, Location const &location) { // desugar static args llvm::SmallString<128> buf; llvm::raw_svector_ostream sout(buf); @@ -1889,12 +1888,12 @@ namespace clay { } else { int bracket = 1; while (bracket) { - unsigned p = save(); + unsigned i = save(); if (symbol("[")) { ++bracket; continue; } - restore(p); + restore(i); if (symbol("]")) --bracket; } @@ -2285,7 +2284,7 @@ namespace clay { if (symbol(":")) { if (!optReturnTypeList(returnSpecs)) return false; if (!optVarReturnType(varReturnSpec)) return false; - if (returnSpecs.size() > 0 || varReturnSpec != nullptr) + if (!returnSpecs.empty() || varReturnSpec != nullptr) exprRetSpecs = true; return true; } else { @@ -2312,7 +2311,7 @@ namespace clay { // static bool isOverload(bool &isDefault) { - int p = save(); + int p = static_cast(save()); if (keyword("overload")) isDefault = false; else if (restore(p), keyword("default")) @@ -2394,7 +2393,7 @@ namespace clay { ProcedurePtr u = new Procedure(module, z, vis, true); u->location = location; - x.push_back(u.ptr()); + x.emplace_back(u.ptr()); ExprPtr target = new NameRef(z); target->location = location; @@ -2402,7 +2401,7 @@ namespace clay { target->endLocation = targetEndLocation; OverloadPtr v = new Overload(module, target, y, false, isInline, hasAsConversion); v->location = location; - x.push_back(v.ptr()); + x.emplace_back(v.ptr()); u->singleOverload = v; @@ -2444,7 +2443,7 @@ namespace clay { ProcedurePtr proc = new Procedure(module, name, vis, privateOverload, interface); proc->location = location; - x.push_back(proc.ptr()); + x.emplace_back(proc.ptr()); return true; } @@ -2475,14 +2474,14 @@ namespace clay { if (!body(code->body)) return false; code->location = location; if (exprRetSpecs && code->body->stmtKind == RETURN) { - Return *x = (Return *) code->body.ptr(); - if (x->isExprReturn) - x->isReturnSpecs = true; + auto return_ = dynamic_cast(code->body.ptr()); + if (return_->isExprReturn) + return_->isReturnSpecs = true; } ProcedurePtr proc = new Procedure(module, name, vis, true); proc->location = location; - x.push_back(proc.ptr()); + x.emplace_back(proc.ptr()); ExprPtr target = new NameRef(name); target->location = location; @@ -2490,7 +2489,7 @@ namespace clay { target->endLocation = targetEndLocation; OverloadPtr oload = new Overload(module, target, code, callByName, isInline, hasAsConversion); oload->location = location; - x.push_back(oload.ptr()); + x.emplace_back(oload.ptr()); proc->singleOverload = oload; @@ -2542,9 +2541,9 @@ namespace clay { if (!llvmCode(code->llvmBody)) return false; } if (exprRetSpecs && code->body->stmtKind == RETURN) { - Return *x = (Return *) code->body.ptr(); - if (x->isExprReturn) - x->isReturnSpecs = true; + auto return_ = dynamic_cast(code->body.ptr()); + if (return_->isExprReturn) + return_->isReturnSpecs = true; } target->location = location; target->startLocation = targetStartLocation; @@ -2975,7 +2974,7 @@ namespace clay { Location location = currentLocation(); Token *t; if (!next(t) || t->tokenKind != T_DOC_PROPERTY) return false; - llvm::StringRef key = llvm::StringRef(t->str); + auto key = llvm::StringRef(t->str); DocumentationAnnotation ano; if (key == "section") { @@ -2993,7 +2992,7 @@ namespace clay { } if (!next(t) || t->tokenKind != T_DOC_TEXT) return false; - llvm::StringRef value = llvm::StringRef(t->str); + auto value = llvm::StringRef(t->str); an.insert(std::pair(ano, value.str())); return true; @@ -3173,22 +3172,22 @@ namespace clay { break; } - unsigned p = save(); + unsigned i = save(); if (!topLevelItem(x.toplevels, nullptr)) { - restore(p); + restore(i); } else { continue; } if (!import(x.imports)) { - restore(p); + restore(i); } else { continue; } if (!blockItem(stmtItem)) { - restore(p); + restore(i); break; } else { x.stmts.push_back(stmtItem); @@ -3205,7 +3204,7 @@ namespace clay { // template - void applyParser(SourcePtr source, unsigned offset, size_t length, Parser parser, ParserParam parserParam, + void applyParser(const SourcePtr& source, unsigned offset, size_t length, Parser parser, ParserParam parserParam, Node &node) { vector t; tokenize(source, offset, length, t); @@ -3216,7 +3215,7 @@ namespace clay { if (!parser(node, parserParam) || (position < t.size())) { Location location; if (maxPosition == t.size()) - location = Location(source.ptr(), unsigned(source->size())); + location = Location(source.ptr(), static_cast(source->size())); else location = t[maxPosition].location; pushLocation(location); @@ -3229,11 +3228,11 @@ namespace clay { struct ModuleParser { llvm::StringRef moduleName; - bool operator()(ModulePtr &m, Module *) { return module(moduleName, m); } + bool operator()(ModulePtr &m, Module *) const { return module(moduleName, m); } }; - ModulePtr parse(llvm::StringRef moduleName, SourcePtr source, ParserFlags flags) { - if (flags && ParserKeepDocumentation) + ModulePtr parse(llvm::StringRef moduleName, const SourcePtr &source, ParserFlags flags) { + if (flags) parserOptionKeepDocumentation = true; ModulePtr m; ModuleParser p = {moduleName}; @@ -3246,7 +3245,7 @@ namespace clay { // parseExpr // - ExprPtr parseExpr(SourcePtr source, unsigned offset, size_t length) { + ExprPtr parseExpr(const SourcePtr &source, unsigned offset, size_t length) { ExprPtr expr; applyParser(source, offset, length, expression, false, expr); return expr; @@ -3256,7 +3255,7 @@ namespace clay { // parseExprList // - ExprListPtr parseExprList(SourcePtr source, unsigned offset, size_t length) { + ExprListPtr parseExprList(const SourcePtr &source, unsigned offset, size_t length) { ExprListPtr exprList; applyParser(source, offset, length, expressionList, false, exprList); return exprList; @@ -3266,7 +3265,7 @@ namespace clay { // parseStatements // - void parseStatements(SourcePtr source, unsigned offset, size_t length, + void parseStatements(const SourcePtr &source, unsigned offset, size_t length, vector &stmts) { applyParser(source, offset, length, blockItems, false, stmts); } @@ -3275,7 +3274,7 @@ namespace clay { // parseTopLevelItems // - void parseTopLevelItems(SourcePtr source, unsigned offset, size_t length, + void parseTopLevelItems(const SourcePtr &source, unsigned offset, size_t length, vector &topLevels, Module *module) { applyParser(source, offset, length, topLevelItems, module, topLevels); } @@ -3284,7 +3283,7 @@ namespace clay { // parseInteractive // - ReplItem parseInteractive(SourcePtr source, unsigned offset, size_t length) { + ReplItem parseInteractive(const SourcePtr &source, unsigned offset, size_t length) { ReplItem x; applyParser(source, offset, length, replItems, false, x); return x; From 624e35920314568c0db7ec841bd9a68eacdcd513 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 10:23:04 -0500 Subject: [PATCH 38/56] Add missing printer.hpp header file for invoketables.cpp --- compiler/invoketables.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/invoketables.cpp b/compiler/invoketables.cpp index b8c6789b..d80935b2 100644 --- a/compiler/invoketables.cpp +++ b/compiler/invoketables.cpp @@ -5,6 +5,7 @@ #include "constructors.hpp" #include "clone.hpp" #include "objects.hpp" +#include "printer.hpp" #pragma clang diagnostic ignored "-Wcovered-switch-default" From 7d19e8d7b159c0b0c497d8ab623163772c138c64 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 10:35:39 -0500 Subject: [PATCH 39/56] Add const ref to header to match definitions --- compiler/parser.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/parser.hpp b/compiler/parser.hpp index 3af1a3a9..a8243843 100644 --- a/compiler/parser.hpp +++ b/compiler/parser.hpp @@ -17,19 +17,19 @@ namespace clay { vector stmts; }; - ModulePtr parse(llvm::StringRef moduleName, SourcePtr source, ParserFlags flags = NoParserFlags); + ModulePtr parse(llvm::StringRef moduleName, const SourcePtr &source, ParserFlags flags = NoParserFlags); - ExprPtr parseExpr(SourcePtr source, unsigned offset, size_t length); + ExprPtr parseExpr(const SourcePtr &source, unsigned offset, size_t length); - ExprListPtr parseExprList(SourcePtr source, unsigned offset, size_t length); + ExprListPtr parseExprList(const SourcePtr &source, unsigned offset, size_t length); - void parseStatements(SourcePtr source, unsigned offset, size_t length, + void parseStatements(const SourcePtr &source, unsigned offset, size_t length, vector &statements); - void parseTopLevelItems(SourcePtr source, unsigned offset, size_t length, + void parseTopLevelItems(const SourcePtr &source, unsigned offset, size_t length, vector &topLevels, Module *); - ReplItem parseInteractive(SourcePtr source, unsigned offset, size_t length); + ReplItem parseInteractive(const SourcePtr &source, unsigned offset, size_t length); typedef vector (*AddTokensCallback)(); From 7597805413866e803a2b6971214f009756664d11 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 10:58:09 -0500 Subject: [PATCH 40/56] Change out the deprecated isX86_MMXTy call --- compiler/analyzer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/analyzer.cpp b/compiler/analyzer.cpp index 31c42724..edf9018b 100644 --- a/compiler/analyzer.cpp +++ b/compiler/analyzer.cpp @@ -1443,7 +1443,7 @@ namespace clay { } return; case IITDescriptor::MMX: - if (!Ty->isX86_MMXTy()) { + if (!Ty->isX86_AMXTy()) { errors << "intrinsic argument " << (ai + 1) << " must match LLVM MMX type, but got "; Ty->print(errors); From b9e892cfac8d5181b09e774363e8c4e0ba01b41d Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 10:59:10 -0500 Subject: [PATCH 41/56] Update the IITDescriptor::Vector case in analyzer.cpp --- compiler/analyzer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/analyzer.cpp b/compiler/analyzer.cpp index edf9018b..d471bd9c 100644 --- a/compiler/analyzer.cpp +++ b/compiler/analyzer.cpp @@ -1480,11 +1480,11 @@ namespace clay { return; case IITDescriptor::Vector: { llvm::VectorType *VT = dyn_cast(Ty); - if (VT == 0) { + if (VT == nullptr) { errors << "intrinsic argument " << (ai + 1) << " must be of an LLVM vector type, but got "; Ty->print(errors); - } else if (VT->getNumElements() != D.Vector_Width) { + } else if (VT->getElementCount() != D.Vector_Width) { errors << "intrinsic argument " << (ai + 1) << " must be of an LLVM vector type with " << D.Vector_Width From ff31c4c4c09efdc72518868ab8214dd2a16c5822 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 11:01:20 -0500 Subject: [PATCH 42/56] Fix some ambiguous function calls using const ref in types.cpp --- compiler/analyzer.cpp | 6 ++---- compiler/types.cpp | 38 +++++++++++++++++++------------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/compiler/analyzer.cpp b/compiler/analyzer.cpp index d471bd9c..8cb92b27 100644 --- a/compiler/analyzer.cpp +++ b/compiler/analyzer.cpp @@ -56,8 +56,7 @@ namespace clay { params(params), varParam(varParam), expr(expr) { } - GlobalVariable::~GlobalVariable() { - } + GlobalVariable::~GlobalVariable() = default; static StatementAnalysis analyzeStatement(StatementPtr stmt, EnvPtr env, AnalysisContext *ctx); @@ -220,8 +219,7 @@ namespace clay { static vector analysisErrorCompileContext; struct ClearAnalysisError { - ClearAnalysisError() { - } + ClearAnalysisError() = default; ~ClearAnalysisError() { analysisErrorLocation = Location(); diff --git a/compiler/types.cpp b/compiler/types.cpp index 055c45e9..8e5635af 100644 --- a/compiler/types.cpp +++ b/compiler/types.cpp @@ -250,7 +250,7 @@ namespace clay { TypePtr cCodePointerType(CallingConv callingConv, llvm::ArrayRef argTypes, bool hasVarArgs, - TypePtr returnType) { + const TypePtr& returnType) { unsigned h = unsigned(callingConv) * 100; for (unsigned i = 0; i < argTypes.size(); ++i) { h += pointerHash(argTypes[i].ptr()); @@ -277,7 +277,7 @@ namespace clay { return t.ptr(); } - TypePtr arrayType(TypePtr elementType, unsigned size) { + TypePtr arrayType(const TypePtr& elementType, const unsigned size) { unsigned h = pointerHash(elementType.ptr()) + size; h &= unsigned(arrayTypes.size() - 1); vector::iterator i, end; @@ -292,7 +292,7 @@ namespace clay { return t.ptr(); } - TypePtr vecType(TypePtr elementType, unsigned size) { + TypePtr vecType(const TypePtr& elementType, const unsigned size) { if (elementType->typeKind != INTEGER_TYPE && elementType->typeKind != FLOAT_TYPE) error("Vec element type must be an integer or float type"); unsigned h = pointerHash(elementType.ptr()) + size; @@ -329,7 +329,7 @@ namespace clay { return t.ptr(); } - TypePtr unionType(llvm::ArrayRef memberTypes) { + TypePtr unionType(const llvm::ArrayRef memberTypes) { unsigned h = 0; TypePtr const *mi, *mend; for (mi = memberTypes.begin(), mend = memberTypes.end(); @@ -349,7 +349,7 @@ namespace clay { return t.ptr(); } - TypePtr recordType(RecordDeclPtr record, llvm::ArrayRef params) { + TypePtr recordType(const RecordDeclPtr& record, llvm::ArrayRef params) { unsigned h = pointerHash(record.ptr()); ObjectPtr const *pi, *pend; for (pi = params.begin(), pend = params.end(); pi != pend; ++pi) @@ -370,7 +370,7 @@ namespace clay { return t.ptr(); } - TypePtr variantType(VariantDeclPtr variant, llvm::ArrayRef params) { + TypePtr variantType(const VariantDeclPtr& variant, llvm::ArrayRef params) { unsigned h = pointerHash(variant.ptr()); for (unsigned i = 0; i < params.size(); ++i) h += objectHash(params[i]); @@ -388,7 +388,7 @@ namespace clay { return t.ptr(); } - TypePtr staticType(ObjectPtr obj) { + TypePtr staticType(const ObjectPtr& obj) { unsigned h = objectHash(obj); h &= unsigned(staticTypes.size() - 1); vector &bucket = staticTypes[h]; @@ -412,13 +412,13 @@ namespace clay { t->initialized = true; } - TypePtr enumType(EnumDeclPtr enumeration) { + TypePtr enumType(const EnumDeclPtr& enumeration) { if (!enumeration->type) enumeration->type = new EnumType(enumeration); return enumeration->type; } - void initializeNewType(NewTypePtr t) { + void initializeNewType(const NewTypePtr& t) { if (t->newtype->initialized) return; CompileContextPusher pusher(t.ptr()); @@ -426,13 +426,13 @@ namespace clay { t->newtype->initialized = true; } - TypePtr newType(NewTypeDeclPtr newtype) { + TypePtr newType(const NewTypeDeclPtr& newtype) { if (!newtype->type) newtype->type = new NewType(newtype); return newtype->type.ptr(); } - TypePtr newtypeReprType(NewTypePtr t) { + TypePtr newtypeReprType(const NewTypePtr& t) { if (!t->newtype->initialized) initializeNewType(t); return t->newtype->baseType; @@ -640,7 +640,7 @@ namespace clay { setProperty(type, props[i]); } - void initializeRecordFields(RecordTypePtr t) { + void initializeRecordFields(const RecordTypePtr& t) { CompileContextPusher pusher(t.ptr()); assert(!t->fieldsInitialized); @@ -727,7 +727,7 @@ namespace clay { return t->fieldNames; } - llvm::ArrayRef recordFieldTypes(RecordTypePtr t) { + llvm::ArrayRef recordFieldTypes(const RecordTypePtr& t) { if (!t->fieldsInitialized) initializeRecordFields(t); return t->fieldTypes; @@ -743,14 +743,14 @@ namespace clay { // variantMemberTypes, variantReprType, dispatchTagCount // - static TypePtr getVariantReprType(VariantTypePtr t) { + static TypePtr getVariantReprType(const VariantTypePtr& t) { ExprPtr variantReprType = operator_expr_variantReprType(); ExprPtr reprExpr = new Call(variantReprType, new ExprList(new ObjectExpr(t.ptr()))); return evaluateType(reprExpr, new Env()); } - static void initializeVariantType(VariantTypePtr t) { + static void initializeVariantType(const VariantTypePtr& t) { assert(!t->initialized); CompileContextPusher pusher(t.ptr()); @@ -987,7 +987,7 @@ namespace clay { static void defineLLVMType(TypePtr t); - static void makeLLVMType(TypePtr t); + static void makeLLVMType(const TypePtr& t); llvm::PointerType *llvmPointerType(TypePtr t) { if (!t->llType) @@ -1024,7 +1024,7 @@ namespace clay { // llvmType // - static void makeLLVMType(TypePtr t) { + static void makeLLVMType(const TypePtr& t) { if (t->llType == nullptr) { verifyRecursionCorrectness(t); declareLLVMType(t); @@ -1034,7 +1034,7 @@ namespace clay { } } - llvm::Type *llvmType(TypePtr t) { + llvm::Type *llvmType(const TypePtr& t) { makeLLVMType(t); return t->llType; @@ -1050,7 +1050,7 @@ namespace clay { return theType; } - llvm::DIType llvmTypeDebugInfo(TypePtr t) { + llvm::DIType llvmTypeDebugInfo(const TypePtr& t) { if (t->llType == nullptr) declareLLVMType(t); From 52f7b750c92ac31b8d2c80d08af819813633239c Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 11:20:10 -0500 Subject: [PATCH 43/56] Use TrackingMDNodeRef for DISubprogram debug info and fix warnings --- compiler/invoketables.hpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/compiler/invoketables.hpp b/compiler/invoketables.hpp index 764885b4..19815b6e 100644 --- a/compiler/invoketables.hpp +++ b/compiler/invoketables.hpp @@ -7,12 +7,14 @@ namespace clay { struct InvokeSet; struct InvokeEntry; - static llvm::SpecificBumpPtrAllocator *invokeEntryAllocator + static auto invokeEntryAllocator = new llvm::SpecificBumpPtrAllocator(); - static llvm::SpecificBumpPtrAllocator *invokeSetAllocator + static auto invokeSetAllocator = new llvm::SpecificBumpPtrAllocator(); struct InvokeEntry { + virtual ~InvokeEntry() = default; + InvokeSet *parent; ObjectPtr callable; vector argsKey; @@ -36,9 +38,9 @@ namespace clay { vector returnTypes; llvm::Function *llvmFunc; - llvm::Function *llvmCWrappers[CC_Count]; + llvm::Function *llvmCWrappers[CC_Count]{}; - llvm::TrackingVH debugInfo; + llvm::TrackingMDNodeRef debugInfo; bool analyzed: 1; bool analyzing: 1; @@ -46,7 +48,7 @@ namespace clay { bool runtimeNop: 1; InvokeEntry(InvokeSet *parent, - ObjectPtr callable, + const ObjectPtr &callable, llvm::ArrayRef argsKey) : parent(parent), callable(callable), argsKey(argsKey), @@ -58,8 +60,8 @@ namespace clay { analyzing(false), callByName(false), runtimeNop(false) { - for (size_t i = 0; i < CC_Count; ++i) - llvmCWrappers[i] = nullptr; + for (auto & llvmCWrapper : llvmCWrappers) + llvmCWrapper = nullptr; } void *operator new(size_t num_bytes) { @@ -67,12 +69,16 @@ namespace clay { } virtual void dealloc() { ANodeAllocator->Deallocate(this); } - llvm::DISubprogram getDebugInfo() { return llvm::DISubprogram(debugInfo); } + llvm::DISubprogram *getDebugInfo() const { + return llvm::dyn_cast_or_null(debugInfo.get()); + } }; extern vector patternOverloads; struct InvokeSet { + virtual ~InvokeSet() = default; + ObjectPtr callable; vector argsKey; OverloadPtr interface; @@ -87,9 +93,9 @@ namespace clay { bool shouldLog: 1; bool evaluatingPredicate: 1; - InvokeSet(ObjectPtr callable, + InvokeSet(const ObjectPtr &callable, llvm::ArrayRef argsKey, - OverloadPtr symbolInterface, + const OverloadPtr &symbolInterface, llvm::ArrayRef symbolOverloads) : callable(callable), argsKey(argsKey), interface(symbolInterface), From f561ea25c7f20a0b78440e2a6250d3bd473fabe3 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 11:28:29 -0500 Subject: [PATCH 44/56] Apply .get() on buffer in desugar.cpp --- compiler/desugar.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/desugar.cpp b/compiler/desugar.cpp index 15c852f1..73cabcbb 100644 --- a/compiler/desugar.cpp +++ b/compiler/desugar.cpp @@ -7,6 +7,7 @@ #include "clone.hpp" #include "objects.hpp" #include "error.hpp" +#include "printer.hpp" namespace clay { ExprPtr desugarCharLiteral(char c) { @@ -402,7 +403,7 @@ namespace clay { sourceNameOut << ">"; return new Source(sourceNameOut.str(), - llvm::MemoryBuffer::getMemBufferCopy(sourceTextBuf)); + llvm::MemoryBuffer::getMemBufferCopy(sourceTextBuf).get()); } ExprListPtr desugarEvalExpr(EvalExprPtr eval, EnvPtr env) { From e3a3f9614f3c5b97748155296efca0166786f8a3 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sat, 13 Dec 2025 12:35:43 -0500 Subject: [PATCH 45/56] Define modern AttributeList and include FoldingSet --- compiler/externals.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/externals.hpp b/compiler/externals.hpp index dbdb107f..b5f6f284 100644 --- a/compiler/externals.hpp +++ b/compiler/externals.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include "clay.hpp" #include "codegen.hpp" @@ -41,7 +43,7 @@ namespace clay { llvm::CallingConv::ID llConv; ArgInfo retInfo; vector argInfos; - vector> attrs; + llvm::AttributeList attrs; ExternalFunction(CallingConv conv, TypePtr ret, vector &args, size_t numReqArg, From 0ccd673b7bf90a97a6b05ecc3221ec23fa23f711 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sun, 14 Dec 2025 04:59:18 -0500 Subject: [PATCH 46/56] Add .gitattributes --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..bc8bc344 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.clay linguist-language=C From 70ccdef7774c3b8760b81ec50e396e1203c7013f Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sun, 14 Dec 2025 08:29:07 -0500 Subject: [PATCH 47/56] Fix the header situation with llvm in clay.hpp --- compiler/analyzer.cpp | 2 -- compiler/analyzer_op.cpp | 2 -- compiler/clay.cpp | 29 ----------------------------- compiler/clay.hpp | 35 ++++++++++++++++++++++++++++++++++- compiler/claydoc.cpp | 6 +++--- compiler/codegen_op.cpp | 2 +- compiler/desugar.cpp | 3 +-- compiler/error.cpp | 2 ++ compiler/error.hpp | 3 +-- compiler/interactive.cpp | 3 --- compiler/invoketables.cpp | 1 - compiler/lambdas.cpp | 1 - compiler/loader.cpp | 2 ++ compiler/loader.hpp | 1 - compiler/profiler.cpp | 1 - 15 files changed, 44 insertions(+), 49 deletions(-) diff --git a/compiler/analyzer.cpp b/compiler/analyzer.cpp index 8cb92b27..631f9bbf 100644 --- a/compiler/analyzer.cpp +++ b/compiler/analyzer.cpp @@ -1,4 +1,3 @@ - #include "clay.hpp" #include "evaluator.hpp" #include "codegen.hpp" @@ -17,7 +16,6 @@ #include "clone.hpp" #include "objects.hpp" #include "analyzer_op.hpp" -#include "printer.hpp" #pragma clang diagnostic ignored "-Wcovered-switch-default" diff --git a/compiler/analyzer_op.cpp b/compiler/analyzer_op.cpp index 0448f604..b1ace831 100644 --- a/compiler/analyzer_op.cpp +++ b/compiler/analyzer_op.cpp @@ -4,11 +4,9 @@ #include "constructors.hpp" #include "loader.hpp" #include "env.hpp" - #include "analyzer.hpp" #include "analyzer_op.hpp" #include "invoketables.hpp" -#include "printer.hpp" namespace clay { static size_t staticToSizeTOrIntValue(MultiPValue *args, size_t index) { diff --git a/compiler/clay.cpp b/compiler/clay.cpp index 2561a6ab..2b1b76db 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -1,32 +1,3 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include #include diff --git a/compiler/clay.hpp b/compiler/clay.hpp index 83433e3c..5013752c 100644 --- a/compiler/clay.hpp +++ b/compiler/clay.hpp @@ -17,7 +17,6 @@ #pragma warning(disable: 4146 4244 4267 4355 4146 4800 4996) #endif -#include #include #include #include @@ -34,6 +33,40 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/compiler/claydoc.cpp b/compiler/claydoc.cpp index a18fbba0..f691e46c 100644 --- a/compiler/claydoc.cpp +++ b/compiler/claydoc.cpp @@ -1,12 +1,12 @@ #include #include -#include "claydoc.hpp" -#include "parser.hpp" - #include #include +#include "claydoc.hpp" +#include "parser.hpp" + using namespace std; using namespace clay; diff --git a/compiler/codegen_op.cpp b/compiler/codegen_op.cpp index 990d60dc..595ce87f 100644 --- a/compiler/codegen_op.cpp +++ b/compiler/codegen_op.cpp @@ -9,8 +9,8 @@ #include "constructors.hpp" #include "externals.hpp" #include "env.hpp" - #include "codegen_op.hpp" +#include "invoketables.hpp" namespace clay { static llvm::StringMap stringTableConstants; diff --git a/compiler/desugar.cpp b/compiler/desugar.cpp index 73cabcbb..1b713e1f 100644 --- a/compiler/desugar.cpp +++ b/compiler/desugar.cpp @@ -1,13 +1,12 @@ #include "clay.hpp" #include "operators.hpp" #include "evaluator.hpp" -// #include "analyzer.hpp" +#include "analyzer.hpp" #include "desugar.hpp" #include "parser.hpp" #include "clone.hpp" #include "objects.hpp" #include "error.hpp" -#include "printer.hpp" namespace clay { ExprPtr desugarCharLiteral(char c) { diff --git a/compiler/error.cpp b/compiler/error.cpp index d0f8cc2d..7a7bffb7 100644 --- a/compiler/error.cpp +++ b/compiler/error.cpp @@ -6,6 +6,8 @@ #include "error.hpp" #include "printer.hpp" +#include + namespace clay { bool shouldPrintFullMatchErrors; set > logMatchSymbols; diff --git a/compiler/error.hpp b/compiler/error.hpp index 247d53dd..a08ed56f 100644 --- a/compiler/error.hpp +++ b/compiler/error.hpp @@ -1,8 +1,7 @@ #pragma once #include "clay.hpp" -// #include "invoketables.hpp" -// #include "printer.hpp" +#include "printer.hpp" #if defined(__GNUC__) || defined(__clang__) #define CLAY_NORETURN __attribute__((noreturn)) diff --git a/compiler/interactive.cpp b/compiler/interactive.cpp index fd055101..9896819b 100644 --- a/compiler/interactive.cpp +++ b/compiler/interactive.cpp @@ -1,6 +1,3 @@ -#include -#include - #include "clay.hpp" #include "lexer.hpp" #include "parser.hpp" diff --git a/compiler/invoketables.cpp b/compiler/invoketables.cpp index d80935b2..b8c6789b 100644 --- a/compiler/invoketables.cpp +++ b/compiler/invoketables.cpp @@ -5,7 +5,6 @@ #include "constructors.hpp" #include "clone.hpp" #include "objects.hpp" -#include "printer.hpp" #pragma clang diagnostic ignored "-Wcovered-switch-default" diff --git a/compiler/lambdas.cpp b/compiler/lambdas.cpp index c6ae9c0b..c96abf15 100644 --- a/compiler/lambdas.cpp +++ b/compiler/lambdas.cpp @@ -7,7 +7,6 @@ #include "loader.hpp" #include "env.hpp" #include "error.hpp" -#include "printer.hpp" namespace clay { struct LambdaContext { diff --git a/compiler/loader.cpp b/compiler/loader.cpp index 071d8338..d2bbc060 100644 --- a/compiler/loader.cpp +++ b/compiler/loader.cpp @@ -1,3 +1,5 @@ +#include + #include "clay.hpp" #include "loader.hpp" #include "patterns.hpp" diff --git a/compiler/loader.hpp b/compiler/loader.hpp index 8eaa5759..0f0cada9 100644 --- a/compiler/loader.hpp +++ b/compiler/loader.hpp @@ -1,6 +1,5 @@ #pragma once - #include "clay.hpp" namespace clay { diff --git a/compiler/profiler.cpp b/compiler/profiler.cpp index b91f8aa5..2262977d 100644 --- a/compiler/profiler.cpp +++ b/compiler/profiler.cpp @@ -1,6 +1,5 @@ #include "clay.hpp" #include "profiler.hpp" -#include "printer.hpp" namespace clay { static llvm::StringMap countsMap; From 92bc0837a5a09e24a311b3b0ae1f01ae2e4b8bd6 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sun, 14 Dec 2025 08:32:31 -0500 Subject: [PATCH 48/56] Undo mistake of replaceall nullptr --- compiler/codegen.cpp | 4 ++-- compiler/codegen_op.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/codegen.cpp b/compiler/codegen.cpp index 9f22d4a1..c6ec722c 100644 --- a/compiler/codegen.cpp +++ b/compiler/codegen.cpp @@ -42,7 +42,7 @@ namespace clay { } llvm::Value *noExceptionReturnValue() { - return llvm::ConstantPointernullptr::get(exceptionReturnType()); + return llvm::ConstantPointerNull::get(exceptionReturnType()); } void codegenValueInit(CValuePtr dest, CodegenContext *ctx); @@ -1360,7 +1360,7 @@ namespace clay { assert(mpv->size() == 1); PVData const &y = mpv->values[0]; llvm::Constant *initializer = - llvm::Constant::getnullptrValue(llvmType(y.type)); + llvm::Constant::getNullValue(llvmType(y.type)); llvm::SmallString<128> nameBuf; llvm::raw_svector_ostream nameStr(nameBuf); diff --git a/compiler/codegen_op.cpp b/compiler/codegen_op.cpp index 595ce87f..f572b7a8 100644 --- a/compiler/codegen_op.cpp +++ b/compiler/codegen_op.cpp @@ -1335,7 +1335,7 @@ namespace clay { break; } - case PRIM_nullptrPointer: { + case PRIM_nullPointer: { ensureArity(args, 1); TypePtr dest = valueToPointerLikeType(args, 0); assert(out->size() == 1); @@ -1343,7 +1343,7 @@ namespace clay { assert(out0->type == dest); llvm::PointerType *llType = llvm::dyn_cast(llvmType(dest)); assert(llType != nullptr); - llvm::Value *result = llvm::ConstantPointernullptr::get(llType); + llvm::Value *result = llvm::ConstantPointerNull::get(llType); ctx->builder->CreateStore(result, out0->llValue); break; } From d4eff9e96f1518a4c6870b979e40ea94c77b0821 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sun, 14 Dec 2025 08:32:52 -0500 Subject: [PATCH 49/56] Update .gitattributes to JS --- .gitattributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index bc8bc344..623cd141 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -*.clay linguist-language=C +*.clay linguist-language=JavaScript From 097dbc07e1f32bd89da38bbd15295cc572e5355b Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sun, 14 Dec 2025 08:34:24 -0500 Subject: [PATCH 50/56] Remove const reference on recordType --- compiler/clay.hpp | 2 +- compiler/types.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/clay.hpp b/compiler/clay.hpp index 5013752c..bde527a9 100644 --- a/compiler/clay.hpp +++ b/compiler/clay.hpp @@ -2725,7 +2725,7 @@ namespace clay { bool fieldsInitialized: 1; bool hasVarField: 1; - RecordType(const RecordDeclPtr &record, llvm::ArrayRef params); + RecordType(RecordDeclPtr record, llvm::ArrayRef params); size_t varFieldSize() const { return fieldTypes.size() - fieldNames.size() + 1; diff --git a/compiler/types.cpp b/compiler/types.cpp index 8e5635af..ba7e4f06 100644 --- a/compiler/types.cpp +++ b/compiler/types.cpp @@ -349,7 +349,7 @@ namespace clay { return t.ptr(); } - TypePtr recordType(const RecordDeclPtr& record, llvm::ArrayRef params) { + TypePtr recordType(RecordDeclPtr record, llvm::ArrayRef params) { unsigned h = pointerHash(record.ptr()); ObjectPtr const *pi, *pend; for (pi = params.begin(), pend = params.end(); pi != pend; ++pi) From 92d35829a257a114eb30fc8265399224ea2fca3b Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sun, 14 Dec 2025 08:34:48 -0500 Subject: [PATCH 51/56] Add toString to profiler.cpp --- compiler/profiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/profiler.cpp b/compiler/profiler.cpp index 2262977d..56940757 100644 --- a/compiler/profiler.cpp +++ b/compiler/profiler.cpp @@ -7,7 +7,7 @@ namespace clay { void incrementCount(const ObjectPtr &obj) { string buf; llvm::raw_string_ostream sout(buf); - sout << obj; + sout << obj->toString(); string s = sout.str(); llvm::StringMap::iterator i = countsMap.find(s); if (i == countsMap.end()) { From 6076eb7ebe103214b62617fc91f8d30dbb9f9363 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sun, 14 Dec 2025 08:35:19 -0500 Subject: [PATCH 52/56] Remove const reference from error.cpp --- compiler/error.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/error.cpp b/compiler/error.cpp index 7a7bffb7..35e4e592 100644 --- a/compiler/error.cpp +++ b/compiler/error.cpp @@ -36,7 +36,7 @@ namespace clay { contextStack.emplace_back(obj, params); } - void pushCompileContext(const ObjectPtr &obj, llvm::ArrayRef params, llvm::ArrayRef dispatchIndices) { + void pushCompileContext(ObjectPtr obj, llvm::ArrayRef params, llvm::ArrayRef dispatchIndices) { if (contextStack.size() >= RECURSION_WARNING_LEVEL) warning("potential runaway recursion"); if (!contextStack.empty()) @@ -56,7 +56,7 @@ namespace clay { contextStack = x; } - CompileContextPusher::CompileContextPusher(const ObjectPtr &obj, llvm::ArrayRef params, + CompileContextPusher::CompileContextPusher(ObjectPtr obj, llvm::ArrayRef params, llvm::ArrayRef dispatchIndices) { vector params2; for (const auto & param : params) { @@ -97,7 +97,7 @@ namespace clay { int DebugPrinter::indent = 0; - DebugPrinter::DebugPrinter(const ObjectPtr &obj) + DebugPrinter::DebugPrinter(ObjectPtr obj) : obj(obj) { for (int i = 0; i < indent; ++i) llvm::outs() << ' '; From 47ae5ae5c81eeaf9dedb2c5652067b747ed45e42 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sun, 14 Dec 2025 08:36:41 -0500 Subject: [PATCH 53/56] Add type to CreateLoad in codegen_op.cpp --- compiler/codegen_op.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/compiler/codegen_op.cpp b/compiler/codegen_op.cpp index f572b7a8..ebbdbaec 100644 --- a/compiler/codegen_op.cpp +++ b/compiler/codegen_op.cpp @@ -155,7 +155,8 @@ namespace clay { } type = cv->type; } - return ctx->builder->CreateLoad(cv->llValue); + llvm::Type *llTy = llvmType(cv->type); + return ctx->builder->CreateLoad(llTy, cv->llValue); } static llvm::Value *floatValue(MultiCValuePtr args, @@ -175,7 +176,8 @@ namespace clay { } type = (FloatType *) cv->type.ptr(); } - return ctx->builder->CreateLoad(cv->llValue); + llvm::Type *llTy = llvmType(cv->type); + return ctx->builder->CreateLoad(llTy, cv->llValue); } static llvm::Value *integerOrPointerLikeValue(MultiCValuePtr args, @@ -198,7 +200,8 @@ namespace clay { } type = cv->type; } - return ctx->builder->CreateLoad(cv->llValue); + llvm::Type *llTy = llvmType(cv->type); + return ctx->builder->CreateLoad(llTy, cv->llValue); } static void checkIntegerValue(MultiCValuePtr args, @@ -222,7 +225,8 @@ namespace clay { CodegenContext *ctx) { checkIntegerValue(args, index, type, ctx); CValuePtr cv = args->values[index]; - return ctx->builder->CreateLoad(cv->llValue); + llvm::Type *llTy = llvmType(cv->type); + return ctx->builder->CreateLoad(llTy, cv->llValue); } static llvm::Value *pointerValue(MultiCValuePtr args, @@ -239,7 +243,8 @@ namespace clay { type = (PointerType *) cv->type.ptr(); llvmType(type->pointeeType); // force the pointee type to be refined } - return ctx->builder->CreateLoad(cv->llValue); + llvm::Type *llTy = llvmType(cv->type); + return ctx->builder->CreateLoad(llTy, cv->llValue); } static llvm::Value *pointerLikeValue(MultiCValuePtr args, @@ -257,7 +262,8 @@ namespace clay { cv->type); type = cv->type; } - return ctx->builder->CreateLoad(cv->llValue); + llvm::Type *llTy = llvmType(cv->type); + return ctx->builder->CreateLoad(llTy, cv->llValue); } static llvm::Value *cCodePointerValue(MultiCValuePtr args, @@ -333,7 +339,8 @@ namespace clay { argumentTypeError(index, "enum type", cv->type); type = (EnumType *) cv->type.ptr(); } - return ctx->builder->CreateLoad(cv->llValue); + llvm::Type *llTy = llvmType(cv->type); + return ctx->builder->CreateLoad(llTy, cv->llValue); } llvm::AtomicOrdering atomicOrderValue(MultiCValuePtr args, unsigned index) { From fe660143a3ce8a107b6dbfb1b361b11c61dfbcbd Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sun, 14 Dec 2025 08:41:14 -0500 Subject: [PATCH 54/56] Use new AtomicOrdering states --- compiler/codegen_op.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/codegen_op.cpp b/compiler/codegen_op.cpp index ebbdbaec..dbd5a8c3 100644 --- a/compiler/codegen_op.cpp +++ b/compiler/codegen_op.cpp @@ -350,21 +350,21 @@ namespace clay { PrimOp *prim = (PrimOp *) obj.ptr(); switch (prim->primOpCode) { case PRIM_OrderUnordered: - return llvm::Unordered; + return llvm::AtomicOrdering::Unordered; case PRIM_OrderMonotonic: - return llvm::Monotonic; + return llvm::AtomicOrdering::Monotonic; case PRIM_OrderAcquire: - return llvm::Acquire; + return llvm::AtomicOrdering::Acquire; case PRIM_OrderRelease: - return llvm::Release; + return llvm::AtomicOrdering::Release; case PRIM_OrderAcqRel: - return llvm::AcquireRelease; + return llvm::AtomicOrdering::AcquireRelease; case PRIM_OrderSeqCst: - return llvm::SequentiallyConsistent; + return llvm::AtomicOrdering::SequentiallyConsistent; } } argumentTypeError(index, "atomic ordering", cv->type); - return llvm::Unordered; + return llvm::AtomicOrdering::Unordered; } llvm::AtomicRMWInst::BinOp atomicRMWOpValue(MultiCValuePtr args, unsigned index) { From cc2e8978858881e9060165812012ef1151742a24 Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Sun, 14 Dec 2025 08:42:56 -0500 Subject: [PATCH 55/56] Use DW_TAG_variable tag instead of old DW_TAG_arg_variable and DW_TAG_auto_variable --- compiler/codegen.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/codegen.cpp b/compiler/codegen.cpp index c6ec722c..1cb89164 100644 --- a/compiler/codegen.cpp +++ b/compiler/codegen.cpp @@ -1603,7 +1603,7 @@ namespace clay { Location argLocation = arg->location; llvm::DIFile file = getDebugLineCol(argLocation, line, column); llvm::DIVariable debugVar = llvmDIBuilder->createLocalVariable( - llvm::dwarf::DW_TAG_arg_variable, // tag + llvm::dwarf::DW_TAG_variable, // tag x->getDebugInfo(), // scope arg->name->str, // name file, // file @@ -2893,7 +2893,7 @@ namespace clay { llvm::DIFile file = getDebugLineCol(argLocation, line, column); llvm::DebugLoc debugLoc = llvm::DebugLoc::get(line, column, entry->getDebugInfo()); llvm::DIVariable debugVar = llvmDIBuilder->createLocalVariable( - llvm::dwarf::DW_TAG_arg_variable, // tag + llvm::dwarf::DW_TAG_variable, // tag entry->getDebugInfo(), // scope entry->fixedArgNames[i]->str, // name file, // file @@ -2935,7 +2935,7 @@ namespace clay { if (llvmDIBuilder != nullptr) { llvm::DebugLoc debugLoc = llvm::DebugLoc::get(line, column, entry->getDebugInfo()); llvm::DIVariable debugVar = llvmDIBuilder->createLocalVariable( - llvm::dwarf::DW_TAG_arg_variable, // tag + llvm::dwarf::DW_TAG_variable, // tag entry->getDebugInfo(), // scope sout.str(), // name file, // file @@ -2969,7 +2969,7 @@ namespace clay { llvm::DIFile file = getDebugLineCol(argLocation, line, column); llvm::DebugLoc debugLoc = llvm::DebugLoc::get(line, column, entry->getDebugInfo()); llvm::DIVariable debugVar = llvmDIBuilder->createLocalVariable( - llvm::dwarf::DW_TAG_arg_variable, // tag + llvm::dwarf::DW_TAG_variable, // tag entry->getDebugInfo(), // scope entry->fixedArgNames[i]->str, // name file, // file @@ -3995,7 +3995,7 @@ namespace clay { if (llvmDIBuilder != nullptr) { llvm::DILexicalBlock debugBlock = ctx->getDebugScope(); llvm::DIVariable debugVar = llvmDIBuilder->createLocalVariable( - llvm::dwarf::DW_TAG_auto_variable, // tag + llvm::dwarf::DW_TAG_variable, // tag debugBlock, // scope getBindingVariableName(x, i), // name file, // file @@ -4062,7 +4062,7 @@ namespace clay { if (llvmDIBuilder != nullptr) { llvm::DILexicalBlock debugBlock = ctx->getDebugScope(); llvm::DIVariable debugVar = llvmDIBuilder->createLocalVariable( - llvm::dwarf::DW_TAG_auto_variable, // tag + llvm::dwarf::DW_TAG_variable, // tag debugBlock, // scope getBindingVariableName(x, i), // name file, // file @@ -4133,7 +4133,7 @@ namespace clay { llvm::DILexicalBlock debugBlock = ctx->getDebugScope(); llvm::DIType debugType = llvmTypeDebugInfo(pv.type); llvm::DIVariable debugVar = llvmDIBuilder->createLocalVariable( - llvm::dwarf::DW_TAG_auto_variable, // tag + llvm::dwarf::DW_TAG_variable, // tag debugBlock, // scope getBindingVariableName(x, i), // name file, // file From 69ae16ce62b7fe7122e5b330afa143fd51b59c8c Mon Sep 17 00:00:00 2001 From: Ramon Asuncion Date: Fri, 8 May 2026 21:23:58 -0400 Subject: [PATCH 56/56] Fix DI type API, BumpPtrAllocator, and reformat codebase --- .clang-format | 3 + .gitignore | 4 +- CMakeLists.txt | 7 +- compiler/analyzer.cpp | 4562 ++++++++++----------- compiler/analyzer.hpp | 232 +- compiler/analyzer_op.cpp | 1881 +++++---- compiler/analyzer_op.hpp | 2 +- compiler/checkedcast.hpp | 11 +- compiler/clay.cpp | 1766 ++++---- compiler/clay.hpp | 4620 ++++++++++----------- compiler/claydoc.cpp | 96 +- compiler/claydoc.hpp | 4 +- compiler/clone.cpp | 916 +++-- compiler/clone.hpp | 36 +- compiler/codegen.cpp | 7828 +++++++++++++++++------------------- compiler/codegen.hpp | 432 +- compiler/codegen_op.cpp | 4199 ++++++++++--------- compiler/codegen_op.hpp | 6 +- compiler/constructors.cpp | 228 +- compiler/constructors.hpp | 10 +- compiler/desugar.cpp | 894 ++-- compiler/desugar.hpp | 32 +- compiler/env.cpp | 823 ++-- compiler/env.hpp | 35 +- compiler/error.cpp | 806 ++-- compiler/error.hpp | 221 +- compiler/evaluator.cpp | 4128 ++++++++++--------- compiler/evaluator.hpp | 183 +- compiler/evaluator_op.cpp | 4314 ++++++++++---------- compiler/evaluator_op.hpp | 2 +- compiler/externals.cpp | 2071 +++++----- compiler/externals.hpp | 214 +- compiler/hirestimer.cpp | 123 +- compiler/hirestimer.hpp | 22 +- compiler/html.cpp | 119 +- compiler/int128.hpp | 252 +- compiler/interactive.cpp | 541 +-- compiler/invoketables.cpp | 705 ++-- compiler/invoketables.hpp | 254 +- compiler/lambdas.cpp | 1236 +++--- compiler/lambdas.hpp | 2 +- compiler/lexer.cpp | 1644 ++++---- compiler/lexer.hpp | 96 +- compiler/literals.cpp | 658 +-- compiler/literals.hpp | 6 +- compiler/loader.cpp | 2631 ++++++------ compiler/loader.hpp | 475 +-- compiler/matchinvoke.cpp | 418 +- compiler/matchinvoke.hpp | 255 +- compiler/objects.cpp | 230 +- compiler/objects.hpp | 97 +- compiler/operators.hpp | 298 +- compiler/parachute.cpp | 106 +- compiler/parachute.hpp | 4 +- compiler/parser.cpp | 6100 +++++++++++++++------------- compiler/parser.hpp | 44 +- compiler/patterns.cpp | 1291 +++--- compiler/patterns.hpp | 42 +- compiler/printer.cpp | 2434 +++++------ compiler/printer.hpp | 81 +- compiler/profiler.cpp | 48 +- compiler/profiler.hpp | 6 +- compiler/refcounted.hpp | 108 +- compiler/refcounted_ut.cpp | 14 +- compiler/types.cpp | 3026 +++++++------- compiler/types.hpp | 179 +- compiler/ut.hpp | 49 +- compiler/ut_main.cpp | 46 +- 68 files changed, 32157 insertions(+), 32049 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..e6e2c5bf --- /dev/null +++ b/.clang-format @@ -0,0 +1,3 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +TabWidth: 4 diff --git a/.gitignore b/.gitignore index a9316691..89e59f99 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ .DS_Store Thumbs.db *.pdb -.vscode/ +.vscode/*.code-workspace +.cache/ +compile_commands.json *.swp *.swo *.idea/ diff --git a/CMakeLists.txt b/CMakeLists.txt index eb6cecba..e94311b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,6 @@ if(UNIX) OUTPUT_VARIABLE LLVM_CXXFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE ) - set(LLVM_CXXFLAGS ${LLVM_CXXFLAGS}) separate_arguments(LLVM_CXXFLAGS) if(CMAKE_BUILD_TYPE STREQUAL "Debug") @@ -83,7 +82,6 @@ if(UNIX) OUTPUT_VARIABLE LLVM_INCLUDEDIR OUTPUT_STRIP_TRAILING_WHITESPACE ) - set(LLVM_INCLUDEDIR ${LLVM_INCLUDEDIR}) message("-- Using LLVM: ${LLVM_DIR}") message("-- LLVM include dir: ${LLVM_INCLUDEDIR}") @@ -94,6 +92,7 @@ if(UNIX) elseif(WIN32) + # TODO: unverified, port to find_package(LLVM CONFIG) + llvm_map_components_to_libnames. set(LLVM_DIR "$ENV{ProgramFiles}/LLVM" CACHE PATH "llvm install path") if(IS_DIRECTORY ${LLVM_DIR}) @@ -119,10 +118,6 @@ elseif(WIN32) endif() -set(BUILD_BINDGEN True CACHE BOOL - "Build the clay-bindgen tool for generating Clay bindings from C header files." -) - install(DIRECTORY doc/ DESTINATION share/doc/clay) install(DIRECTORY examples/ DESTINATION share/doc/clay/examples) install(DIRECTORY lib-clay DESTINATION lib) diff --git a/compiler/analyzer.cpp b/compiler/analyzer.cpp index 631f9bbf..1c5087c2 100644 --- a/compiler/analyzer.cpp +++ b/compiler/analyzer.cpp @@ -1,2630 +1,2656 @@ +#include "analyzer.hpp" +#include "analyzer_op.hpp" #include "clay.hpp" -#include "evaluator.hpp" +#include "clone.hpp" #include "codegen.hpp" -#include "loader.hpp" -#include "operators.hpp" -#include "patterns.hpp" -#include "lambdas.hpp" -#include "analyzer.hpp" -#include "invoketables.hpp" -#include "matchinvoke.hpp" -#include "error.hpp" -#include "literals.hpp" -#include "desugar.hpp" #include "constructors.hpp" +#include "desugar.hpp" #include "env.hpp" -#include "clone.hpp" +#include "error.hpp" +#include "evaluator.hpp" +#include "invoketables.hpp" +#include "lambdas.hpp" +#include "literals.hpp" +#include "loader.hpp" +#include "matchinvoke.hpp" #include "objects.hpp" -#include "analyzer_op.hpp" +#include "operators.hpp" +#include "patterns.hpp" #pragma clang diagnostic ignored "-Wcovered-switch-default" namespace clay { - GVarInstance::GVarInstance(const GlobalVariablePtr &gvar, - llvm::ArrayRef params) - : gvar(gvar), params(params), - llGlobal(nullptr), debugInfo(nullptr), analyzing(false) { - } - - GVarInstance::~GVarInstance() = default; +GVarInstance::GVarInstance(const GlobalVariablePtr &gvar, + llvm::ArrayRef params) + : gvar(gvar), params(params), llGlobal(nullptr), debugInfo(nullptr), + analyzing(false) {} - Procedure::Procedure(Module *module, IdentifierPtr name, Visibility visibility, bool privateOverload) - : TopLevelItem(PROCEDURE, module, name, visibility), - privateOverload(privateOverload) { - } - - Procedure::Procedure(Module *module, IdentifierPtr name, Visibility visibility, bool privateOverload, - OverloadPtr interface) - : TopLevelItem(PROCEDURE, module, name, visibility), - interface(interface), privateOverload(privateOverload) { - } +GVarInstance::~GVarInstance() = default; - Procedure::~Procedure() { - } +Procedure::Procedure(Module *module, IdentifierPtr name, Visibility visibility, + bool privateOverload) + : TopLevelItem(PROCEDURE, module, name, visibility), + privateOverload(privateOverload) {} - GlobalVariable::GlobalVariable(Module *module, IdentifierPtr name, - Visibility visibility, - llvm::ArrayRef patternVars, - ExprPtr predicate, - llvm::ArrayRef params, - IdentifierPtr varParam, - ExprPtr expr) - : TopLevelItem(GLOBAL_VARIABLE, module, name, visibility), - patternVars(patternVars), predicate(predicate), - params(params), varParam(varParam), expr(expr) { - } +Procedure::Procedure(Module *module, IdentifierPtr name, Visibility visibility, + bool privateOverload, OverloadPtr interface) + : TopLevelItem(PROCEDURE, module, name, visibility), interface(interface), + privateOverload(privateOverload) {} - GlobalVariable::~GlobalVariable() = default; +Procedure::~Procedure() {} - static StatementAnalysis analyzeStatement(StatementPtr stmt, EnvPtr env, AnalysisContext *ctx); +GlobalVariable::GlobalVariable(Module *module, IdentifierPtr name, + Visibility visibility, + llvm::ArrayRef patternVars, + ExprPtr predicate, + llvm::ArrayRef params, + IdentifierPtr varParam, ExprPtr expr) + : TopLevelItem(GLOBAL_VARIABLE, module, name, visibility), + patternVars(patternVars), predicate(predicate), params(params), + varParam(varParam), expr(expr) {} - static EnvPtr analyzeBinding(BindingPtr x, EnvPtr env); +GlobalVariable::~GlobalVariable() = default; - static int analysisCachingDisabled = 0; - void disableAnalysisCaching() { analysisCachingDisabled += 1; } - void enableAnalysisCaching() { analysisCachingDisabled -= 1; } +static StatementAnalysis analyzeStatement(StatementPtr stmt, EnvPtr env, + AnalysisContext *ctx); - static TypePtr objectType(ObjectPtr x); +static EnvPtr analyzeBinding(BindingPtr x, EnvPtr env); - static bool staticToTypeTuple(ObjectPtr x, vector &out); +static int analysisCachingDisabled = 0; +void disableAnalysisCaching() { analysisCachingDisabled += 1; } +void enableAnalysisCaching() { analysisCachingDisabled -= 1; } - static void staticToTypeTuple(MultiStaticPtr x, unsigned index, - vector &out); +static TypePtr objectType(ObjectPtr x); - static int staticToInt(MultiStaticPtr x, unsigned index); +static bool staticToTypeTuple(ObjectPtr x, vector &out); - // - // utility procs - // +static void staticToTypeTuple(MultiStaticPtr x, unsigned index, + vector &out); - static TypePtr objectType(ObjectPtr x) { - switch (x->objKind) { - case VALUE_HOLDER: { - ValueHolder *y = (ValueHolder *) x.ptr(); - return y->type; - } +static int staticToInt(MultiStaticPtr x, unsigned index); - case TYPE: - case PRIM_OP: - case PROCEDURE: - case INTRINSIC: - case GLOBAL_ALIAS: - case RECORD_DECL: - case VARIANT_DECL: - case MODULE: - case IDENTIFIER: - return staticType(x); +// +// utility procs +// - default: - error("untypeable object"); - return nullptr; - } +static TypePtr objectType(ObjectPtr x) { + switch (x->objKind) { + case VALUE_HOLDER: { + ValueHolder *y = (ValueHolder *)x.ptr(); + return y->type; } - ObjectPtr unwrapStaticType(TypePtr t) { - if (t->typeKind != STATIC_TYPE) - return nullptr; - StaticType *st = (StaticType *) t.ptr(); - return st->obj; - } + case TYPE: + case PRIM_OP: + case PROCEDURE: + case INTRINSIC: + case GLOBAL_ALIAS: + case RECORD_DECL: + case VARIANT_DECL: + case MODULE: + case IDENTIFIER: + return staticType(x); - static bool staticToTypeTuple(ObjectPtr x, vector &out) { - TypePtr t; - if (staticToType(x, t)) { - out.push_back(t); - return true; - } - if (x->objKind != VALUE_HOLDER) - return false; - ValueHolderPtr y = (ValueHolder *) x.ptr(); - assert(y->type->typeKind != STATIC_TYPE); - if (y->type->typeKind != TUPLE_TYPE) - return false; - TupleTypePtr z = static_cast(y->type.ptr()); - for (const auto &elementType: z->elementTypes) { - ObjectPtr obj = unwrapStaticType(elementType); - if ((!obj) || (obj->objKind != TYPE)) - return false; - out.push_back(static_cast(obj.ptr())); - } - return true; + default: + error("untypeable object"); + return nullptr; } +} - static void staticToTypeTuple(MultiStaticPtr x, const unsigned index, - vector &out) { - if (!staticToTypeTuple(x->values[index], out)) - argumentError(index, "expecting zero-or-more types"); - } +ObjectPtr unwrapStaticType(TypePtr t) { + if (t->typeKind != STATIC_TYPE) + return nullptr; + StaticType *st = (StaticType *)t.ptr(); + return st->obj; +} - static bool staticToInt(ObjectPtr x, int &out, TypePtr &type) { - if (x->objKind != VALUE_HOLDER) - return false; - ValueHolderPtr vh = static_cast(x.ptr()); - if (vh->type != cIntType) { - type = vh->type; - return false; - } - out = vh->as(); +static bool staticToTypeTuple(ObjectPtr x, vector &out) { + TypePtr t; + if (staticToType(x, t)) { + out.push_back(t); return true; } - - static int staticToInt(MultiStaticPtr x, unsigned index) { - int out = -1; - TypePtr type; - if (!staticToInt(x->values[index], out, type)) { - argumentTypeError(index, "Int", type); - } - return out; - } - - bool staticToBool(ObjectPtr x, bool &out, TypePtr &type) { - if (x->objKind != VALUE_HOLDER) - return false; - ValueHolderPtr vh = (ValueHolder *) x.ptr(); - if (vh->type != boolType) { - type = vh->type; + if (x->objKind != VALUE_HOLDER) + return false; + ValueHolderPtr y = (ValueHolder *)x.ptr(); + assert(y->type->typeKind != STATIC_TYPE); + if (y->type->typeKind != TUPLE_TYPE) + return false; + TupleTypePtr z = static_cast(y->type.ptr()); + for (const auto &elementType : z->elementTypes) { + ObjectPtr obj = unwrapStaticType(elementType); + if ((!obj) || (obj->objKind != TYPE)) return false; - } - out = vh->as(); - return true; + out.push_back(static_cast(obj.ptr())); } + return true; +} - bool staticToBool(MultiStaticPtr x, unsigned index) { - bool out = false; - TypePtr type; - if (!staticToBool(x->values[index], out, type)) - argumentTypeError(index, "Bool", type); - return out; - } +static void staticToTypeTuple(MultiStaticPtr x, const unsigned index, + vector &out) { + if (!staticToTypeTuple(x->values[index], out)) + argumentError(index, "expecting zero-or-more types"); +} - bool staticToCallingConv(ObjectPtr x, CallingConv &out) { - if (x->objKind != PRIM_OP) - return false; - PrimOp *ccPrim = (PrimOp *) x.ptr(); - switch (ccPrim->primOpCode) { - case PRIM_AttributeCCall: - out = CC_DEFAULT; - return true; - case PRIM_AttributeStdCall: - out = CC_STDCALL; - return true; - case PRIM_AttributeFastCall: - out = CC_FASTCALL; - return true; - case PRIM_AttributeThisCall: - out = CC_THISCALL; - return true; - case PRIM_AttributeLLVMCall: - out = CC_LLVM; - return true; - default: - return false; - } +static bool staticToInt(ObjectPtr x, int &out, TypePtr &type) { + if (x->objKind != VALUE_HOLDER) + return false; + ValueHolderPtr vh = static_cast(x.ptr()); + if (vh->type != cIntType) { + type = vh->type; + return false; } + out = vh->as(); + return true; +} - CallingConv staticToCallingConv(MultiStaticPtr x, unsigned index) { - CallingConv out; - if (!staticToCallingConv(x->values[index], out)) - argumentError(index, "expecting calling convention attribute"); - return out; +static int staticToInt(MultiStaticPtr x, unsigned index) { + int out = -1; + TypePtr type; + if (!staticToInt(x->values[index], out, type)) { + argumentTypeError(index, "Int", type); } + return out; +} - // - // safe analysis - // +bool staticToBool(ObjectPtr x, bool &out, TypePtr &type) { + if (x->objKind != VALUE_HOLDER) + return false; + ValueHolderPtr vh = (ValueHolder *)x.ptr(); + if (vh->type != boolType) { + type = vh->type; + return false; + } + out = vh->as(); + return true; +} - static Location analysisErrorLocation; - static vector analysisErrorCompileContext; +bool staticToBool(MultiStaticPtr x, unsigned index) { + bool out = false; + TypePtr type; + if (!staticToBool(x->values[index], out, type)) + argumentTypeError(index, "Bool", type); + return out; +} - struct ClearAnalysisError { - ClearAnalysisError() = default; +bool staticToCallingConv(ObjectPtr x, CallingConv &out) { + if (x->objKind != PRIM_OP) + return false; + PrimOp *ccPrim = (PrimOp *)x.ptr(); + switch (ccPrim->primOpCode) { + case PRIM_AttributeCCall: + out = CC_DEFAULT; + return true; + case PRIM_AttributeStdCall: + out = CC_STDCALL; + return true; + case PRIM_AttributeFastCall: + out = CC_FASTCALL; + return true; + case PRIM_AttributeThisCall: + out = CC_THISCALL; + return true; + case PRIM_AttributeLLVMCall: + out = CC_LLVM; + return true; + default: + return false; + } +} - ~ClearAnalysisError() { - analysisErrorLocation = Location(); - analysisErrorCompileContext.clear(); - } - }; +CallingConv staticToCallingConv(MultiStaticPtr x, unsigned index) { + CallingConv out; + if (!staticToCallingConv(x->values[index], out)) + argumentError(index, "expecting calling convention attribute"); + return out; +} - static void updateAnalysisErrorLocation() { - analysisErrorLocation = topLocation(); - analysisErrorCompileContext = getCompileContext(); - } +// +// safe analysis +// - static void analysisError() { - setCompileContext(analysisErrorCompileContext); - LocationContext loc(analysisErrorLocation); - error("type propagation failed due to recursion without base case"); - } +static Location analysisErrorLocation; +static vector analysisErrorCompileContext; - PVData safeAnalyzeOne(ExprPtr expr, EnvPtr env) { - ClearAnalysisError clear; - PVData result = analyzeOne(expr, env); - if (!result.ok()) - analysisError(); - return result; - } +struct ClearAnalysisError { + ClearAnalysisError() = default; - MultiPValuePtr safeAnalyzeMulti(ExprListPtr exprs, EnvPtr env, size_t wantCount) { - ClearAnalysisError clear; - MultiPValuePtr result = analyzeMulti(exprs, env, wantCount); - if (!result) - analysisError(); - return result; + ~ClearAnalysisError() { + analysisErrorLocation = Location(); + analysisErrorCompileContext.clear(); } +}; - MultiPValuePtr safeAnalyzeExpr(ExprPtr expr, EnvPtr env) { - ClearAnalysisError clear; - MultiPValuePtr result = analyzeExpr(expr, env); - if (!result) - analysisError(); - return result; - } +static void updateAnalysisErrorLocation() { + analysisErrorLocation = topLocation(); + analysisErrorCompileContext = getCompileContext(); +} - MultiPValuePtr safeAnalyzeIndexingExpr(ExprPtr indexable, - ExprListPtr args, - EnvPtr env) { - ClearAnalysisError clear; - MultiPValuePtr result = analyzeIndexingExpr(indexable, args, env); - if (!result) - analysisError(); - return result; - } +static void analysisError() { + setCompileContext(analysisErrorCompileContext); + LocationContext loc(analysisErrorLocation); + error("type propagation failed due to recursion without base case"); +} - MultiPValuePtr safeAnalyzeMultiArgs(ExprListPtr exprs, - EnvPtr env, - vector &dispatchIndices) { - ClearAnalysisError clear; - MultiPValuePtr result = analyzeMultiArgs(exprs, env, dispatchIndices); - if (!result) - analysisError(); - return result; - } - - InvokeEntry *safeAnalyzeCallable(ObjectPtr x, - llvm::ArrayRef args) { - ClearAnalysisError clear; - InvokeEntry *entry = analyzeCallable(x, args); - if (!entry->callByName && !entry->analyzed) - analysisError(); - return entry; - } +PVData safeAnalyzeOne(ExprPtr expr, EnvPtr env) { + ClearAnalysisError clear; + PVData result = analyzeOne(expr, env); + if (!result.ok()) + analysisError(); + return result; +} - MultiPValuePtr safeAnalyzeCallByName(InvokeEntry *entry, - ExprPtr callable, - ExprListPtr args, - EnvPtr env) { - ClearAnalysisError clear; - MultiPValuePtr result = analyzeCallByName(entry, callable, args, env); - if (!entry) - analysisError(); - return result; - } +MultiPValuePtr safeAnalyzeMulti(ExprListPtr exprs, EnvPtr env, + size_t wantCount) { + ClearAnalysisError clear; + MultiPValuePtr result = analyzeMulti(exprs, env, wantCount); + if (!result) + analysisError(); + return result; +} - MultiPValuePtr safeAnalyzeGVarInstance(GVarInstancePtr x) { - ClearAnalysisError clear; - MultiPValuePtr result = analyzeGVarInstance(x); - if (!result) - analysisError(); - return result; - } +MultiPValuePtr safeAnalyzeExpr(ExprPtr expr, EnvPtr env) { + ClearAnalysisError clear; + MultiPValuePtr result = analyzeExpr(expr, env); + if (!result) + analysisError(); + return result; +} - // - // analyzeMulti - // +MultiPValuePtr safeAnalyzeIndexingExpr(ExprPtr indexable, ExprListPtr args, + EnvPtr env) { + ClearAnalysisError clear; + MultiPValuePtr result = analyzeIndexingExpr(indexable, args, env); + if (!result) + analysisError(); + return result; +} - static MultiPValuePtr analyzeMulti2(ExprListPtr exprs, EnvPtr env, size_t wantCount); +MultiPValuePtr safeAnalyzeMultiArgs(ExprListPtr exprs, EnvPtr env, + vector &dispatchIndices) { + ClearAnalysisError clear; + MultiPValuePtr result = analyzeMultiArgs(exprs, env, dispatchIndices); + if (!result) + analysisError(); + return result; +} - MultiPValuePtr analyzeMulti(ExprListPtr exprs, EnvPtr env, size_t wantCount) { - if (analysisCachingDisabled > 0) - return analyzeMulti2(exprs, env, wantCount); - if (!exprs->cachedAnalysis) - exprs->cachedAnalysis = analyzeMulti2(exprs, env, wantCount); - return exprs->cachedAnalysis; - } +InvokeEntry *safeAnalyzeCallable(ObjectPtr x, llvm::ArrayRef args) { + ClearAnalysisError clear; + InvokeEntry *entry = analyzeCallable(x, args); + if (!entry->callByName && !entry->analyzed) + analysisError(); + return entry; +} - static MultiPValuePtr analyzeMulti2(ExprListPtr exprs, EnvPtr env, size_t wantCount) { - MultiPValuePtr out = new MultiPValue(); - ExprPtr unpackExpr = implicitUnpackExpr(wantCount, exprs); - if (unpackExpr != nullptr) { - MultiPValuePtr z = analyzeExpr(unpackExpr, env); - if (!z) - return nullptr; - out->add(z); - } else - for (unsigned i = 0; i < exprs->size(); ++i) { - ExprPtr x = exprs->exprs[i]; - if (x->exprKind == UNPACK) { - Unpack *y = (Unpack *) x.ptr(); - MultiPValuePtr z = analyzeExpr(y->expr, env); - if (!z) - return nullptr; - out->add(z); - } else if (x->exprKind == PAREN) { - MultiPValuePtr y = analyzeExpr(x, env); - if (!y) - return nullptr; - out->add(y); - } else { - PVData y = analyzeOne(x, env); - if (!y.ok()) - return nullptr; - out->add(y); - } - } - return out; - } +MultiPValuePtr safeAnalyzeCallByName(InvokeEntry *entry, ExprPtr callable, + ExprListPtr args, EnvPtr env) { + ClearAnalysisError clear; + MultiPValuePtr result = analyzeCallByName(entry, callable, args, env); + if (!entry) + analysisError(); + return result; +} - // - // analyzeOne - // +MultiPValuePtr safeAnalyzeGVarInstance(GVarInstancePtr x) { + ClearAnalysisError clear; + MultiPValuePtr result = analyzeGVarInstance(x); + if (!result) + analysisError(); + return result; +} - PVData analyzeOne(ExprPtr expr, EnvPtr env) { - MultiPValuePtr x = analyzeExpr(expr, env); - if (!x) - return PVData(); - LocationContext loc(expr->location); - ensureArity(x, 1); - return x->values[0]; - } +// +// analyzeMulti +// - // - // analyzeMultiArgs, analyzeOneArg, analyzeArgExpr - // +static MultiPValuePtr analyzeMulti2(ExprListPtr exprs, EnvPtr env, + size_t wantCount); - static MultiPValuePtr analyzeMultiArgs2(ExprListPtr exprs, - EnvPtr env, - unsigned startIndex, - vector &dispatchIndices); +MultiPValuePtr analyzeMulti(ExprListPtr exprs, EnvPtr env, size_t wantCount) { + if (analysisCachingDisabled > 0) + return analyzeMulti2(exprs, env, wantCount); + if (!exprs->cachedAnalysis) + exprs->cachedAnalysis = analyzeMulti2(exprs, env, wantCount); + return exprs->cachedAnalysis; +} - MultiPValuePtr analyzeMultiArgs(ExprListPtr exprs, - EnvPtr env, - vector &dispatchIndices) { - if (analysisCachingDisabled > 0) - return analyzeMultiArgs2(exprs, env, 0, dispatchIndices); - if (!exprs->cachedAnalysis) { - MultiPValuePtr mpv = analyzeMultiArgs2(exprs, env, 0, dispatchIndices); - if (mpv.ptr() && dispatchIndices.empty()) - exprs->cachedAnalysis = mpv; - return mpv; - } - return exprs->cachedAnalysis; - } - - static MultiPValuePtr analyzeMultiArgs2(ExprListPtr exprs, - EnvPtr env, - unsigned startIndex, - vector &dispatchIndices) { - MultiPValuePtr out = new MultiPValue(); - unsigned index = startIndex; +static MultiPValuePtr analyzeMulti2(ExprListPtr exprs, EnvPtr env, + size_t wantCount) { + MultiPValuePtr out = new MultiPValue(); + ExprPtr unpackExpr = implicitUnpackExpr(wantCount, exprs); + if (unpackExpr != nullptr) { + MultiPValuePtr z = analyzeExpr(unpackExpr, env); + if (!z) + return nullptr; + out->add(z); + } else for (unsigned i = 0; i < exprs->size(); ++i) { ExprPtr x = exprs->exprs[i]; if (x->exprKind == UNPACK) { - Unpack *y = (Unpack *) x.ptr(); - MultiPValuePtr z = analyzeArgExpr(y->expr, env, index, dispatchIndices); + Unpack *y = (Unpack *)x.ptr(); + MultiPValuePtr z = analyzeExpr(y->expr, env); if (!z) return nullptr; - index += unsigned(z->size()); out->add(z); } else if (x->exprKind == PAREN) { - MultiPValuePtr z = analyzeArgExpr(x, env, index, dispatchIndices); - if (!z) + MultiPValuePtr y = analyzeExpr(x, env); + if (!y) return nullptr; - index += unsigned(z->size()); - out->add(z); + out->add(y); } else { - PVData y = analyzeOneArg(x, env, index, dispatchIndices); + PVData y = analyzeOne(x, env); if (!y.ok()) return nullptr; out->add(y); - index += 1; } } - return out; - } - - PVData analyzeOneArg(ExprPtr x, - EnvPtr env, - unsigned startIndex, - vector &dispatchIndices) { - MultiPValuePtr mpv = analyzeArgExpr(x, env, startIndex, dispatchIndices); - if (!mpv) - return PVData(); - LocationContext loc(x->location); - ensureArity(mpv, 1); - return mpv->values[0]; - } - - MultiPValuePtr analyzeArgExpr(ExprPtr x, - EnvPtr env, - unsigned startIndex, - vector &dispatchIndices) { - if (x->exprKind == DISPATCH_EXPR) { - DispatchExpr *y = (DispatchExpr *) x.ptr(); - MultiPValuePtr mpv = analyzeExpr(y->expr, env); - if (!mpv) - return nullptr; - for (unsigned i = 0; i < mpv->size(); ++i) - dispatchIndices.push_back(i + startIndex); - return mpv; - } - return analyzeExpr(x, env); - } - - // - // analyzeExpr - // - - static MultiPValuePtr analyzeExpr2(ExprPtr expr, EnvPtr env); - - void appendArgString(Expr *expr, string *outString) { - ForeignExpr *fexpr; - if (expr->exprKind == FOREIGN_EXPR) - fexpr = (ForeignExpr *) expr; - else if (expr->exprKind == UNPACK) { - Unpack *uexpr = (Unpack *) expr; - if (uexpr->expr->exprKind != FOREIGN_EXPR) - goto notAlias; - fexpr = (ForeignExpr *) uexpr->expr.ptr(); - *outString += ".."; - } else - goto notAlias; + return out; +} - *outString += fexpr->expr->asString(); - return; +// +// analyzeOne +// + +PVData analyzeOne(ExprPtr expr, EnvPtr env) { + MultiPValuePtr x = analyzeExpr(expr, env); + if (!x) + return PVData(); + LocationContext loc(expr->location); + ensureArity(x, 1); + return x->values[0]; +} - notAlias: - error("__ARG__ may only be applied to an alias value or alias function argument"); - } +// +// analyzeMultiArgs, analyzeOneArg, analyzeArgExpr +// + +static MultiPValuePtr analyzeMultiArgs2(ExprListPtr exprs, EnvPtr env, + unsigned startIndex, + vector &dispatchIndices); + +MultiPValuePtr analyzeMultiArgs(ExprListPtr exprs, EnvPtr env, + vector &dispatchIndices) { + if (analysisCachingDisabled > 0) + return analyzeMultiArgs2(exprs, env, 0, dispatchIndices); + if (!exprs->cachedAnalysis) { + MultiPValuePtr mpv = analyzeMultiArgs2(exprs, env, 0, dispatchIndices); + if (mpv.ptr() && dispatchIndices.empty()) + exprs->cachedAnalysis = mpv; + return mpv; + } + return exprs->cachedAnalysis; +} - MultiPValuePtr analyzeExpr(ExprPtr expr, EnvPtr env) { - if (analysisCachingDisabled > 0) - return analyzeExpr2(expr, env); - if (!expr->cachedAnalysis) - expr->cachedAnalysis = analyzeExpr2(expr, env); - return expr->cachedAnalysis; +static MultiPValuePtr analyzeMultiArgs2(ExprListPtr exprs, EnvPtr env, + unsigned startIndex, + vector &dispatchIndices) { + MultiPValuePtr out = new MultiPValue(); + unsigned index = startIndex; + for (unsigned i = 0; i < exprs->size(); ++i) { + ExprPtr x = exprs->exprs[i]; + if (x->exprKind == UNPACK) { + Unpack *y = (Unpack *)x.ptr(); + MultiPValuePtr z = + analyzeArgExpr(y->expr, env, index, dispatchIndices); + if (!z) + return nullptr; + index += unsigned(z->size()); + out->add(z); + } else if (x->exprKind == PAREN) { + MultiPValuePtr z = analyzeArgExpr(x, env, index, dispatchIndices); + if (!z) + return nullptr; + index += unsigned(z->size()); + out->add(z); + } else { + PVData y = analyzeOneArg(x, env, index, dispatchIndices); + if (!y.ok()) + return nullptr; + out->add(y); + index += 1; + } } + return out; +} - static MultiPValuePtr analyzeExpr2(ExprPtr expr, EnvPtr env) { - LocationContext loc(expr->location); - switch (expr->exprKind) { - case BOOL_LITERAL: { - return new MultiPValue(PVData(boolType, true)); - } - - case INT_LITERAL: { - IntLiteral *x = (IntLiteral *) expr.ptr(); - ValueHolderPtr v = parseIntLiteral(safeLookupModule(env), x); - return new MultiPValue(PVData(v->type, true)); - } +PVData analyzeOneArg(ExprPtr x, EnvPtr env, unsigned startIndex, + vector &dispatchIndices) { + MultiPValuePtr mpv = analyzeArgExpr(x, env, startIndex, dispatchIndices); + if (!mpv) + return PVData(); + LocationContext loc(x->location); + ensureArity(mpv, 1); + return mpv->values[0]; +} - case FLOAT_LITERAL: { - FloatLiteral *x = (FloatLiteral *) expr.ptr(); - ValueHolderPtr v = parseFloatLiteral(safeLookupModule(env), x); - return new MultiPValue(PVData(v->type, true)); - } +MultiPValuePtr analyzeArgExpr(ExprPtr x, EnvPtr env, unsigned startIndex, + vector &dispatchIndices) { + if (x->exprKind == DISPATCH_EXPR) { + DispatchExpr *y = (DispatchExpr *)x.ptr(); + MultiPValuePtr mpv = analyzeExpr(y->expr, env); + if (!mpv) + return nullptr; + for (unsigned i = 0; i < mpv->size(); ++i) + dispatchIndices.push_back(i + startIndex); + return mpv; + } + return analyzeExpr(x, env); +} - case CHAR_LITERAL: { - CharLiteral *x = (CharLiteral *) expr.ptr(); - if (!x->desugared) - x->desugared = desugarCharLiteral(x->value); - return analyzeExpr(x->desugared, env); - } +// +// analyzeExpr +// - case STRING_LITERAL: { - StringLiteral *x = (StringLiteral *) expr.ptr(); - return new MultiPValue(staticPValue(x->value.ptr())); - } +static MultiPValuePtr analyzeExpr2(ExprPtr expr, EnvPtr env); - case NAME_REF: { - NameRef *x = (NameRef *) expr.ptr(); - ObjectPtr y = safeLookupEnv(env, x->name); - if (y->objKind == EXPRESSION) { - ExprPtr z = (Expr *) y.ptr(); - return analyzeExpr(z, env); - } else if (y->objKind == EXPR_LIST) { - ExprListPtr z = (ExprList *) y.ptr(); - return analyzeMulti(z, env, 0); - } - return analyzeStaticObject(y); - } +void appendArgString(Expr *expr, string *outString) { + ForeignExpr *fexpr; + if (expr->exprKind == FOREIGN_EXPR) + fexpr = (ForeignExpr *)expr; + else if (expr->exprKind == UNPACK) { + Unpack *uexpr = (Unpack *)expr; + if (uexpr->expr->exprKind != FOREIGN_EXPR) + goto notAlias; + fexpr = (ForeignExpr *)uexpr->expr.ptr(); + *outString += ".."; + } else + goto notAlias; - case FILE_EXPR: { - Location location = safeLookupCallByNameLocation(env); - string filename = location.source->fileName; - return analyzeStaticObject(Identifier::get(filename)); - } + *outString += fexpr->expr->asString(); + return; - case LINE_EXPR: { - return new MultiPValue(PVData(cSizeTType, true)); - } +notAlias: + error("__ARG__ may only be applied to an alias value or alias function " + "argument"); +} - case COLUMN_EXPR: { - return new MultiPValue(PVData(cSizeTType, true)); - } +MultiPValuePtr analyzeExpr(ExprPtr expr, EnvPtr env) { + if (analysisCachingDisabled > 0) + return analyzeExpr2(expr, env); + if (!expr->cachedAnalysis) + expr->cachedAnalysis = analyzeExpr2(expr, env); + return expr->cachedAnalysis; +} - case ARG_EXPR: { - ARGExpr *arg = (ARGExpr *) expr.ptr(); - ObjectPtr obj = safeLookupEnv(env, arg->name); - string argString; - if (obj->objKind == EXPRESSION) { - Expr *expr = (Expr *) obj.ptr(); - appendArgString(expr, &argString); - } else if (obj->objKind == EXPR_LIST) { - ExprList *elist = (ExprList *) obj.ptr(); - for (vector::const_iterator i = elist->exprs.begin(), - end = elist->exprs.end(); - i != end; - ++i) { - if (!argString.empty()) - argString += ", "; - - Expr *expr = i->ptr(); - appendArgString(expr, &argString); - } - } - return analyzeStaticObject(Identifier::get(argString)); - } +static MultiPValuePtr analyzeExpr2(ExprPtr expr, EnvPtr env) { + LocationContext loc(expr->location); + switch (expr->exprKind) { + case BOOL_LITERAL: { + return new MultiPValue(PVData(boolType, true)); + } - case TUPLE: { - Tuple *x = (Tuple *) expr.ptr(); - return analyzeCallExpr(operator_expr_tupleLiteral(), - x->args, - env); - } + case INT_LITERAL: { + IntLiteral *x = (IntLiteral *)expr.ptr(); + ValueHolderPtr v = parseIntLiteral(safeLookupModule(env), x); + return new MultiPValue(PVData(v->type, true)); + } - case PAREN: { - Paren *x = (Paren *) expr.ptr(); - return analyzeMulti(x->args, env, 0); - } + case FLOAT_LITERAL: { + FloatLiteral *x = (FloatLiteral *)expr.ptr(); + ValueHolderPtr v = parseFloatLiteral(safeLookupModule(env), x); + return new MultiPValue(PVData(v->type, true)); + } - case INDEXING: { - Indexing *x = (Indexing *) expr.ptr(); - return analyzeIndexingExpr(x->expr, x->args, env); - } + case CHAR_LITERAL: { + CharLiteral *x = (CharLiteral *)expr.ptr(); + if (!x->desugared) + x->desugared = desugarCharLiteral(x->value); + return analyzeExpr(x->desugared, env); + } - case CALL: { - Call *x = (Call *) expr.ptr(); - return analyzeCallExpr(x->expr, x->allArgs(), env); - } + case STRING_LITERAL: { + StringLiteral *x = (StringLiteral *)expr.ptr(); + return new MultiPValue(staticPValue(x->value.ptr())); + } - case FIELD_REF: { - FieldRef *x = (FieldRef *) expr.ptr(); - if (!x->desugared) - desugarFieldRef(x, safeLookupModule(env)); - if (x->isDottedModuleName) - return analyzeExpr(x->desugared, env); + case NAME_REF: { + NameRef *x = (NameRef *)expr.ptr(); + ObjectPtr y = safeLookupEnv(env, x->name); + if (y->objKind == EXPRESSION) { + ExprPtr z = (Expr *)y.ptr(); + return analyzeExpr(z, env); + } else if (y->objKind == EXPR_LIST) { + ExprListPtr z = (ExprList *)y.ptr(); + return analyzeMulti(z, env, 0); + } + return analyzeStaticObject(y); + } - PVData pv = analyzeOne(x->expr, env); - if (!pv.ok()) - return nullptr; - if (pv.type->typeKind == STATIC_TYPE) { - StaticType *st = (StaticType *) pv.type.ptr(); - if (st->obj->objKind == MODULE) { - Module *m = (Module *) st->obj.ptr(); - ObjectPtr obj = safeLookupPublic(m, x->name); - return analyzeStaticObject(obj); - } - } + case FILE_EXPR: { + Location location = safeLookupCallByNameLocation(env); + string filename = location.source->fileName; + return analyzeStaticObject(Identifier::get(filename)); + } - return analyzeExpr(x->desugared, env); - } + case LINE_EXPR: { + return new MultiPValue(PVData(cSizeTType, true)); + } - case STATIC_INDEXING: { - StaticIndexing *x = (StaticIndexing *) expr.ptr(); - if (!x->desugared) - x->desugared = desugarStaticIndexing(x); - return analyzeExpr(x->desugared, env); - } + case COLUMN_EXPR: { + return new MultiPValue(PVData(cSizeTType, true)); + } - case VARIADIC_OP: { - VariadicOp *x = (VariadicOp *) expr.ptr(); - if (x->op == ADDRESS_OF) { - PVData pv = analyzeOne(x->exprs->exprs.front(), env); - if (!pv.ok()) - return nullptr; - if (pv.isRValue) - error("can't take address of a temporary"); - } - if (!x->desugared) - x->desugared = desugarVariadicOp(x); - return analyzeExpr(x->desugared, env); - } + case ARG_EXPR: { + ARGExpr *arg = (ARGExpr *)expr.ptr(); + ObjectPtr obj = safeLookupEnv(env, arg->name); + string argString; + if (obj->objKind == EXPRESSION) { + Expr *expr = (Expr *)obj.ptr(); + appendArgString(expr, &argString); + } else if (obj->objKind == EXPR_LIST) { + ExprList *elist = (ExprList *)obj.ptr(); + for (vector::const_iterator i = elist->exprs.begin(), + end = elist->exprs.end(); + i != end; ++i) { + if (!argString.empty()) + argString += ", "; - case EVAL_EXPR: { - EvalExpr *eval = (EvalExpr *) expr.ptr(); - // XXX compilation context - ExprListPtr evaled = desugarEvalExpr(eval, env); - return analyzeMulti(evaled, env, 0); + Expr *expr = i->ptr(); + appendArgString(expr, &argString); } + } + return analyzeStaticObject(Identifier::get(argString)); + } - case AND: { - return new MultiPValue(PVData(boolType, true)); - } + case TUPLE: { + Tuple *x = (Tuple *)expr.ptr(); + return analyzeCallExpr(operator_expr_tupleLiteral(), x->args, env); + } - case OR: { - return new MultiPValue(PVData(boolType, true)); - } + case PAREN: { + Paren *x = (Paren *)expr.ptr(); + return analyzeMulti(x->args, env, 0); + } - case LAMBDA: { - Lambda *x = (Lambda *) expr.ptr(); - if (!x->initialized) - initializeLambda(x, env); - return analyzeExpr(x->converted, env); - } + case INDEXING: { + Indexing *x = (Indexing *)expr.ptr(); + return analyzeIndexingExpr(x->expr, x->args, env); + } - case UNPACK: { - Unpack *unpack = (Unpack *) expr.ptr(); - if (unpack->expr->exprKind != FOREIGN_EXPR) - error("incorrect usage of unpack operator"); - return analyzeExpr(unpack->expr, env); - } + case CALL: { + Call *x = (Call *)expr.ptr(); + return analyzeCallExpr(x->expr, x->allArgs(), env); + } - case STATIC_EXPR: { - StaticExpr *x = (StaticExpr *) expr.ptr(); - ObjectPtr obj = evaluateOneStatic(x->expr, env); - TypePtr t = staticType(obj); - return new MultiPValue(PVData(t, true)); - } + case FIELD_REF: { + FieldRef *x = (FieldRef *)expr.ptr(); + if (!x->desugared) + desugarFieldRef(x, safeLookupModule(env)); + if (x->isDottedModuleName) + return analyzeExpr(x->desugared, env); - case DISPATCH_EXPR: { - error("incorrect usage of dispatch operator"); - return nullptr; + PVData pv = analyzeOne(x->expr, env); + if (!pv.ok()) + return nullptr; + if (pv.type->typeKind == STATIC_TYPE) { + StaticType *st = (StaticType *)pv.type.ptr(); + if (st->obj->objKind == MODULE) { + Module *m = (Module *)st->obj.ptr(); + ObjectPtr obj = safeLookupPublic(m, x->name); + return analyzeStaticObject(obj); } + } - case FOREIGN_EXPR: { - ForeignExpr *x = (ForeignExpr *) expr.ptr(); - return analyzeExpr(x->expr, x->getEnv()); - } + return analyzeExpr(x->desugared, env); + } - case OBJECT_EXPR: { - ObjectExpr *x = (ObjectExpr *) expr.ptr(); - return analyzeStaticObject(x->obj); - } + case STATIC_INDEXING: { + StaticIndexing *x = (StaticIndexing *)expr.ptr(); + if (!x->desugared) + x->desugared = desugarStaticIndexing(x); + return analyzeExpr(x->desugared, env); + } - default: - assert(false); + case VARIADIC_OP: { + VariadicOp *x = (VariadicOp *)expr.ptr(); + if (x->op == ADDRESS_OF) { + PVData pv = analyzeOne(x->exprs->exprs.front(), env); + if (!pv.ok()) return nullptr; + if (pv.isRValue) + error("can't take address of a temporary"); } + if (!x->desugared) + x->desugared = desugarVariadicOp(x); + return analyzeExpr(x->desugared, env); } - // - // analyzeStaticObject - // - - MultiPValuePtr analyzeStaticObject(ObjectPtr x) { - switch (x->objKind) { - case NEW_TYPE_DECL: { - NewTypeDecl *y = (NewTypeDecl *) x.ptr(); - assert(y->type->typeKind == NEW_TYPE); - initializeNewType(y->type); - - return new MultiPValue(PVData(y->type.ptr(), true)); - } - - case ENUM_MEMBER: { - EnumMember *y = (EnumMember *) x.ptr(); - assert(y->type->typeKind == ENUM_TYPE); - initializeEnumType((EnumType *) y->type.ptr()); + case EVAL_EXPR: { + EvalExpr *eval = (EvalExpr *)expr.ptr(); + // XXX compilation context + ExprListPtr evaled = desugarEvalExpr(eval, env); + return analyzeMulti(evaled, env, 0); + } - return new MultiPValue(PVData(y->type, true)); - } + case AND: { + return new MultiPValue(PVData(boolType, true)); + } - case GLOBAL_VARIABLE: { - GlobalVariable *y = (GlobalVariable *) x.ptr(); - if (y->hasParams()) { - TypePtr t = staticType(x); - return new MultiPValue(PVData(t, true)); - } - GVarInstancePtr inst = defaultGVarInstance(y); - return analyzeGVarInstance(inst); - } + case OR: { + return new MultiPValue(PVData(boolType, true)); + } - case EXTERNAL_VARIABLE: { - ExternalVariable *y = (ExternalVariable *) x.ptr(); - return new MultiPValue(analyzeExternalVariable(y)); - } + case LAMBDA: { + Lambda *x = (Lambda *)expr.ptr(); + if (!x->initialized) + initializeLambda(x, env); + return analyzeExpr(x->converted, env); + } - case EXTERNAL_PROCEDURE: { - ExternalProcedure *y = (ExternalProcedure *) x.ptr(); - analyzeExternalProcedure(y); - return new MultiPValue(PVData(y->ptrType, true)); - } + case UNPACK: { + Unpack *unpack = (Unpack *)expr.ptr(); + if (unpack->expr->exprKind != FOREIGN_EXPR) + error("incorrect usage of unpack operator"); + return analyzeExpr(unpack->expr, env); + } - case GLOBAL_ALIAS: { - GlobalAlias *y = (GlobalAlias *) x.ptr(); - if (y->hasParams()) { - TypePtr t = staticType(x); - return new MultiPValue(PVData(t, true)); - } - evaluatePredicate(y->patternVars, y->predicate, y->env); - return analyzeExpr(y->expr, y->env); - } + case STATIC_EXPR: { + StaticExpr *x = (StaticExpr *)expr.ptr(); + ObjectPtr obj = evaluateOneStatic(x->expr, env); + TypePtr t = staticType(obj); + return new MultiPValue(PVData(t, true)); + } - case VALUE_HOLDER: { - ValueHolder *y = (ValueHolder *) x.ptr(); - return new MultiPValue(PVData(y->type, true)); - } + case DISPATCH_EXPR: { + error("incorrect usage of dispatch operator"); + return nullptr; + } - case MULTI_STATIC: { - MultiStatic *y = (MultiStatic *) x.ptr(); - MultiPValuePtr mpv = new MultiPValue(); - for (size_t i = 0; i < y->size(); ++i) { - TypePtr t = objectType(y->values[i]); - mpv->values.push_back(PVData(t, true)); - } - return mpv; - } + case FOREIGN_EXPR: { + ForeignExpr *x = (ForeignExpr *)expr.ptr(); + return analyzeExpr(x->expr, x->getEnv()); + } - case RECORD_DECL: { - RecordDecl *y = (RecordDecl *) x.ptr(); - ObjectPtr z; - if (y->params.empty() && !y->varParam) - z = recordType(y, vector()).ptr(); - else - z = y; - return new MultiPValue(PVData(staticType(z), true)); - } + case OBJECT_EXPR: { + ObjectExpr *x = (ObjectExpr *)expr.ptr(); + return analyzeStaticObject(x->obj); + } - case VARIANT_DECL: { - VariantDecl *y = (VariantDecl *) x.ptr(); - ObjectPtr z; - if (y->params.empty() && !y->varParam) - z = variantType(y, vector()).ptr(); - else - z = y; - return new MultiPValue(PVData(staticType(z), true)); - } + default: + assert(false); + return nullptr; + } +} - case TYPE: - case PRIM_OP: - case PROCEDURE: - case MODULE: - case INTRINSIC: - case IDENTIFIER: { - TypePtr t = staticType(x); - return new MultiPValue(PVData(t, true)); - } +// +// analyzeStaticObject +// - case EVALUE: { - EValue *y = (EValue *) x.ptr(); - return new MultiPValue(PVData(y->type, y->forwardedRValue)); - } +MultiPValuePtr analyzeStaticObject(ObjectPtr x) { + switch (x->objKind) { + case NEW_TYPE_DECL: { + NewTypeDecl *y = (NewTypeDecl *)x.ptr(); + assert(y->type->typeKind == NEW_TYPE); + initializeNewType(y->type); - case MULTI_EVALUE: { - MultiEValue *y = (MultiEValue *) x.ptr(); - MultiPValuePtr z = new MultiPValue(); - for (size_t i = 0; i < y->values.size(); ++i) { - EValue *ev = y->values[i].ptr(); - z->values.push_back(PVData(ev->type, ev->forwardedRValue)); - } - return z; - } + return new MultiPValue(PVData(y->type.ptr(), true)); + } - case CVALUE: { - CValue *y = (CValue *) x.ptr(); - return new MultiPValue(PVData(y->type, y->forwardedRValue)); - } + case ENUM_MEMBER: { + EnumMember *y = (EnumMember *)x.ptr(); + assert(y->type->typeKind == ENUM_TYPE); + initializeEnumType((EnumType *)y->type.ptr()); - case MULTI_CVALUE: { - MultiCValue *y = (MultiCValue *) x.ptr(); - MultiPValuePtr z = new MultiPValue(); - for (size_t i = 0; i < y->values.size(); ++i) { - CValue *cv = y->values[i].ptr(); - z->add(PVData(cv->type, cv->forwardedRValue)); - } - return z; - } + return new MultiPValue(PVData(y->type, true)); + } - case PVALUE: { - PValue *y = (PValue *) x.ptr(); - return new MultiPValue(y->data); - } + case GLOBAL_VARIABLE: { + GlobalVariable *y = (GlobalVariable *)x.ptr(); + if (y->hasParams()) { + TypePtr t = staticType(x); + return new MultiPValue(PVData(t, true)); + } + GVarInstancePtr inst = defaultGVarInstance(y); + return analyzeGVarInstance(inst); + } - case MULTI_PVALUE: { - MultiPValue *y = (MultiPValue *) x.ptr(); - return y; - } + case EXTERNAL_VARIABLE: { + ExternalVariable *y = (ExternalVariable *)x.ptr(); + return new MultiPValue(analyzeExternalVariable(y)); + } - case PATTERN: - case MULTI_PATTERN: - error("pattern variable cannot be used as value"); - return nullptr; + case EXTERNAL_PROCEDURE: { + ExternalProcedure *y = (ExternalProcedure *)x.ptr(); + analyzeExternalProcedure(y); + return new MultiPValue(PVData(y->ptrType, true)); + } - default: - invalidStaticObjectError(x); - return nullptr; + case GLOBAL_ALIAS: { + GlobalAlias *y = (GlobalAlias *)x.ptr(); + if (y->hasParams()) { + TypePtr t = staticType(x); + return new MultiPValue(PVData(t, true)); } + evaluatePredicate(y->patternVars, y->predicate, y->env); + return analyzeExpr(y->expr, y->env); } - // - // lookupGVarInstance, defaultGVarInstance - // analyzeGVarIndexing, analyzeGVarInstance - // + case VALUE_HOLDER: { + ValueHolder *y = (ValueHolder *)x.ptr(); + return new MultiPValue(PVData(y->type, true)); + } - GVarInstancePtr lookupGVarInstance(GlobalVariablePtr x, - llvm::ArrayRef params) { - if (!x->instances) - x->instances = new ObjectTable(); - Pointer &y = x->instances->lookup(params); - if (!y) { - y = new GVarInstance(x, params); + case MULTI_STATIC: { + MultiStatic *y = (MultiStatic *)x.ptr(); + MultiPValuePtr mpv = new MultiPValue(); + for (size_t i = 0; i < y->size(); ++i) { + TypePtr t = objectType(y->values[i]); + mpv->values.push_back(PVData(t, true)); } - return (GVarInstance *) y.ptr(); + return mpv; } - GVarInstancePtr defaultGVarInstance(GlobalVariablePtr x) { - return lookupGVarInstance(x, vector()); + case RECORD_DECL: { + RecordDecl *y = (RecordDecl *)x.ptr(); + ObjectPtr z; + if (y->params.empty() && !y->varParam) + z = recordType(y, vector()).ptr(); + else + z = y; + return new MultiPValue(PVData(staticType(z), true)); } - GVarInstancePtr analyzeGVarIndexing(GlobalVariablePtr x, - ExprListPtr args, - EnvPtr env) { - assert(x->hasParams()); - MultiStaticPtr params = evaluateMultiStatic(args, env); - if (x->varParam.ptr()) { - if (params->size() < x->params.size()) - arityError2(x->params.size(), params->size()); - } else { - ensureArity(params, x->params.size()); - } - return lookupGVarInstance(x, params->values); + case VARIANT_DECL: { + VariantDecl *y = (VariantDecl *)x.ptr(); + ObjectPtr z; + if (y->params.empty() && !y->varParam) + z = variantType(y, vector()).ptr(); + else + z = y; + return new MultiPValue(PVData(staticType(z), true)); } - MultiPValuePtr analyzeGVarInstance(GVarInstancePtr x) { - if (x->analysis.ptr()) - return x->analysis; - CompileContextPusher pusher(x->gvar.ptr(), x->params); - if (x->analyzing) { - updateAnalysisErrorLocation(); - return nullptr; + case TYPE: + case PRIM_OP: + case PROCEDURE: + case MODULE: + case INTRINSIC: + case IDENTIFIER: { + TypePtr t = staticType(x); + return new MultiPValue(PVData(t, true)); + } + + case EVALUE: { + EValue *y = (EValue *)x.ptr(); + return new MultiPValue(PVData(y->type, y->forwardedRValue)); + } + + case MULTI_EVALUE: { + MultiEValue *y = (MultiEValue *)x.ptr(); + MultiPValuePtr z = new MultiPValue(); + for (size_t i = 0; i < y->values.size(); ++i) { + EValue *ev = y->values[i].ptr(); + z->values.push_back(PVData(ev->type, ev->forwardedRValue)); } - GlobalVariablePtr gvar = x->gvar; - if (!x->expr) - x->expr = clone(gvar->expr); - if (!x->env) { - x->env = new Env(gvar->env); - for (size_t i = 0; i < gvar->params.size(); ++i) { - addLocal(x->env, gvar->params[i], x->params[i]); - } - if (gvar->varParam.ptr()) { - MultiStaticPtr varParams = new MultiStatic(); - for (size_t i = gvar->params.size(); i < x->params.size(); ++i) - varParams->add(x->params[i]); - addLocal(x->env, gvar->varParam, varParams.ptr()); - } + return z; + } + + case CVALUE: { + CValue *y = (CValue *)x.ptr(); + return new MultiPValue(PVData(y->type, y->forwardedRValue)); + } + + case MULTI_CVALUE: { + MultiCValue *y = (MultiCValue *)x.ptr(); + MultiPValuePtr z = new MultiPValue(); + for (size_t i = 0; i < y->values.size(); ++i) { + CValue *cv = y->values[i].ptr(); + z->add(PVData(cv->type, cv->forwardedRValue)); } - x->analyzing = true; - evaluatePredicate(x->gvar->patternVars, x->gvar->predicate, x->env); - PVData pv = analyzeOne(x->expr, x->env); - x->analyzing = false; - if (!pv.ok()) - return nullptr; - x->analysis = new MultiPValue(PVData(pv.type, false)); - x->type = pv.type; - return x->analysis; + return z; } - // - // analyzeExternalVariable - // + case PVALUE: { + PValue *y = (PValue *)x.ptr(); + return new MultiPValue(y->data); + } - PVData analyzeExternalVariable(ExternalVariablePtr x) { - if (!x->type2) - x->type2 = evaluateType(x->type, x->env); - return PVData(x->type2, false); + case MULTI_PVALUE: { + MultiPValue *y = (MultiPValue *)x.ptr(); + return y; } - // - // analyzeExternalProcedure - // + case PATTERN: + case MULTI_PATTERN: + error("pattern variable cannot be used as value"); + return nullptr; - void analyzeExternalProcedure(ExternalProcedurePtr x) { - if (x->analyzed) - return; - if (!x->attributesVerified) - verifyAttributes(x); - vector argTypes; - for (size_t i = 0; i < x->args.size(); ++i) { - ExternalArgPtr y = x->args[i]; - y->type2 = evaluateType(y->type, x->env); - argTypes.push_back(y->type2); - } - if (!x->returnType) - x->returnType2 = nullptr; - else - x->returnType2 = evaluateType(x->returnType, x->env); - x->ptrType = cCodePointerType(x->callingConv, argTypes, - x->hasVarArgs, x->returnType2); - x->analyzed = true; + default: + invalidStaticObjectError(x); + return nullptr; } +} - // - // verifyAttributes - // +// +// lookupGVarInstance, defaultGVarInstance +// analyzeGVarIndexing, analyzeGVarInstance +// - void verifyAttributes(ExternalProcedurePtr x) { - assert(!x->attributesVerified); - x->attributesVerified = true; - x->attrDLLImport = false; - x->attrDLLExport = false; - int callingConv = -1; - x->attrAsmLabel = ""; +GVarInstancePtr lookupGVarInstance(GlobalVariablePtr x, + llvm::ArrayRef params) { + if (!x->instances) + x->instances = new ObjectTable(); + Pointer &y = x->instances->lookup(params); + if (!y) { + y = new GVarInstance(x, params); + } + return (GVarInstance *)y.ptr(); +} - MultiStaticPtr attrs = evaluateMultiStatic(x->attributes, x->env); +GVarInstancePtr defaultGVarInstance(GlobalVariablePtr x) { + return lookupGVarInstance(x, vector()); +} - for (size_t i = 0; i < attrs->size(); ++i) { - ObjectPtr obj = attrs->values[i]; +GVarInstancePtr analyzeGVarIndexing(GlobalVariablePtr x, ExprListPtr args, + EnvPtr env) { + assert(x->hasParams()); + MultiStaticPtr params = evaluateMultiStatic(args, env); + if (x->varParam.ptr()) { + if (params->size() < x->params.size()) + arityError2(x->params.size(), params->size()); + } else { + ensureArity(params, x->params.size()); + } + return lookupGVarInstance(x, params->values); +} - switch (obj->objKind) { - case PRIM_OP: { - PrimOp *y = (PrimOp *) obj.ptr(); - switch (y->primOpCode) { - case PRIM_AttributeStdCall: { - if (callingConv != -1) - error(x, "cannot specify more than one calling convention in external attributes"); - callingConv = CC_STDCALL; - break; - } - case PRIM_AttributeFastCall: { - if (callingConv != -1) - error(x, "cannot specify more than one calling convention in external attributes"); - callingConv = CC_FASTCALL; - break; - } - case PRIM_AttributeThisCall: { - if (callingConv != -1) - error(x, "cannot specify more than one calling convention in external attributes"); - callingConv = CC_THISCALL; - break; - } - case PRIM_AttributeCCall: { - if (callingConv != -1) - error(x, "cannot specify more than one calling convention in external attributes"); - callingConv = CC_DEFAULT; - break; - } - case PRIM_AttributeLLVMCall: { - if (callingConv != -1) - error(x, "cannot specify more than one calling convention in external attributes"); - callingConv = CC_LLVM; - break; - } - case PRIM_AttributeDLLImport: { - if (x->attrDLLExport) - error(x, "dllimport specified after dllexport in external attributes"); - x->attrDLLImport = true; - break; - } - case PRIM_AttributeDLLExport: { - if (x->attrDLLImport) - error(x, "dllexport specified after dllimport in external attributes"); - x->attrDLLExport = true; - break; - } - default: { - string buf; - llvm::raw_string_ostream os(buf); - os << "invalid external function attribute: "; - printStaticName(os, obj); - error(x, os.str()); - } - } - break; - } - case IDENTIFIER: { - Identifier *y = (Identifier *) obj.ptr(); - x->attrAsmLabel = y->str; - break; - } - default: { - string buf; - llvm::raw_string_ostream os(buf); - os << "invalid external function attribute: "; - printStaticName(os, obj); - error(x, os.str()); - } - } +MultiPValuePtr analyzeGVarInstance(GVarInstancePtr x) { + if (x->analysis.ptr()) + return x->analysis; + CompileContextPusher pusher(x->gvar.ptr(), x->params); + if (x->analyzing) { + updateAnalysisErrorLocation(); + return nullptr; + } + GlobalVariablePtr gvar = x->gvar; + if (!x->expr) + x->expr = clone(gvar->expr); + if (!x->env) { + x->env = new Env(gvar->env); + for (size_t i = 0; i < gvar->params.size(); ++i) { + addLocal(x->env, gvar->params[i], x->params[i]); + } + if (gvar->varParam.ptr()) { + MultiStaticPtr varParams = new MultiStatic(); + for (size_t i = gvar->params.size(); i < x->params.size(); ++i) + varParams->add(x->params[i]); + addLocal(x->env, gvar->varParam, varParams.ptr()); } - if (callingConv == -1) - callingConv = CC_DEFAULT; - x->callingConv = (CallingConv) callingConv; } + x->analyzing = true; + evaluatePredicate(x->gvar->patternVars, x->gvar->predicate, x->env); + PVData pv = analyzeOne(x->expr, x->env); + x->analyzing = false; + if (!pv.ok()) + return nullptr; + x->analysis = new MultiPValue(PVData(pv.type, false)); + x->type = pv.type; + return x->analysis; +} - void verifyAttributes(ExternalVariablePtr var) { - assert(!var->attributesVerified); - var->attributesVerified = true; - var->attrDLLImport = false; - var->attrDLLExport = false; +// +// analyzeExternalVariable +// - MultiStaticPtr attrs = evaluateMultiStatic(var->attributes, var->env); +PVData analyzeExternalVariable(ExternalVariablePtr x) { + if (!x->type2) + x->type2 = evaluateType(x->type, x->env); + return PVData(x->type2, false); +} - for (size_t i = 0; i < attrs->size(); ++i) { - ObjectPtr obj = attrs->values[i]; +// +// analyzeExternalProcedure +// + +void analyzeExternalProcedure(ExternalProcedurePtr x) { + if (x->analyzed) + return; + if (!x->attributesVerified) + verifyAttributes(x); + vector argTypes; + for (size_t i = 0; i < x->args.size(); ++i) { + ExternalArgPtr y = x->args[i]; + y->type2 = evaluateType(y->type, x->env); + argTypes.push_back(y->type2); + } + if (!x->returnType) + x->returnType2 = nullptr; + else + x->returnType2 = evaluateType(x->returnType, x->env); + x->ptrType = cCodePointerType(x->callingConv, argTypes, x->hasVarArgs, + x->returnType2); + x->analyzed = true; +} + +// +// verifyAttributes +// + +void verifyAttributes(ExternalProcedurePtr x) { + assert(!x->attributesVerified); + x->attributesVerified = true; + x->attrDLLImport = false; + x->attrDLLExport = false; + int callingConv = -1; + x->attrAsmLabel = ""; + + MultiStaticPtr attrs = evaluateMultiStatic(x->attributes, x->env); - if (obj->objKind != PRIM_OP) { + for (size_t i = 0; i < attrs->size(); ++i) { + ObjectPtr obj = attrs->values[i]; + + switch (obj->objKind) { + case PRIM_OP: { + PrimOp *y = (PrimOp *)obj.ptr(); + switch (y->primOpCode) { + case PRIM_AttributeStdCall: { + if (callingConv != -1) + error(x, "cannot specify more than one calling convention " + "in external attributes"); + callingConv = CC_STDCALL; + break; + } + case PRIM_AttributeFastCall: { + if (callingConv != -1) + error(x, "cannot specify more than one calling convention " + "in external attributes"); + callingConv = CC_FASTCALL; + break; + } + case PRIM_AttributeThisCall: { + if (callingConv != -1) + error(x, "cannot specify more than one calling convention " + "in external attributes"); + callingConv = CC_THISCALL; + break; + } + case PRIM_AttributeCCall: { + if (callingConv != -1) + error(x, "cannot specify more than one calling convention " + "in external attributes"); + callingConv = CC_DEFAULT; + break; + } + case PRIM_AttributeLLVMCall: { + if (callingConv != -1) + error(x, "cannot specify more than one calling convention " + "in external attributes"); + callingConv = CC_LLVM; + break; + } + case PRIM_AttributeDLLImport: { + if (x->attrDLLExport) + error(x, "dllimport specified after dllexport in external " + "attributes"); + x->attrDLLImport = true; + break; + } + case PRIM_AttributeDLLExport: { + if (x->attrDLLImport) + error(x, "dllexport specified after dllimport in external " + "attributes"); + x->attrDLLExport = true; + break; + } + default: { string buf; llvm::raw_string_ostream os(buf); - os << "invalid external variable attribute: "; + os << "invalid external function attribute: "; printStaticName(os, obj); - error(var, os.str()); + error(x, os.str()); } - - PrimOp *y = (PrimOp *) obj.ptr(); - switch (y->primOpCode) { - case PRIM_AttributeDLLImport: { - if (var->attrDLLExport) - error(var, "dllimport specified after dllexport in external attributes"); - var->attrDLLImport = true; - break; - } - case PRIM_AttributeDLLExport: { - if (var->attrDLLImport) - error(var, "dllexport specified after dllimport in external attributes"); - var->attrDLLExport = true; - break; - } - default: { - string buf; - llvm::raw_string_ostream os(buf); - os << "invalid external variable attribute: "; - printStaticName(os, obj); - error(var, os.str()); - } } + break; + } + case IDENTIFIER: { + Identifier *y = (Identifier *)obj.ptr(); + x->attrAsmLabel = y->str; + break; + } + default: { + string buf; + llvm::raw_string_ostream os(buf); + os << "invalid external function attribute: "; + printStaticName(os, obj); + error(x, os.str()); + } } } + if (callingConv == -1) + callingConv = CC_DEFAULT; + x->callingConv = (CallingConv)callingConv; +} - void verifyAttributes(ModulePtr mod) { - assert(!mod->attributesVerified); - mod->attributesVerified = true; +void verifyAttributes(ExternalVariablePtr var) { + assert(!var->attributesVerified); + var->attributesVerified = true; + var->attrDLLImport = false; + var->attrDLLExport = false; - if (mod->declaration != nullptr && mod->declaration->attributes != nullptr) { - MultiStaticPtr attrs = evaluateMultiStatic(mod->declaration->attributes, mod->env); + MultiStaticPtr attrs = evaluateMultiStatic(var->attributes, var->env); - for (size_t i = 0; i < attrs->size(); ++i) { - ObjectPtr obj = attrs->values[i]; + for (size_t i = 0; i < attrs->size(); ++i) { + ObjectPtr obj = attrs->values[i]; - switch (obj->objKind) { - case TYPE: { - if (obj->objKind == TYPE) { - Type *ty = (Type *) obj.ptr(); - if (ty->typeKind == FLOAT_TYPE) { - mod->attrDefaultFloatType = (FloatType *) ty; - } else if (ty->typeKind == INTEGER_TYPE) { - mod->attrDefaultIntegerType = (IntegerType *) ty; - } - } - break; - } - case IDENTIFIER: { - Identifier *y = (Identifier *) obj.ptr(); - mod->attrBuildFlags.push_back(y->str); - break; + if (obj->objKind != PRIM_OP) { + string buf; + llvm::raw_string_ostream os(buf); + os << "invalid external variable attribute: "; + printStaticName(os, obj); + error(var, os.str()); + } + + PrimOp *y = (PrimOp *)obj.ptr(); + switch (y->primOpCode) { + case PRIM_AttributeDLLImport: { + if (var->attrDLLExport) + error(var, "dllimport specified after dllexport in external " + "attributes"); + var->attrDLLImport = true; + break; + } + case PRIM_AttributeDLLExport: { + if (var->attrDLLImport) + error(var, "dllexport specified after dllimport in external " + "attributes"); + var->attrDLLExport = true; + break; + } + default: { + string buf; + llvm::raw_string_ostream os(buf); + os << "invalid external variable attribute: "; + printStaticName(os, obj); + error(var, os.str()); + } + } + } +} + +void verifyAttributes(ModulePtr mod) { + assert(!mod->attributesVerified); + mod->attributesVerified = true; + + if (mod->declaration != nullptr && + mod->declaration->attributes != nullptr) { + MultiStaticPtr attrs = + evaluateMultiStatic(mod->declaration->attributes, mod->env); + + for (size_t i = 0; i < attrs->size(); ++i) { + ObjectPtr obj = attrs->values[i]; + + switch (obj->objKind) { + case TYPE: { + if (obj->objKind == TYPE) { + Type *ty = (Type *)obj.ptr(); + if (ty->typeKind == FLOAT_TYPE) { + mod->attrDefaultFloatType = (FloatType *)ty; + } else if (ty->typeKind == INTEGER_TYPE) { + mod->attrDefaultIntegerType = (IntegerType *)ty; } - default: - string buf; - llvm::raw_string_ostream os(buf); - os << "invalid module attribute: "; - printStaticName(os, obj); - error(mod->declaration, os.str()); } + break; + } + case IDENTIFIER: { + Identifier *y = (Identifier *)obj.ptr(); + mod->attrBuildFlags.push_back(y->str); + break; + } + default: + string buf; + llvm::raw_string_ostream os(buf); + os << "invalid module attribute: "; + printStaticName(os, obj); + error(mod->declaration, os.str()); } } } +} - // - // analyzeIndexingExpr - // - - static bool isTypeConstructor(ObjectPtr x) { - if (x->objKind == PRIM_OP) { - PrimOpPtr y = (PrimOp *) x.ptr(); - switch (y->primOpCode) { - case PRIM_Pointer: - case PRIM_CodePointer: - case PRIM_ExternalCodePointer: - case PRIM_Array: - case PRIM_Vec: - case PRIM_Tuple: - case PRIM_Union: - case PRIM_Static: - return true; - default: - return false; - } - } else if (x->objKind == RECORD_DECL) { +// +// analyzeIndexingExpr +// + +static bool isTypeConstructor(ObjectPtr x) { + if (x->objKind == PRIM_OP) { + PrimOpPtr y = (PrimOp *)x.ptr(); + switch (y->primOpCode) { + case PRIM_Pointer: + case PRIM_CodePointer: + case PRIM_ExternalCodePointer: + case PRIM_Array: + case PRIM_Vec: + case PRIM_Tuple: + case PRIM_Union: + case PRIM_Static: return true; - } else if (x->objKind == VARIANT_DECL) { - return true; - } else { + default: return false; } + } else if (x->objKind == RECORD_DECL) { + return true; + } else if (x->objKind == VARIANT_DECL) { + return true; + } else { + return false; } +} - MultiPValuePtr analyzeIndexingExpr(ExprPtr indexable, - ExprListPtr args, - EnvPtr env) { - PVData pv = analyzeOne(indexable, env); - if (!pv.ok()) - return nullptr; - ObjectPtr obj = unwrapStaticType(pv.type); - if (obj.ptr()) { - if (isTypeConstructor(obj)) { - MultiStaticPtr params = evaluateMultiStatic(args, env); - PVData out = analyzeTypeConstructor(obj, params); - return new MultiPValue(out); - } - if (obj->objKind == GLOBAL_ALIAS) { - GlobalAlias *x = (GlobalAlias *) obj.ptr(); - return analyzeAliasIndexing(x, args, env); - } - if (obj->objKind == GLOBAL_VARIABLE) { - GlobalVariable *x = (GlobalVariable *) obj.ptr(); - GVarInstancePtr y = analyzeGVarIndexing(x, args, env); - return analyzeGVarInstance(y); - } - if (obj->objKind != VALUE_HOLDER && obj->objKind != IDENTIFIER) - error("invalid indexing operation"); +MultiPValuePtr analyzeIndexingExpr(ExprPtr indexable, ExprListPtr args, + EnvPtr env) { + PVData pv = analyzeOne(indexable, env); + if (!pv.ok()) + return nullptr; + ObjectPtr obj = unwrapStaticType(pv.type); + if (obj.ptr()) { + if (isTypeConstructor(obj)) { + MultiStaticPtr params = evaluateMultiStatic(args, env); + PVData out = analyzeTypeConstructor(obj, params); + return new MultiPValue(out); } - ExprListPtr args2 = new ExprList(indexable); - args2->add(args); - return analyzeCallExpr(operator_expr_index(), args2, env); - } - - // - // unwrapByRef - // - - bool unwrapByRef(TypePtr &t) { - if (t->typeKind == RECORD_TYPE) { - RecordType *rt = (RecordType *) t.ptr(); - if (rt->record.ptr() == primitive_ByRef().ptr()) { - assert(rt->params.size() == 1); - ObjectPtr obj = rt->params[0]; - if (obj->objKind != TYPE) { - string buf; - llvm::raw_string_ostream ostr(buf); - ostr << "invalid return type: " << t; - error(ostr.str()); - } - t = (Type *) obj.ptr(); - return true; + if (obj->objKind == GLOBAL_ALIAS) { + GlobalAlias *x = (GlobalAlias *)obj.ptr(); + return analyzeAliasIndexing(x, args, env); + } + if (obj->objKind == GLOBAL_VARIABLE) { + GlobalVariable *x = (GlobalVariable *)obj.ptr(); + GVarInstancePtr y = analyzeGVarIndexing(x, args, env); + return analyzeGVarInstance(y); + } + if (obj->objKind != VALUE_HOLDER && obj->objKind != IDENTIFIER) + error("invalid indexing operation"); + } + ExprListPtr args2 = new ExprList(indexable); + args2->add(args); + return analyzeCallExpr(operator_expr_index(), args2, env); +} + +// +// unwrapByRef +// + +bool unwrapByRef(TypePtr &t) { + if (t->typeKind == RECORD_TYPE) { + RecordType *rt = (RecordType *)t.ptr(); + if (rt->record.ptr() == primitive_ByRef().ptr()) { + assert(rt->params.size() == 1); + ObjectPtr obj = rt->params[0]; + if (obj->objKind != TYPE) { + string buf; + llvm::raw_string_ostream ostr(buf); + ostr << "invalid return type: " << t; + error(ostr.str()); } + t = (Type *)obj.ptr(); + return true; } - return false; } + return false; +} - // - // constructType - // +// +// constructType +// - TypePtr constructType(ObjectPtr constructor, MultiStaticPtr args) { - if (constructor->objKind == PRIM_OP) { - PrimOpPtr x = (PrimOp *) constructor.ptr(); +TypePtr constructType(ObjectPtr constructor, MultiStaticPtr args) { + if (constructor->objKind == PRIM_OP) { + PrimOpPtr x = (PrimOp *)constructor.ptr(); - switch (x->primOpCode) { - case PRIM_Pointer: { - ensureArity(args, 1); - TypePtr pointeeType = staticToType(args, 0); - return pointerType(pointeeType); - } + switch (x->primOpCode) { + case PRIM_Pointer: { + ensureArity(args, 1); + TypePtr pointeeType = staticToType(args, 0); + return pointerType(pointeeType); + } - case PRIM_CodePointer: { - ensureArity(args, 2); - vector argTypes; - staticToTypeTuple(args, 0, argTypes); - vector returnTypes; - staticToTypeTuple(args, 1, returnTypes); - vector returnIsRef(returnTypes.size(), false); - for (size_t i = 0; i < returnTypes.size(); ++i) - returnIsRef[i] = unwrapByRef(returnTypes[i]); - return codePointerType(argTypes, returnIsRef, returnTypes); - } + case PRIM_CodePointer: { + ensureArity(args, 2); + vector argTypes; + staticToTypeTuple(args, 0, argTypes); + vector returnTypes; + staticToTypeTuple(args, 1, returnTypes); + vector returnIsRef(returnTypes.size(), false); + for (size_t i = 0; i < returnTypes.size(); ++i) + returnIsRef[i] = unwrapByRef(returnTypes[i]); + return codePointerType(argTypes, returnIsRef, returnTypes); + } - case PRIM_ExternalCodePointer: { - ensureArity(args, 4); - - CallingConv cc = staticToCallingConv(args, 0); - bool hasVarArgs = staticToBool(args, 1); - vector argTypes; - staticToTypeTuple(args, 2, argTypes); - vector returnTypes; - staticToTypeTuple(args, 3, returnTypes); - if (returnTypes.size() > 1) - argumentError(1, "C code cannot return more than one value"); - TypePtr returnType; - if (returnTypes.size() == 1) - returnType = returnTypes[0]; - return cCodePointerType(cc, argTypes, hasVarArgs, returnType); - } + case PRIM_ExternalCodePointer: { + ensureArity(args, 4); - case PRIM_Array: { - ensureArity(args, 2); - TypePtr t = staticToType(args, 0); - return arrayType(t, unsigned(staticToInt(args, 1))); - } + CallingConv cc = staticToCallingConv(args, 0); + bool hasVarArgs = staticToBool(args, 1); + vector argTypes; + staticToTypeTuple(args, 2, argTypes); + vector returnTypes; + staticToTypeTuple(args, 3, returnTypes); + if (returnTypes.size() > 1) + argumentError(1, "C code cannot return more than one value"); + TypePtr returnType; + if (returnTypes.size() == 1) + returnType = returnTypes[0]; + return cCodePointerType(cc, argTypes, hasVarArgs, returnType); + } - case PRIM_Vec: { - ensureArity(args, 2); - TypePtr t = staticToType(args, 0); - return vecType(t, unsigned(staticToInt(args, 1))); - } + case PRIM_Array: { + ensureArity(args, 2); + TypePtr t = staticToType(args, 0); + return arrayType(t, unsigned(staticToInt(args, 1))); + } - case PRIM_Tuple: { - vector types; - for (size_t i = 0; i < args->size(); ++i) - types.push_back(staticToType(args, i)); - return tupleType(types); - } + case PRIM_Vec: { + ensureArity(args, 2); + TypePtr t = staticToType(args, 0); + return vecType(t, unsigned(staticToInt(args, 1))); + } - case PRIM_Union: { - vector types; - for (size_t i = 0; i < args->size(); ++i) - types.push_back(staticToType(args, i)); - return unionType(types); - } + case PRIM_Tuple: { + vector types; + for (size_t i = 0; i < args->size(); ++i) + types.push_back(staticToType(args, i)); + return tupleType(types); + } - case PRIM_Static: { - ensureArity(args, 1); - return staticType(args->values[0]); - } + case PRIM_Union: { + vector types; + for (size_t i = 0; i < args->size(); ++i) + types.push_back(staticToType(args, i)); + return unionType(types); + } - default: - assert(false); - return nullptr; - } - } else if (constructor->objKind == RECORD_DECL) { - RecordDeclPtr x = (RecordDecl *) constructor.ptr(); - if (x->varParam.ptr()) { - if (args->size() < x->params.size()) - arityError2(x->params.size(), args->size()); - } else { - ensureArity(args, x->params.size()); - } - return recordType(x, args->values); - } else if (constructor->objKind == VARIANT_DECL) { - VariantDeclPtr x = (VariantDecl *) constructor.ptr(); - if (x->varParam.ptr()) { - if (args->size() < x->params.size()) - arityError2(x->params.size(), args->size()); - } else { - ensureArity(args, x->params.size()); - } - return variantType(x, args->values); - } else { + case PRIM_Static: { + ensureArity(args, 1); + return staticType(args->values[0]); + } + + default: assert(false); return nullptr; } + } else if (constructor->objKind == RECORD_DECL) { + RecordDeclPtr x = (RecordDecl *)constructor.ptr(); + if (x->varParam.ptr()) { + if (args->size() < x->params.size()) + arityError2(x->params.size(), args->size()); + } else { + ensureArity(args, x->params.size()); + } + return recordType(x, args->values); + } else if (constructor->objKind == VARIANT_DECL) { + VariantDeclPtr x = (VariantDecl *)constructor.ptr(); + if (x->varParam.ptr()) { + if (args->size() < x->params.size()) + arityError2(x->params.size(), args->size()); + } else { + ensureArity(args, x->params.size()); + } + return variantType(x, args->values); + } else { + assert(false); + return nullptr; } +} - // - // analyzeTypeConstructor - // +// +// analyzeTypeConstructor +// - PVData analyzeTypeConstructor(ObjectPtr obj, MultiStaticPtr args) { - TypePtr t = constructType(obj, args); - return staticPValue(t.ptr()); - } +PVData analyzeTypeConstructor(ObjectPtr obj, MultiStaticPtr args) { + TypePtr t = constructType(obj, args); + return staticPValue(t.ptr()); +} - // - // analyzeAliasIndexing - // +// +// analyzeAliasIndexing +// + +MultiPValuePtr analyzeAliasIndexing(GlobalAliasPtr x, ExprListPtr args, + EnvPtr env) { + assert(x->hasParams()); + MultiStaticPtr params = evaluateMultiStatic(args, env); + if (x->varParam.ptr()) { + if (params->size() < x->params.size()) + arityError2(x->params.size(), params->size()); + } else { + ensureArity(params, x->params.size()); + } + EnvPtr bodyEnv = new Env(x->env); + for (size_t i = 0; i < x->params.size(); ++i) { + addLocal(bodyEnv, x->params[i], params->values[i]); + } + if (x->varParam.ptr()) { + MultiStaticPtr varParams = new MultiStatic(); + for (size_t i = x->params.size(); i < params->size(); ++i) + varParams->add(params->values[i]); + addLocal(bodyEnv, x->varParam, varParams.ptr()); + } + evaluatePredicate(x->patternVars, x->predicate, bodyEnv); + AnalysisCachingDisabler disabler; + return analyzeExpr(x->expr, bodyEnv); +} - MultiPValuePtr analyzeAliasIndexing(GlobalAliasPtr x, - ExprListPtr args, - EnvPtr env) { - assert(x->hasParams()); - MultiStaticPtr params = evaluateMultiStatic(args, env); - if (x->varParam.ptr()) { - if (params->size() < x->params.size()) - arityError2(x->params.size(), params->size()); - } else { - ensureArity(params, x->params.size()); +// +// analyzeReturn +// + +MultiPValuePtr analyzeReturn(llvm::ArrayRef returnIsRef, + llvm::ArrayRef returnTypes) { + MultiPValuePtr x = new MultiPValue(); + for (size_t i = 0; i < returnTypes.size(); ++i) { + PVData pv = PVData(returnTypes[i], !returnIsRef[i]); + x->values.push_back(pv); + } + return x.ptr(); +} + +// +// analyzeIntrinsic +// + +// this class is designed to pervert the intrinsic verification code +// in llvm/Intrinsics.gen, selected by #define GET_INTRINSIC_VERIFIER, +// into doing type checking and output type propagation for an intrinsic. +// GET_INTRINSIC_VERIFIER contains a function body that expects to have +// the following in scope: +// - namespace llvm +// - int-sized bit mask constants `ExtendedElementVectorType` and +// `TruncatedElementVectorType` +// - an `llvm::Intrinsic::ID ID` +// - an `llvm::FunctionType *IF`. This is unused by our code, so we provide +// a dummy IF variable instead +// - a function that can be called as +// `VerifyIntrinsicPrototype(ID, IF, numReturns, numArgs, ...)` +// where the varargs are either values from the llvm::MVT::SimpleValueType +// enum signifying the expected return or argument type, or negative values +// equal to `~index`, indicating that that argument must be the same type as +// the `index`th vararg. +struct IntrinsicAnalyzer { + llvm::Intrinsic::ID ID; + llvm::ArrayRef inputTypes; + + string outError; + llvm::SmallVector ArgTys; + + IntrinsicAnalyzer(llvm::Intrinsic::ID ID, + llvm::ArrayRef inputTypes) + : ID(ID), inputTypes(inputTypes) {} + + static void + skipReturnType(llvm::ArrayRef &Infos) { + using namespace llvm; + using namespace Intrinsic; + IITDescriptor D = Infos.front(); + Infos = Infos.slice(1); + + switch (D.Kind) { + case IITDescriptor::Void: + return; + case IITDescriptor::MMX: + return; + case IITDescriptor::Metadata: + return; + case IITDescriptor::Float: + return; + case IITDescriptor::Double: + return; + case IITDescriptor::Integer: + return; + case IITDescriptor::Vector: + skipReturnType(Infos); + return; + case IITDescriptor::Pointer: + skipReturnType(Infos); + return; + case IITDescriptor::Struct: { + for (unsigned i = 0, e = D.Struct_NumElements; i != e; ++i) + skipReturnType(Infos); + return; + } + case IITDescriptor::Argument: + return; + case IITDescriptor::ExtendArgument: + return; + case IITDescriptor::TruncArgument: + return; + default: + return; } - EnvPtr bodyEnv = new Env(x->env); - for (size_t i = 0; i < x->params.size(); ++i) { - addLocal(bodyEnv, x->params[i], params->values[i]); + llvm_unreachable("unhandled"); + } + + void + VerifyIntrinsicType(llvm::Type *Ty, + llvm::ArrayRef &Infos, + llvm::raw_string_ostream &errors, size_t ai) { + using namespace llvm; + using namespace Intrinsic; + + // If we ran out of descriptors, there are too many arguments. + if (Infos.empty()) { + errors << "intrinsic has too many arguments"; + return; } - if (x->varParam.ptr()) { - MultiStaticPtr varParams = new MultiStatic(); - for (size_t i = x->params.size(); i < params->size(); ++i) - varParams->add(params->values[i]); - addLocal(bodyEnv, x->varParam, varParams.ptr()); - } - evaluatePredicate(x->patternVars, x->predicate, bodyEnv); - AnalysisCachingDisabler disabler; - return analyzeExpr(x->expr, bodyEnv); - } - - // - // analyzeReturn - // - - MultiPValuePtr analyzeReturn(llvm::ArrayRef returnIsRef, - llvm::ArrayRef returnTypes) { - MultiPValuePtr x = new MultiPValue(); - for (size_t i = 0; i < returnTypes.size(); ++i) { - PVData pv = PVData(returnTypes[i], !returnIsRef[i]); - x->values.push_back(pv); - } - return x.ptr(); - } - - // - // analyzeIntrinsic - // - - // this class is designed to pervert the intrinsic verification code - // in llvm/Intrinsics.gen, selected by #define GET_INTRINSIC_VERIFIER, - // into doing type checking and output type propagation for an intrinsic. - // GET_INTRINSIC_VERIFIER contains a function body that expects to have - // the following in scope: - // - namespace llvm - // - int-sized bit mask constants `ExtendedElementVectorType` and `TruncatedElementVectorType` - // - an `llvm::Intrinsic::ID ID` - // - an `llvm::FunctionType *IF`. This is unused by our code, so we provide - // a dummy IF variable instead - // - a function that can be called as - // `VerifyIntrinsicPrototype(ID, IF, numReturns, numArgs, ...)` - // where the varargs are either values from the llvm::MVT::SimpleValueType enum - // signifying the expected return or argument type, or negative values - // equal to `~index`, indicating that that argument must be the same type as - // the `index`th vararg. - struct IntrinsicAnalyzer { - llvm::Intrinsic::ID ID; - llvm::ArrayRef inputTypes; - - string outError; - llvm::SmallVector ArgTys; - - IntrinsicAnalyzer(llvm::Intrinsic::ID ID, - llvm::ArrayRef inputTypes) - : ID(ID), inputTypes(inputTypes) { - } - - static void skipReturnType( - llvm::ArrayRef &Infos) { - using namespace llvm; - using namespace Intrinsic; - IITDescriptor D = Infos.front(); - Infos = Infos.slice(1); - - switch (D.Kind) { - case IITDescriptor::Void: return; - case IITDescriptor::MMX: return; - case IITDescriptor::Metadata: return; - case IITDescriptor::Float: return; - case IITDescriptor::Double: return; - case IITDescriptor::Integer: return; - case IITDescriptor::Vector: - skipReturnType(Infos); - return; - case IITDescriptor::Pointer: - skipReturnType(Infos); - return; - case IITDescriptor::Struct: { - for (unsigned i = 0, e = D.Struct_NumElements; i != e; ++i) - skipReturnType(Infos); - return; - } - case IITDescriptor::Argument: return; - case IITDescriptor::ExtendArgument: return; - case IITDescriptor::TruncArgument: return; - default: return; + IITDescriptor D = Infos.front(); + Infos = Infos.slice(1); + + switch (D.Kind) { + case IITDescriptor::Void: + if (!Ty->isVoidTy()) { + errors << "intrinsic argument " << (ai + 1) + << " must match LLVM void type, but got "; + Ty->print(errors); + } + return; + case IITDescriptor::MMX: + if (!Ty->isX86_AMXTy()) { + errors << "intrinsic argument " << (ai + 1) + << " must match LLVM MMX type, but got "; + Ty->print(errors); + } + return; + case IITDescriptor::Metadata: + if (!Ty->isMetadataTy()) { + errors << "intrinsic argument " << (ai + 1) + << " must match LLVM metadata type, but got "; + Ty->print(errors); + } + return; + case IITDescriptor::Float: + if (!Ty->isFloatTy()) { + errors << "intrinsic argument " << (ai + 1) + << " must match LLVM float type, but got "; + Ty->print(errors); + } + return; + case IITDescriptor::Double: + if (!Ty->isDoubleTy()) { + errors << "intrinsic argument " << (ai + 1) + << " must match LLVM double type, but got "; + Ty->print(errors); } - llvm_unreachable("unhandled"); + return; + case IITDescriptor::Integer: + if (!Ty->isIntegerTy(D.Integer_Width)) { + errors << "intrinsic argument " << (ai + 1) + << " must match LLVM i" << D.Integer_Width + << " type, but got "; + Ty->print(errors); + } + return; + case IITDescriptor::Vector: { + llvm::VectorType *VT = dyn_cast(Ty); + if (VT == nullptr) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM vector type, but got "; + Ty->print(errors); + } else if (VT->getElementCount() != D.Vector_Width) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM vector type with " + << D.Vector_Width << " elements, but got "; + Ty->print(errors); + } + VerifyIntrinsicType(VT->getElementType(), Infos, errors, ai); + return; + } + case IITDescriptor::Pointer: { + llvm::PointerType *PT = dyn_cast(Ty); + if (PT == 0) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM pointer type, but got "; + Ty->print(errors); + } else if (PT->getAddressSpace() != D.Pointer_AddressSpace) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM pointer type with" + << D.Pointer_AddressSpace << " address space, but got "; + Ty->print(errors); + } + VerifyIntrinsicType(PT->getElementType(), Infos, errors, ai); + return; } - void VerifyIntrinsicType( - llvm::Type *Ty, - llvm::ArrayRef &Infos, - llvm::raw_string_ostream &errors, size_t ai) { - using namespace llvm; - using namespace Intrinsic; + case IITDescriptor::Struct: { + llvm::StructType *ST = dyn_cast(Ty); + if (ST == 0) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM struct type, but got "; + Ty->print(errors); + } else if (ST->getNumElements() != D.Struct_NumElements) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM struct type with " + << D.Struct_NumElements << " elements, but got "; + Ty->print(errors); + } + for (unsigned i = 0, e = D.Struct_NumElements; i != e; ++i) + VerifyIntrinsicType(ST->getElementType(i), Infos, errors, ai); + return; + } - // If we ran out of descriptors, there are too many arguments. - if (Infos.empty()) { - errors << "intrinsic has too many arguments"; + case IITDescriptor::Argument: + // Two cases here - If this is the second occurrence of an argument, + // verify that the later instance matches the previous instance. + if (D.getArgumentNumber() < ArgTys.size()) { + if (Ty != ArgTys[D.getArgumentNumber()]) { + errors << "intrinsic argument " << (ai + 1) + << " must match LLVM type of argument " + << D.getArgumentNumber() << ", which is "; + ArgTys[D.getArgumentNumber()]->print(errors); + errors << ", but got "; + Ty->print(errors); + } return; } - IITDescriptor D = Infos.front(); - Infos = Infos.slice(1); - - switch (D.Kind) { - case IITDescriptor::Void: - if (!Ty->isVoidTy()) { - errors << "intrinsic argument " << (ai + 1) - << " must match LLVM void type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::MMX: - if (!Ty->isX86_AMXTy()) { - errors << "intrinsic argument " << (ai + 1) - << " must match LLVM MMX type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::Metadata: - if (!Ty->isMetadataTy()) { - errors << "intrinsic argument " << (ai + 1) - << " must match LLVM metadata type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::Float: - if (!Ty->isFloatTy()) { - errors << "intrinsic argument " << (ai + 1) - << " must match LLVM float type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::Double: - if (!Ty->isDoubleTy()) { - errors << "intrinsic argument " << (ai + 1) - << " must match LLVM double type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::Integer: - if (!Ty->isIntegerTy(D.Integer_Width)) { - errors << "intrinsic argument " << (ai + 1) - << " must match LLVM i" << D.Integer_Width - << " type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::Vector: { - llvm::VectorType *VT = dyn_cast(Ty); - if (VT == nullptr) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM vector type, but got "; - Ty->print(errors); - } else if (VT->getElementCount() != D.Vector_Width) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM vector type with " - << D.Vector_Width - << " elements, but got "; - Ty->print(errors); - } - VerifyIntrinsicType(VT->getElementType(), Infos, errors, ai); - return; + + // Otherwise, if this is the first instance of an argument, record + // it and verify the "Any" kind. + assert(D.getArgumentNumber() == ArgTys.size() && + "Table consistency error"); + ArgTys.push_back(Ty); + + switch (D.getArgumentKind()) { + case IITDescriptor::AK_AnyInteger: + if (!Ty->isIntOrIntVectorTy()) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM integer type, but got "; + Ty->print(errors); } - case IITDescriptor::Pointer: { - llvm::PointerType *PT = dyn_cast(Ty); - if (PT == 0) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM pointer type, but got "; - Ty->print(errors); - } else if (PT->getAddressSpace() != D.Pointer_AddressSpace) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM pointer type with" - << D.Pointer_AddressSpace - << " address space, but got "; - Ty->print(errors); - } - VerifyIntrinsicType(PT->getElementType(), Infos, errors, ai); - return; + return; + case IITDescriptor::AK_AnyFloat: + if (!Ty->isFPOrFPVectorTy()) { + errors + << "intrinsic argument " << (ai + 1) + << " must be of an LLVM floating point type, but got "; + Ty->print(errors); } - - case IITDescriptor::Struct: { - llvm::StructType *ST = dyn_cast(Ty); - if (ST == 0) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM struct type, but got "; - Ty->print(errors); - } else if (ST->getNumElements() != D.Struct_NumElements) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM struct type with " - << D.Struct_NumElements - << " elements, but got "; - Ty->print(errors); - } - for (unsigned i = 0, e = D.Struct_NumElements; i != e; ++i) - VerifyIntrinsicType(ST->getElementType(i), Infos, errors, ai); - return; + return; + case IITDescriptor::AK_AnyVector: + if (!isa(Ty)) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM vector type, but got "; + Ty->print(errors); } + return; + case IITDescriptor::AK_AnyPointer: + if (!isa(Ty)) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM pointer type, but got "; + Ty->print(errors); + } + return; + default: + return; + } + llvm_unreachable("all argument kinds not covered"); - case IITDescriptor::Argument: - // Two cases here - If this is the second occurrence of an argument, verify - // that the later instance matches the previous instance. - if (D.getArgumentNumber() < ArgTys.size()) { - if (Ty != ArgTys[D.getArgumentNumber()]) { - errors << "intrinsic argument " << (ai + 1) - << " must match LLVM type of argument " - << D.getArgumentNumber() - << ", which is "; - ArgTys[D.getArgumentNumber()]->print(errors); - errors << ", but got "; - Ty->print(errors); - } - return; - } + case IITDescriptor::ExtendArgument: + // This may only be used when referring to a previous vector + // argument. + if (D.getArgumentNumber() >= ArgTys.size() || + !isa(ArgTys[D.getArgumentNumber()]) || + llvm::VectorType::getExtendedElementVectorType( + cast(ArgTys[D.getArgumentNumber()])) != + Ty) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM vector type, but got "; + Ty->print(errors); + } + return; - // Otherwise, if this is the first instance of an argument, record it and - // verify the "Any" kind. - assert(D.getArgumentNumber() == ArgTys.size() && "Table consistency error"); - ArgTys.push_back(Ty); - - switch (D.getArgumentKind()) { - case IITDescriptor::AK_AnyInteger: - if (!Ty->isIntOrIntVectorTy()) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM integer type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::AK_AnyFloat: - if (!Ty->isFPOrFPVectorTy()) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM floating point type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::AK_AnyVector: - if (!isa(Ty)) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM vector type, but got "; - Ty->print(errors); - } - return; - case IITDescriptor::AK_AnyPointer: - if (!isa(Ty)) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM pointer type, but got "; - Ty->print(errors); - } - return; - default: return; - } - llvm_unreachable("all argument kinds not covered"); - - case IITDescriptor::ExtendArgument: - // This may only be used when referring to a previous vector argument. - if (D.getArgumentNumber() >= ArgTys.size() || - !isa(ArgTys[D.getArgumentNumber()]) || - llvm::VectorType::getExtendedElementVectorType( - cast( - ArgTys[D.getArgumentNumber()])) != Ty) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM vector type, but got "; - Ty->print(errors); - } - return; - - case IITDescriptor::TruncArgument: - // This may only be used when referring to a previous vector argument. - if (D.getArgumentNumber() >= ArgTys.size() || - !isa(ArgTys[D.getArgumentNumber()]) || - llvm::VectorType::getTruncatedElementVectorType( - cast( - ArgTys[D.getArgumentNumber()])) != Ty) { - errors << "intrinsic argument " << (ai + 1) - << " must be of an LLVM vector type, but got "; - Ty->print(errors); - } - return; - default: return; + case IITDescriptor::TruncArgument: + // This may only be used when referring to a previous vector + // argument. + if (D.getArgumentNumber() >= ArgTys.size() || + !isa(ArgTys[D.getArgumentNumber()]) || + llvm::VectorType::getTruncatedElementVectorType( + cast(ArgTys[D.getArgumentNumber()])) != + Ty) { + errors << "intrinsic argument " << (ai + 1) + << " must be of an LLVM vector type, but got "; + Ty->print(errors); } - llvm_unreachable("unhandled"); + return; + default: + return; } + llvm_unreachable("unhandled"); + } - void run() { - using namespace llvm; + void run() { + using namespace llvm; - llvm::raw_string_ostream errors(outError); + llvm::raw_string_ostream errors(outError); - SmallVector Table; - getIntrinsicInfoTableEntries(ID, Table); - ArrayRef TableRef = Table; + SmallVector Table; + getIntrinsicInfoTableEntries(ID, Table); + ArrayRef TableRef = Table; - skipReturnType(TableRef); + skipReturnType(TableRef); - for (unsigned i = 0, e = inputTypes.size(); i != e; ++i) { - VerifyIntrinsicType(inputTypes[i], TableRef, errors, i); - } - if (!TableRef.empty()) { - errors << "intrinsic has too few arguments"; - } + for (unsigned i = 0, e = inputTypes.size(); i != e; ++i) { + VerifyIntrinsicType(inputTypes[i], TableRef, errors, i); + } + if (!TableRef.empty()) { + errors << "intrinsic has too few arguments"; } - - bool ok() const { return outError.empty(); } - }; - - static TypePtr intrinsicOutputType(llvm::Type *ty) { - if (llvm::IntegerType *intTy = llvm::dyn_cast(ty)) { - switch (intTy->getBitWidth()) { - case 8: - return uint8Type; - case 16: - return uint16Type; - case 32: - return uint32Type; - case 64: - return uint64Type; - case 128: - return uint128Type; - default: - return nullptr; - } - } else if (ty == llvm::Type::getFloatTy(ty->getContext())) - return float32Type; - else if (ty == llvm::Type::getDoubleTy(ty->getContext())) - return float64Type; - else if (auto *pointerTy = llvm::dyn_cast(ty)) { - TypePtr baseType = intrinsicOutputType(pointerTy->getPointerElementType()); - if (baseType != nullptr) - return pointerType(baseType); - else - return nullptr; - } else if (auto *vectorTy = llvm::dyn_cast(ty)) { - TypePtr baseType = intrinsicOutputType(vectorTy->getElementType()); - if (baseType != nullptr) - return vecType(baseType, vectorTy->getNumElements()); - else - return nullptr; - } else - return nullptr; } - static MultiPValuePtr intrinsicOutputTypes(llvm::Function *instance) { - MultiPValuePtr ret = new MultiPValue(); - llvm::Type *ty = instance->getFunctionType()->getReturnType(); - - if (ty->isVoidTy()) - return ret; - - TypePtr outType = intrinsicOutputType(ty); - if (outType == nullptr) { - std::string errorBuf; - llvm::raw_string_ostream errors(errorBuf); - errors << "intrinsic returning LLVM type "; - ty->print(errors); - errors << " not yet supported"; - error(errors.str()); + bool ok() const { return outError.empty(); } +}; + +static TypePtr intrinsicOutputType(llvm::Type *ty) { + if (llvm::IntegerType *intTy = llvm::dyn_cast(ty)) { + switch (intTy->getBitWidth()) { + case 8: + return uint8Type; + case 16: + return uint16Type; + case 32: + return uint32Type; + case 64: + return uint64Type; + case 128: + return uint128Type; + default: + return nullptr; } + } else if (ty == llvm::Type::getFloatTy(ty->getContext())) + return float32Type; + else if (ty == llvm::Type::getDoubleTy(ty->getContext())) + return float64Type; + else if (auto *pointerTy = llvm::dyn_cast(ty)) { + TypePtr baseType = + intrinsicOutputType(pointerTy->getPointerElementType()); + if (baseType != nullptr) + return pointerType(baseType); + else + return nullptr; + } else if (auto *vectorTy = llvm::dyn_cast(ty)) { + TypePtr baseType = intrinsicOutputType(vectorTy->getElementType()); + if (baseType != nullptr) + return vecType(baseType, vectorTy->getNumElements()); + else + return nullptr; + } else + return nullptr; +} - ret->add(PVData(outType, true)); - return ret; - } +static MultiPValuePtr intrinsicOutputTypes(llvm::Function *instance) { + MultiPValuePtr ret = new MultiPValue(); + llvm::Type *ty = instance->getFunctionType()->getReturnType(); - static MultiPValuePtr analyzeIntrinsic(IntrinsicSymbol *intrin, MultiPValue *args) { - vector argsKey; - args->toArgsKey(&argsKey); + if (ty->isVoidTy()) + return ret; - map, IntrinsicInstance>::const_iterator instancePair - = intrin->instances.find(argsKey); - if (instancePair != intrin->instances.end()) { - IntrinsicInstance const &instance = instancePair->second; - if (!instance.error.empty()) { - error(instance.error); - return nullptr; - } else { - assert(instance.function != nullptr); - return instance.outputTypes; - } - } else { - vector inputTypes; - for (vector::const_iterator i = argsKey.begin(), end = argsKey.end(); - i != end; - ++i) { - Type *type = i->ptr(); - if (type->typeKind == STATIC_TYPE) { - StaticType *staticType = (StaticType *) type; - if (staticType->obj->objKind != VALUE_HOLDER) - // XXX defer error for analyzeCallDefined - error("intrinsic static arguments must be boolean or integer statics"); - ValueHolder *vh = (ValueHolder *) staticType->obj.ptr(); - type = vh->type.ptr(); - } - inputTypes.push_back(llvmType(type)); - } - IntrinsicAnalyzer ia(intrin->id, inputTypes); - ia.run(); - IntrinsicInstance &instance = intrin->instances[argsKey]; - if (ia.outError.empty()) { - instance.function = llvm::Intrinsic::getOrInsertDeclaration(llvmModule, - intrin->id, - ia.ArgTys); - instance.outputTypes = intrinsicOutputTypes(instance.function); - return instance.outputTypes; - } else { - instance.function = nullptr; - instance.outputTypes = nullptr; - instance.error.swap(ia.outError); - error(instance.error); // XXX factor this out and use in analyzeCallDefined - return nullptr; - } - } + TypePtr outType = intrinsicOutputType(ty); + if (outType == nullptr) { + std::string errorBuf; + llvm::raw_string_ostream errors(errorBuf); + errors << "intrinsic returning LLVM type "; + ty->print(errors); + errors << " not yet supported"; + error(errors.str()); } - // - // analyzeCallExpr - // + ret->add(PVData(outType, true)); + return ret; +} - MultiPValuePtr analyzeCallExpr(ExprPtr callable, - ExprListPtr args, - EnvPtr env) { - PVData pv = analyzeOne(callable, env); - if (!pv.ok()) +static MultiPValuePtr analyzeIntrinsic(IntrinsicSymbol *intrin, + MultiPValue *args) { + vector argsKey; + args->toArgsKey(&argsKey); + + map, IntrinsicInstance>::const_iterator instancePair = + intrin->instances.find(argsKey); + if (instancePair != intrin->instances.end()) { + IntrinsicInstance const &instance = instancePair->second; + if (!instance.error.empty()) { + error(instance.error); return nullptr; - switch (pv.type->typeKind) { - case CODE_POINTER_TYPE: { - MultiPValuePtr mpv = analyzeMulti(args, env, 0); - if (!mpv) - return nullptr; - return analyzeCallPointer(pv, mpv); - } - default: - break; + } else { + assert(instance.function != nullptr); + return instance.outputTypes; } - ObjectPtr obj = unwrapStaticType(pv.type); - if (!obj) { - ExprListPtr args2 = new ExprList(callable); - args2->add(args); - return analyzeCallExpr(operator_expr_call(), args2, env); + } else { + vector inputTypes; + for (vector::const_iterator i = argsKey.begin(), + end = argsKey.end(); + i != end; ++i) { + Type *type = i->ptr(); + if (type->typeKind == STATIC_TYPE) { + StaticType *staticType = (StaticType *)type; + if (staticType->obj->objKind != VALUE_HOLDER) + // XXX defer error for analyzeCallDefined + error("intrinsic static arguments must be boolean or " + "integer statics"); + ValueHolder *vh = (ValueHolder *)staticType->obj.ptr(); + type = vh->type.ptr(); + } + inputTypes.push_back(llvmType(type)); } + IntrinsicAnalyzer ia(intrin->id, inputTypes); + ia.run(); + IntrinsicInstance &instance = intrin->instances[argsKey]; + if (ia.outError.empty()) { + instance.function = llvm::Intrinsic::getOrInsertDeclaration( + llvmModule, intrin->id, ia.ArgTys); + instance.outputTypes = intrinsicOutputTypes(instance.function); + return instance.outputTypes; + } else { + instance.function = nullptr; + instance.outputTypes = nullptr; + instance.error.swap(ia.outError); + error(instance.error); // XXX factor this out and use in + // analyzeCallDefined + return nullptr; + } + } +} - switch (obj->objKind) { - case TYPE: - case RECORD_DECL: - case VARIANT_DECL: - case PROCEDURE: - case GLOBAL_ALIAS: - case PRIM_OP: { - if ((obj->objKind == PRIM_OP) && !isOverloadablePrimOp(obj)) { - PrimOpPtr x = (PrimOp *) obj.ptr(); - MultiPValuePtr mpv = analyzeMulti(args, env, 0); - if (!mpv) - return nullptr; - return analyzePrimOp(x, mpv); - } - vector dispatchIndices; - MultiPValuePtr mpv = analyzeMultiArgs(args, env, dispatchIndices); - if (!mpv) - return nullptr; - if (dispatchIndices.size() > 0) { - return analyzeDispatch(obj, mpv, dispatchIndices); - } - CompileContextPusher pusher(obj, mpv->values); - InvokeEntry *entry = - analyzeCallable(obj, mpv->values); - if (entry->callByName) - return analyzeCallByName(entry, callable, args, env); - if (!entry->analyzed) - return nullptr; - return analyzeReturn(entry->returnIsRef, entry->returnTypes); - } - - case INTRINSIC: { - IntrinsicSymbol *intrin = (IntrinsicSymbol *) obj.ptr(); - MultiPValuePtr mpv = analyzeMulti(args, env, 0); - if (!mpv) - return nullptr; - return analyzeIntrinsic(intrin, mpv.ptr()); - } - - default: - error("invalid call expression"); +// +// analyzeCallExpr +// + +MultiPValuePtr analyzeCallExpr(ExprPtr callable, ExprListPtr args, EnvPtr env) { + PVData pv = analyzeOne(callable, env); + if (!pv.ok()) + return nullptr; + switch (pv.type->typeKind) { + case CODE_POINTER_TYPE: { + MultiPValuePtr mpv = analyzeMulti(args, env, 0); + if (!mpv) + return nullptr; + return analyzeCallPointer(pv, mpv); + } + default: + break; + } + ObjectPtr obj = unwrapStaticType(pv.type); + if (!obj) { + ExprListPtr args2 = new ExprList(callable); + args2->add(args); + return analyzeCallExpr(operator_expr_call(), args2, env); + } + + switch (obj->objKind) { + case TYPE: + case RECORD_DECL: + case VARIANT_DECL: + case PROCEDURE: + case GLOBAL_ALIAS: + case PRIM_OP: { + if ((obj->objKind == PRIM_OP) && !isOverloadablePrimOp(obj)) { + PrimOpPtr x = (PrimOp *)obj.ptr(); + MultiPValuePtr mpv = analyzeMulti(args, env, 0); + if (!mpv) return nullptr; + return analyzePrimOp(x, mpv); + } + vector dispatchIndices; + MultiPValuePtr mpv = analyzeMultiArgs(args, env, dispatchIndices); + if (!mpv) + return nullptr; + if (dispatchIndices.size() > 0) { + return analyzeDispatch(obj, mpv, dispatchIndices); } + CompileContextPusher pusher(obj, mpv->values); + InvokeEntry *entry = analyzeCallable(obj, mpv->values); + if (entry->callByName) + return analyzeCallByName(entry, callable, args, env); + if (!entry->analyzed) + return nullptr; + return analyzeReturn(entry->returnIsRef, entry->returnTypes); } - - // - // analyzeDispatch - // - - PVData analyzeDispatchIndex(PVData const &pv, unsigned tag) { - MultiPValuePtr args = new MultiPValue(); - args->add(pv); - ValueHolderPtr vh = intToValueHolder((int) tag); - args->add(staticPValue(vh.ptr())); - - MultiPValuePtr out = - analyzeCallValue(staticPValue(operator_dispatchIndex()), args); - ensureArity(out, 1); - return out->values[0]; - } - - MultiPValuePtr analyzeDispatch(ObjectPtr obj, - MultiPValuePtr args, - llvm::ArrayRef dispatchIndices) { - if (dispatchIndices.empty()) - return analyzeCallValue(staticPValue(obj), args); - - CompileContextPusher pusher(obj, args->values, dispatchIndices); - - unsigned index = dispatchIndices[0]; - vector dispatchIndices2(dispatchIndices.begin() + 1, - dispatchIndices.end()); - MultiPValuePtr prefix = new MultiPValue(); - for (unsigned i = 0; i < index; ++i) - prefix->add(args->values[i]); - MultiPValuePtr suffix = new MultiPValue(); - for (unsigned i = index + 1; i < args->size(); ++i) - suffix->add(args->values[i]); - PVData const &pvDispatch = args->values[index]; - unsigned memberCount = dispatchTagCount(pvDispatch.type); - - MultiPValuePtr result; - vector dispatchedTypes; - for (unsigned i = 0; i < memberCount; ++i) { - MultiPValuePtr args2 = new MultiPValue(); - args2->add(prefix); - PVData pvDispatch2 = analyzeDispatchIndex(pvDispatch, i); - args2->add(pvDispatch2); - args2->add(suffix); - MultiPValuePtr result2 = analyzeDispatch(obj, args2, dispatchIndices2); - if (!result2) - return nullptr; - if (!result) { - result = result2; + + case INTRINSIC: { + IntrinsicSymbol *intrin = (IntrinsicSymbol *)obj.ptr(); + MultiPValuePtr mpv = analyzeMulti(args, env, 0); + if (!mpv) + return nullptr; + return analyzeIntrinsic(intrin, mpv.ptr()); + } + + default: + error("invalid call expression"); + return nullptr; + } +} + +// +// analyzeDispatch +// + +PVData analyzeDispatchIndex(PVData const &pv, unsigned tag) { + MultiPValuePtr args = new MultiPValue(); + args->add(pv); + ValueHolderPtr vh = intToValueHolder((int)tag); + args->add(staticPValue(vh.ptr())); + + MultiPValuePtr out = + analyzeCallValue(staticPValue(operator_dispatchIndex()), args); + ensureArity(out, 1); + return out->values[0]; +} + +MultiPValuePtr analyzeDispatch(ObjectPtr obj, MultiPValuePtr args, + llvm::ArrayRef dispatchIndices) { + if (dispatchIndices.empty()) + return analyzeCallValue(staticPValue(obj), args); + + CompileContextPusher pusher(obj, args->values, dispatchIndices); + + unsigned index = dispatchIndices[0]; + vector dispatchIndices2(dispatchIndices.begin() + 1, + dispatchIndices.end()); + MultiPValuePtr prefix = new MultiPValue(); + for (unsigned i = 0; i < index; ++i) + prefix->add(args->values[i]); + MultiPValuePtr suffix = new MultiPValue(); + for (unsigned i = index + 1; i < args->size(); ++i) + suffix->add(args->values[i]); + PVData const &pvDispatch = args->values[index]; + unsigned memberCount = dispatchTagCount(pvDispatch.type); + + MultiPValuePtr result; + vector dispatchedTypes; + for (unsigned i = 0; i < memberCount; ++i) { + MultiPValuePtr args2 = new MultiPValue(); + args2->add(prefix); + PVData pvDispatch2 = analyzeDispatchIndex(pvDispatch, i); + args2->add(pvDispatch2); + args2->add(suffix); + MultiPValuePtr result2 = analyzeDispatch(obj, args2, dispatchIndices2); + if (!result2) + return nullptr; + if (!result) { + result = result2; + } else { + bool ok = true; + if (result->size() != result2->size()) { + ok = false; } else { - bool ok = true; - if (result->size() != result2->size()) { - ok = false; - } else { - for (unsigned j = 0; j < result2->size(); ++j) { - PVData const &pv = result->values[j]; - PVData const &pv2 = result2->values[j]; - if (pv.type != pv2.type) { - ok = false; - break; - } - if (pv.isRValue != pv2.isRValue) { - ok = false; - break; - } - } - } - if (!ok) { - string buf; - llvm::raw_string_ostream ostr(buf); - ostr << "mismatching result types with dispatch"; - ostr << "\n expected "; - unsigned j = 0; - for (; j < result->size(); ++j) { - if (j != 0) ostr << ", "; - ostr << result->values[j].type; - } - ostr << "\n from dispatching to "; - for (j = 0; j < dispatchedTypes.size(); ++j) { - if (j != 0) ostr << ", "; - ostr << dispatchedTypes[j]; + for (unsigned j = 0; j < result2->size(); ++j) { + PVData const &pv = result->values[j]; + PVData const &pv2 = result2->values[j]; + if (pv.type != pv2.type) { + ok = false; + break; } - ostr << "\n but got "; - for (j = 0; j < result->size(); ++j) { - if (j != 0) ostr << ", "; - ostr << result2->values[j].type; + if (pv.isRValue != pv2.isRValue) { + ok = false; + break; } - ostr << "\n when dispatching to " << pvDispatch2.type; - argumentError(index, ostr.str()); } } - dispatchedTypes.push_back(pvDispatch2.type); - } - assert(result.ptr()); - return result; - } - - // - // analyzeCallValue - // - - MultiPValuePtr analyzeCallValue(PVData const &callable, - MultiPValuePtr args) { - switch (callable.type->typeKind) { - case CODE_POINTER_TYPE: - return analyzeCallPointer(callable, args); - default: - break; - } - ObjectPtr obj = unwrapStaticType(callable.type); - if (!obj) { - MultiPValuePtr args2 = new MultiPValue(callable); - args2->add(args); - return analyzeCallValue(staticPValue(operator_call()), args2); - } - - switch (obj->objKind) { - case TYPE: - case RECORD_DECL: - case VARIANT_DECL: - case PROCEDURE: - case GLOBAL_ALIAS: - case PRIM_OP: { - if ((obj->objKind == PRIM_OP) && !isOverloadablePrimOp(obj)) { - PrimOpPtr x = (PrimOp *) obj.ptr(); - return analyzePrimOp(x, args); + if (!ok) { + string buf; + llvm::raw_string_ostream ostr(buf); + ostr << "mismatching result types with dispatch"; + ostr << "\n expected "; + unsigned j = 0; + for (; j < result->size(); ++j) { + if (j != 0) + ostr << ", "; + ostr << result->values[j].type; } - CompileContextPusher pusher(obj, args->values); - InvokeEntry *entry = - analyzeCallable(obj, args->values); - if (entry->callByName) { - ExprListPtr objectExprs = new ExprList(); - for (PVData const *i = args->values.begin(), *end = args->values.end(); - i < end; - ++i) { - objectExprs->add(new ObjectExpr(new PValue(*i))); - } - ExprPtr callableObject = new ObjectExpr(new PValue(callable)); - callableObject->location = topLocation(); - return analyzeCallByName(entry, callableObject, objectExprs, new Env()); - } else if (!entry->analyzed) - return nullptr; - else - return analyzeReturn(entry->returnIsRef, entry->returnTypes); + ostr << "\n from dispatching to "; + for (j = 0; j < dispatchedTypes.size(); ++j) { + if (j != 0) + ostr << ", "; + ostr << dispatchedTypes[j]; + } + ostr << "\n but got "; + for (j = 0; j < result->size(); ++j) { + if (j != 0) + ostr << ", "; + ostr << result2->values[j].type; + } + ostr << "\n when dispatching to " << pvDispatch2.type; + argumentError(index, ostr.str()); } + } + dispatchedTypes.push_back(pvDispatch2.type); + } + assert(result.ptr()); + return result; +} - case INTRINSIC: { - IntrinsicSymbol *intrin = (IntrinsicSymbol *) obj.ptr(); - return analyzeIntrinsic(intrin, args.ptr()); - } +// +// analyzeCallValue +// - default: - error("invalid call expression"); - return nullptr; +MultiPValuePtr analyzeCallValue(PVData const &callable, MultiPValuePtr args) { + switch (callable.type->typeKind) { + case CODE_POINTER_TYPE: + return analyzeCallPointer(callable, args); + default: + break; + } + ObjectPtr obj = unwrapStaticType(callable.type); + if (!obj) { + MultiPValuePtr args2 = new MultiPValue(callable); + args2->add(args); + return analyzeCallValue(staticPValue(operator_call()), args2); + } + + switch (obj->objKind) { + case TYPE: + case RECORD_DECL: + case VARIANT_DECL: + case PROCEDURE: + case GLOBAL_ALIAS: + case PRIM_OP: { + if ((obj->objKind == PRIM_OP) && !isOverloadablePrimOp(obj)) { + PrimOpPtr x = (PrimOp *)obj.ptr(); + return analyzePrimOp(x, args); } + CompileContextPusher pusher(obj, args->values); + InvokeEntry *entry = analyzeCallable(obj, args->values); + if (entry->callByName) { + ExprListPtr objectExprs = new ExprList(); + for (PVData const *i = args->values.begin(), + *end = args->values.end(); + i < end; ++i) { + objectExprs->add(new ObjectExpr(new PValue(*i))); + } + ExprPtr callableObject = new ObjectExpr(new PValue(callable)); + callableObject->location = topLocation(); + return analyzeCallByName(entry, callableObject, objectExprs, + new Env()); + } else if (!entry->analyzed) + return nullptr; + else + return analyzeReturn(entry->returnIsRef, entry->returnTypes); } - - // - // analyzeCallPointer - // - MultiPValuePtr analyzeCallPointer(PVData const &x, - MultiPValuePtr /*args*/) { - switch (x.type->typeKind) { - case CODE_POINTER_TYPE: { - CodePointerType *y = (CodePointerType *) x.type.ptr(); - return analyzeReturn(y->returnIsRef, y->returnTypes); - } + case INTRINSIC: { + IntrinsicSymbol *intrin = (IntrinsicSymbol *)obj.ptr(); + return analyzeIntrinsic(intrin, args.ptr()); + } - default: - assert(false); - return nullptr; - } + default: + error("invalid call expression"); + return nullptr; } +} - // - // analyzeIsDefined, analyzeCallable - // +// +// analyzeCallPointer +// - bool analyzeIsDefined(ObjectPtr x, - llvm::ArrayRef args) { - MatchFailureError failures; - InvokeEntry *entry = lookupInvokeEntry(x, args, failures); +MultiPValuePtr analyzeCallPointer(PVData const &x, MultiPValuePtr /*args*/) { + switch (x.type->typeKind) { + case CODE_POINTER_TYPE: { + CodePointerType *y = (CodePointerType *)x.type.ptr(); + return analyzeReturn(y->returnIsRef, y->returnTypes); + } - if (!entry || !entry->code->hasBody()) - return false; - return true; + default: + assert(false); + return nullptr; } +} - InvokeEntry *analyzeCallable(ObjectPtr x, - llvm::ArrayRef args) { - MatchFailureError failures; - InvokeEntry *entry = lookupInvokeEntry(x, args, failures); +// +// analyzeIsDefined, analyzeCallable +// - if (!entry || !entry->code->hasBody()) { - matchFailureError(failures); - } +bool analyzeIsDefined(ObjectPtr x, llvm::ArrayRef args) { + MatchFailureError failures; + InvokeEntry *entry = lookupInvokeEntry(x, args, failures); - if (entry->parent->shouldLog) - matchFailureLog(failures); + if (!entry || !entry->code->hasBody()) + return false; + return true; +} - if (entry->analyzed) - return entry; - if (entry->analyzing) { - updateAnalysisErrorLocation(); - return entry; - } - if (entry->callByName) { - entry->code = clone(entry->origCode); - return entry; - } +InvokeEntry *analyzeCallable(ObjectPtr x, llvm::ArrayRef args) { + MatchFailureError failures; + InvokeEntry *entry = lookupInvokeEntry(x, args, failures); + + if (!entry || !entry->code->hasBody()) { + matchFailureError(failures); + } - entry->analyzing = true; - analyzeCodeBody(entry); - entry->analyzing = false; + if (entry->parent->shouldLog) + matchFailureLog(failures); + if (entry->analyzed) + return entry; + if (entry->analyzing) { + updateAnalysisErrorLocation(); + return entry; + } + if (entry->callByName) { + entry->code = clone(entry->origCode); return entry; } - // - // analyzeCallByName - // - - MultiPValuePtr analyzeCallByName(InvokeEntry *entry, - ExprPtr callable, - ExprListPtr args, - EnvPtr env) { - assert(entry->callByName); + entry->analyzing = true; + analyzeCodeBody(entry); + entry->analyzing = false; - CodePtr code = entry->code; - assert(code->body.ptr()); + return entry; +} - if (code->hasReturnSpecs()) { - vector returnIsRef; - vector returnTypes; - evaluateReturnSpecs(code->returnSpecs, code->varReturnSpec, - entry->env, returnIsRef, returnTypes); - return analyzeReturn(returnIsRef, returnTypes); +// +// analyzeCallByName +// + +MultiPValuePtr analyzeCallByName(InvokeEntry *entry, ExprPtr callable, + ExprListPtr args, EnvPtr env) { + assert(entry->callByName); + + CodePtr code = entry->code; + assert(code->body.ptr()); + + if (code->hasReturnSpecs()) { + vector returnIsRef; + vector returnTypes; + evaluateReturnSpecs(code->returnSpecs, code->varReturnSpec, entry->env, + returnIsRef, returnTypes); + return analyzeReturn(returnIsRef, returnTypes); + } + + if (entry->varArgName.ptr()) + assert(args->size() >= entry->fixedArgNames.size()); + else + assert(args->size() == entry->fixedArgNames.size()); + + EnvPtr bodyEnv = new Env(entry->env); + bodyEnv->callByNameExprHead = callable; + unsigned i = 0; + for (; i < entry->varArgPosition; ++i) { + ExprPtr expr = foreignExpr(env, args->exprs[i]); + addLocal(bodyEnv, entry->fixedArgNames[i], expr.ptr()); + } + if (entry->varArgName.ptr()) { + unsigned j = 0; + const ExprListPtr varArgs = new ExprList(); + for (; j < args->size() - entry->fixedArgNames.size(); ++j) { + ExprPtr expr = foreignExpr(env, args->exprs[i + j]); + varArgs->add(expr); + } + addLocal(bodyEnv, entry->varArgName, varArgs.ptr()); + for (; i < entry->fixedArgNames.size(); ++i) { + ExprPtr expr = foreignExpr(env, args->exprs[i + j]); + addLocal(bodyEnv, entry->fixedArgNames[i], expr.ptr()); } + } - if (entry->varArgName.ptr()) - assert(args->size() >= entry->fixedArgNames.size()); - else - assert(args->size() == entry->fixedArgNames.size()); + AnalysisContext ctx; + StatementAnalysis sa = analyzeStatement(code->body, bodyEnv, &ctx); + if ((sa == SA_RECURSIVE) && (!ctx.returnInitialized)) + return nullptr; + if (ctx.returnInitialized) { + return analyzeReturn(ctx.returnIsRef, ctx.returnTypes); + } else if ((sa == SA_TERMINATED) && ctx.hasRecursivePropagation) { + analysisError(); + return nullptr; + } else { + // assume void return (zero return values) + return new MultiPValue(); + } +} - EnvPtr bodyEnv = new Env(entry->env); - bodyEnv->callByNameExprHead = callable; - unsigned i = 0; - for (; i < entry->varArgPosition; ++i) { - ExprPtr expr = foreignExpr(env, args->exprs[i]); - addLocal(bodyEnv, entry->fixedArgNames[i], expr.ptr()); +// +// analyzeCodeBody +// + +static void unifyInterfaceReturns(InvokeEntry *entry) { + if (entry->parent->callable->objKind == TYPE) { + string buf; + llvm::raw_string_ostream out(buf); + if (entry->returnTypes.size() != 1) { + out << "constructor overload for type " << entry->parent->callable + << " must return a single value of that type"; + error(entry->code, out.str()); } - if (entry->varArgName.ptr()) { - unsigned j = 0; - const ExprListPtr varArgs = new ExprList(); - for (; j < args->size() - entry->fixedArgNames.size(); ++j) { - ExprPtr expr = foreignExpr(env, args->exprs[i + j]); - varArgs->add(expr); - } - addLocal(bodyEnv, entry->varArgName, varArgs.ptr()); - for (; i < entry->fixedArgNames.size(); ++i) { - ExprPtr expr = foreignExpr(env, args->exprs[i + j]); - addLocal(bodyEnv, entry->fixedArgNames[i], expr.ptr()); - } + if (entry->returnIsRef[0]) { + out << "constructor overload for type " << entry->parent->callable + << " must return by value"; + error(entry->code, out.str()); } - - AnalysisContext ctx; - StatementAnalysis sa = analyzeStatement(code->body, bodyEnv, &ctx); - if ((sa == SA_RECURSIVE) && (!ctx.returnInitialized)) - return nullptr; - if (ctx.returnInitialized) { - return analyzeReturn(ctx.returnIsRef, ctx.returnTypes); - } else if ((sa == SA_TERMINATED) && ctx.hasRecursivePropagation) { - analysisError(); - return nullptr; - } else { - // assume void return (zero return values) - return new MultiPValue(); + if (entry->returnTypes[0].ptr() != entry->parent->callable.ptr()) { + out << "constructor overload for type " << entry->parent->callable + << " returns type " << entry->returnTypes[0]; + error(entry->code, out.str()); } + return; } - // - // analyzeCodeBody - // + if (entry->parent->interface == nullptr) + return; + + CodePtr interfaceCode = entry->parent->interface->code; + if (!interfaceCode->returnSpecsDeclared) + return; - static void unifyInterfaceReturns(InvokeEntry *entry) { - if (entry->parent->callable->objKind == TYPE) { + vector interfaceReturnIsRef; + vector interfaceReturnTypes; + + evaluateReturnSpecs(interfaceCode->returnSpecs, + interfaceCode->varReturnSpec, entry->interfaceEnv, + interfaceReturnIsRef, interfaceReturnTypes); + if (entry->returnTypes.size() != interfaceReturnTypes.size()) { + string buf; + llvm::raw_string_ostream out(buf); + out << "interface declares " << interfaceReturnTypes.size() + << " arguments, but got " << entry->returnTypes.size() << "\n" + << " interface at "; + printFileLineCol(out, entry->parent->interface->location); + error(entry->code, out.str()); + } + for (size_t i = 0; i < interfaceReturnTypes.size(); ++i) { + if (interfaceReturnTypes[i] != entry->returnTypes[i]) { string buf; llvm::raw_string_ostream out(buf); - if (entry->returnTypes.size() != 1) { - out << "constructor overload for type " << entry->parent->callable - << " must return a single value of that type"; - error(entry->code, out.str()); - } - if (entry->returnIsRef[0]) { - out << "constructor overload for type " << entry->parent->callable - << " must return by value"; - error(entry->code, out.str()); - } - if (entry->returnTypes[0].ptr() != entry->parent->callable.ptr()) { - out << "constructor overload for type " << entry->parent->callable - << " returns type " << entry->returnTypes[0]; - error(entry->code, out.str()); - } - return; + out << "return value " << i + 1 << ": " + << "interface declares return type " << interfaceReturnTypes[i] + << ", but overload returns type " << entry->returnTypes[i] + << "\n" + << " interface at "; + printFileLineCol(out, entry->parent->interface->location); + error(entry->code, out.str()); } - - if (entry->parent->interface == nullptr) - return; - - CodePtr interfaceCode = entry->parent->interface->code; - if (!interfaceCode->returnSpecsDeclared) - return; - - vector interfaceReturnIsRef; - vector interfaceReturnTypes; - - evaluateReturnSpecs(interfaceCode->returnSpecs, - interfaceCode->varReturnSpec, - entry->interfaceEnv, - interfaceReturnIsRef, interfaceReturnTypes); - if (entry->returnTypes.size() != interfaceReturnTypes.size()) { + if (interfaceReturnIsRef[i] && !entry->returnIsRef[i]) { string buf; llvm::raw_string_ostream out(buf); - out << "interface declares " << interfaceReturnTypes.size() - << " arguments, but got " << entry->returnTypes.size() << "\n" - << " interface at "; + out << "return value " << i + 1 << ": " + << "interface declares return by reference, but overload " + "returns by value\n" + << " interface at "; printFileLineCol(out, entry->parent->interface->location); error(entry->code, out.str()); } - for (size_t i = 0; i < interfaceReturnTypes.size(); ++i) { - if (interfaceReturnTypes[i] != entry->returnTypes[i]) { - string buf; - llvm::raw_string_ostream out(buf); - out << "return value " << i + 1 << ": " - << "interface declares return type " << interfaceReturnTypes[i] - << ", but overload returns type " << entry->returnTypes[i] << "\n" - << " interface at "; - printFileLineCol(out, entry->parent->interface->location); - error(entry->code, out.str()); - } - if (interfaceReturnIsRef[i] && !entry->returnIsRef[i]) { - string buf; - llvm::raw_string_ostream out(buf); - out << "return value " << i + 1 << ": " - << "interface declares return by reference, but overload returns by value\n" - << " interface at "; - printFileLineCol(out, entry->parent->interface->location); - error(entry->code, out.str()); - } - } } +} - void analyzeCodeBody(InvokeEntry *entry) { - assert(!entry->analyzed); +void analyzeCodeBody(InvokeEntry *entry) { + assert(!entry->analyzed); - CodePtr code = entry->code; - assert(code->hasBody()); + CodePtr code = entry->code; + assert(code->hasBody()); - if (code->isLLVMBody() || code->hasReturnSpecs()) { - evaluateReturnSpecs(code->returnSpecs, code->varReturnSpec, - entry->env, - entry->returnIsRef, entry->returnTypes); - entry->analyzed = true; - return; - } + if (code->isLLVMBody() || code->hasReturnSpecs()) { + evaluateReturnSpecs(code->returnSpecs, code->varReturnSpec, entry->env, + entry->returnIsRef, entry->returnTypes); + entry->analyzed = true; + return; + } - EnvPtr bodyEnv = new Env(entry->env); + EnvPtr bodyEnv = new Env(entry->env); - size_t i = 0; - for (; i < entry->varArgPosition; ++i) { - bool flag = entry->forwardedRValueFlags[i]; - addLocal(bodyEnv, entry->fixedArgNames[i], new PValue(entry->fixedArgTypes[i], flag)); + size_t i = 0; + for (; i < entry->varArgPosition; ++i) { + bool flag = entry->forwardedRValueFlags[i]; + addLocal(bodyEnv, entry->fixedArgNames[i], + new PValue(entry->fixedArgTypes[i], flag)); + } + if (entry->varArgName.ptr()) { + MultiPValuePtr varArgs = new MultiPValue(); + size_t j = 0; + for (; j < entry->varArgTypes.size(); ++j) { + bool flag = entry->forwardedRValueFlags[i + j]; + PVData parg(entry->varArgTypes[j], flag); + varArgs->values.push_back(parg); } - if (entry->varArgName.ptr()) { - MultiPValuePtr varArgs = new MultiPValue(); - size_t j = 0; - for (; j < entry->varArgTypes.size(); ++j) { - bool flag = entry->forwardedRValueFlags[i + j]; - PVData parg(entry->varArgTypes[j], flag); - varArgs->values.push_back(parg); - } - addLocal(bodyEnv, entry->varArgName, varArgs.ptr()); - for (; i < entry->fixedArgNames.size(); ++i) { - bool flag = entry->forwardedRValueFlags[i + j]; - addLocal(bodyEnv, entry->fixedArgNames[i], new PValue(entry->fixedArgTypes[i], flag)); - } + addLocal(bodyEnv, entry->varArgName, varArgs.ptr()); + for (; i < entry->fixedArgNames.size(); ++i) { + bool flag = entry->forwardedRValueFlags[i + j]; + addLocal(bodyEnv, entry->fixedArgNames[i], + new PValue(entry->fixedArgTypes[i], flag)); } + } - AnalysisContext ctx; - StatementAnalysis sa = analyzeStatement(code->body, bodyEnv, &ctx); - if ((sa == SA_RECURSIVE) && (!ctx.returnInitialized)) - return; - if (ctx.returnInitialized) { - entry->returnIsRef = ctx.returnIsRef; - entry->returnTypes = ctx.returnTypes; - } else if ((sa == SA_TERMINATED) && ctx.hasRecursivePropagation) { - analysisError(); - } + AnalysisContext ctx; + StatementAnalysis sa = analyzeStatement(code->body, bodyEnv, &ctx); + if ((sa == SA_RECURSIVE) && (!ctx.returnInitialized)) + return; + if (ctx.returnInitialized) { + entry->returnIsRef = ctx.returnIsRef; + entry->returnTypes = ctx.returnTypes; + } else if ((sa == SA_TERMINATED) && ctx.hasRecursivePropagation) { + analysisError(); + } - unifyInterfaceReturns(entry); + unifyInterfaceReturns(entry); - entry->analyzed = true; - } + entry->analyzed = true; +} - // - // analyzeStatement - // +// +// analyzeStatement +// + +static StatementAnalysis combineStatementAnalysis(StatementAnalysis a, + StatementAnalysis b) { + if ((a == SA_FALLTHROUGH) || (b == SA_FALLTHROUGH)) + return SA_FALLTHROUGH; + if ((a == SA_RECURSIVE) && (b == SA_RECURSIVE)) + return SA_RECURSIVE; + if ((a == SA_TERMINATED) && (b == SA_TERMINATED)) + return SA_TERMINATED; + if ((a == SA_RECURSIVE) && (b == SA_TERMINATED)) + return SA_TERMINATED; + assert((a == SA_TERMINATED) && (b == SA_RECURSIVE)); + return SA_TERMINATED; +} - static StatementAnalysis combineStatementAnalysis(StatementAnalysis a, - StatementAnalysis b) { - if ((a == SA_FALLTHROUGH) || (b == SA_FALLTHROUGH)) - return SA_FALLTHROUGH; - if ((a == SA_RECURSIVE) && (b == SA_RECURSIVE)) +static StatementAnalysis analyzeBlockStatement(const StatementPtr &stmt, + EnvPtr &env, + AnalysisContext *ctx) { + if (stmt->stmtKind == BINDING) { + env = analyzeBinding(static_cast(stmt.ptr()), env); + if (!env) { + ctx->hasRecursivePropagation = true; return SA_RECURSIVE; - if ((a == SA_TERMINATED) && (b == SA_TERMINATED)) - return SA_TERMINATED; - if ((a == SA_RECURSIVE) && (b == SA_TERMINATED)) - return SA_TERMINATED; - assert((a == SA_TERMINATED) && (b == SA_RECURSIVE)); - return SA_TERMINATED; - } + } + return SA_FALLTHROUGH; + } else if (stmt->stmtKind == EVAL_STATEMENT) { + EvalStatement *eval = (EvalStatement *)stmt.ptr(); + llvm::ArrayRef evaled = desugarEvalStatement(eval, env); + for (size_t i = 0; i < evaled.size(); ++i) { + StatementAnalysis sa = analyzeBlockStatement(evaled[i], env, ctx); + if (sa != SA_FALLTHROUGH) + return sa; + } + return SA_FALLTHROUGH; + } else + return analyzeStatement(stmt, env, ctx); +} - static StatementAnalysis analyzeBlockStatement(const StatementPtr &stmt, EnvPtr &env, AnalysisContext *ctx) { - if (stmt->stmtKind == BINDING) { - env = analyzeBinding(static_cast(stmt.ptr()), env); - if (!env) { - ctx->hasRecursivePropagation = true; - return SA_RECURSIVE; - } - return SA_FALLTHROUGH; - } else if (stmt->stmtKind == EVAL_STATEMENT) { - EvalStatement *eval = (EvalStatement *) stmt.ptr(); - llvm::ArrayRef evaled = desugarEvalStatement(eval, env); - for (size_t i = 0; i < evaled.size(); ++i) { - StatementAnalysis sa = analyzeBlockStatement(evaled[i], env, ctx); - if (sa != SA_FALLTHROUGH) - return sa; - } - return SA_FALLTHROUGH; - } else - return analyzeStatement(stmt, env, ctx); - } - - static EnvPtr analyzeStatementExpressionStatements(llvm::ArrayRef stmts, EnvPtr env) { - EnvPtr env2 = env; - for (StatementPtr const *i = stmts.begin(), *end = stmts.end(); - i != end; - ++i) { - switch ((*i)->stmtKind) { - case BINDING: - env2 = analyzeBinding(static_cast(i->ptr()), env2); - if (env2 == nullptr) - return nullptr; - break; - - case ASSIGNMENT: - case VARIADIC_ASSIGNMENT: - case INIT_ASSIGNMENT: - case EXPR_STATEMENT: - break; - - default: - assert(false); - return nullptr; - } +static EnvPtr +analyzeStatementExpressionStatements(llvm::ArrayRef stmts, + EnvPtr env) { + EnvPtr env2 = env; + for (StatementPtr const *i = stmts.begin(), *end = stmts.end(); i != end; + ++i) { + switch ((*i)->stmtKind) { + case BINDING: + env2 = analyzeBinding(static_cast(i->ptr()), env2); + if (env2 == nullptr) + return nullptr; + break; + + case ASSIGNMENT: + case VARIADIC_ASSIGNMENT: + case INIT_ASSIGNMENT: + case EXPR_STATEMENT: + break; + + default: + assert(false); + return nullptr; } - return env2; } + return env2; +} - static StatementAnalysis analyzeStatement(StatementPtr stmt, EnvPtr env, AnalysisContext *ctx) { - LocationContext loc(stmt->location); - - switch (stmt->stmtKind) { - case BLOCK: { - Block *block = (Block *) stmt.ptr(); - for (size_t i = 0; i < block->statements.size(); ++i) { - StatementAnalysis sa = analyzeBlockStatement(block->statements[i], env, ctx); - if (sa != SA_FALLTHROUGH) - return sa; - } - return SA_FALLTHROUGH; - } +static StatementAnalysis analyzeStatement(StatementPtr stmt, EnvPtr env, + AnalysisContext *ctx) { + LocationContext loc(stmt->location); + + switch (stmt->stmtKind) { + case BLOCK: { + Block *block = (Block *)stmt.ptr(); + for (size_t i = 0; i < block->statements.size(); ++i) { + StatementAnalysis sa = + analyzeBlockStatement(block->statements[i], env, ctx); + if (sa != SA_FALLTHROUGH) + return sa; + } + return SA_FALLTHROUGH; + } - case LABEL: - case BINDING: - case ASSIGNMENT: - case INIT_ASSIGNMENT: - case VARIADIC_ASSIGNMENT: - return SA_FALLTHROUGH; + case LABEL: + case BINDING: + case ASSIGNMENT: + case INIT_ASSIGNMENT: + case VARIADIC_ASSIGNMENT: + return SA_FALLTHROUGH; - case GOTO: - return SA_TERMINATED; + case GOTO: + return SA_TERMINATED; - case RETURN: { - Return *x = (Return *) stmt.ptr(); - unsigned wantCount = x->isReturnSpecs ? 1 : 0; - MultiPValuePtr mpv = analyzeMulti(x->values, env, wantCount); + case RETURN: { + Return *x = (Return *)stmt.ptr(); + unsigned wantCount = x->isReturnSpecs ? 1 : 0; + MultiPValuePtr mpv = analyzeMulti(x->values, env, wantCount); - if (!mpv) { - ctx->hasRecursivePropagation = true; - return SA_RECURSIVE; - } - if (ctx->returnInitialized) { - ensureArity(mpv, ctx->returnTypes.size()); - for (unsigned i = 0; i < mpv->size(); ++i) { - PVData const &pv = mpv->values[i]; - bool byRef = returnKindToByRef(x->returnKind, pv); - if (ctx->returnTypes[i] != pv.type) - argumentTypeError(i, ctx->returnTypes[i], pv.type); - if (byRef != ctx->returnIsRef[i]) - argumentError(i, "mismatching by-ref and " - "by-value returns"); - if (byRef && pv.isRValue) - argumentError(i, "cannot return a temporary by reference"); - } - } else { - ctx->returnIsRef.clear(); - ctx->returnTypes.clear(); - for (unsigned i = 0; i < mpv->size(); ++i) { - PVData const &pv = mpv->values[i]; - bool byRef = returnKindToByRef(x->returnKind, pv); - ctx->returnIsRef.push_back(byRef); - if (byRef && pv.isRValue) - argumentError(i, "cannot return a temporary by reference"); - ctx->returnTypes.push_back(pv.type); - } - ctx->returnInitialized = true; - } - return SA_TERMINATED; + if (!mpv) { + ctx->hasRecursivePropagation = true; + return SA_RECURSIVE; + } + if (ctx->returnInitialized) { + ensureArity(mpv, ctx->returnTypes.size()); + for (unsigned i = 0; i < mpv->size(); ++i) { + PVData const &pv = mpv->values[i]; + bool byRef = returnKindToByRef(x->returnKind, pv); + if (ctx->returnTypes[i] != pv.type) + argumentTypeError(i, ctx->returnTypes[i], pv.type); + if (byRef != ctx->returnIsRef[i]) + argumentError(i, "mismatching by-ref and " + "by-value returns"); + if (byRef && pv.isRValue) + argumentError(i, "cannot return a temporary by reference"); } + } else { + ctx->returnIsRef.clear(); + ctx->returnTypes.clear(); + for (unsigned i = 0; i < mpv->size(); ++i) { + PVData const &pv = mpv->values[i]; + bool byRef = returnKindToByRef(x->returnKind, pv); + ctx->returnIsRef.push_back(byRef); + if (byRef && pv.isRValue) + argumentError(i, "cannot return a temporary by reference"); + ctx->returnTypes.push_back(pv.type); + } + ctx->returnInitialized = true; + } + return SA_TERMINATED; + } - case IF: { - auto x = static_cast(stmt.ptr()); + case IF: { + auto x = static_cast(stmt.ptr()); - EnvPtr env2 = analyzeStatementExpressionStatements(x->conditionStatements, env); - if (env2 == nullptr) { - ctx->hasRecursivePropagation = true; - return SA_RECURSIVE; - } + EnvPtr env2 = + analyzeStatementExpressionStatements(x->conditionStatements, env); + if (env2 == nullptr) { + ctx->hasRecursivePropagation = true; + return SA_RECURSIVE; + } - MultiPValuePtr cond = analyzeExpr(x->condition, env2); + MultiPValuePtr cond = analyzeExpr(x->condition, env2); - if (cond->values.size() != 1) { - arityError(1, cond->values.size()); - } + if (cond->values.size() != 1) { + arityError(1, cond->values.size()); + } - PVData &condPvData = cond->values[0]; + PVData &condPvData = cond->values[0]; - BoolKind condKind = typeBoolKind(condPvData.type); + BoolKind condKind = typeBoolKind(condPvData.type); - StatementAnalysis thenResult = SA_FALLTHROUGH; - StatementAnalysis elseResult = SA_FALLTHROUGH; - if (condKind == BOOL_EXPR || condKind == BOOL_STATIC_TRUE) - thenResult = analyzeStatement(x->thenPart, env2, ctx); - if ((condKind == BOOL_EXPR || condKind == BOOL_STATIC_FALSE) && x->elsePart.ptr()) - elseResult = analyzeStatement(x->elsePart, env2, ctx); - return combineStatementAnalysis(thenResult, elseResult); - } + StatementAnalysis thenResult = SA_FALLTHROUGH; + StatementAnalysis elseResult = SA_FALLTHROUGH; + if (condKind == BOOL_EXPR || condKind == BOOL_STATIC_TRUE) + thenResult = analyzeStatement(x->thenPart, env2, ctx); + if ((condKind == BOOL_EXPR || condKind == BOOL_STATIC_FALSE) && + x->elsePart.ptr()) + elseResult = analyzeStatement(x->elsePart, env2, ctx); + return combineStatementAnalysis(thenResult, elseResult); + } - case SWITCH: { - auto *x = static_cast(stmt.ptr()); - if (!x->desugared) - x->desugared = desugarSwitchStatement(x); - return analyzeStatement(x->desugared, env, ctx); - } + case SWITCH: { + auto *x = static_cast(stmt.ptr()); + if (!x->desugared) + x->desugared = desugarSwitchStatement(x); + return analyzeStatement(x->desugared, env, ctx); + } - case EVAL_STATEMENT: { - EvalStatement *eval = (EvalStatement *) stmt.ptr(); - llvm::ArrayRef evaled = desugarEvalStatement(eval, env); - for (size_t i = 0; i < evaled.size(); ++i) { - StatementAnalysis sa = analyzeStatement(evaled[i], env, ctx); - if (sa != SA_FALLTHROUGH) - return sa; - } - return SA_FALLTHROUGH; - } + case EVAL_STATEMENT: { + EvalStatement *eval = (EvalStatement *)stmt.ptr(); + llvm::ArrayRef evaled = desugarEvalStatement(eval, env); + for (size_t i = 0; i < evaled.size(); ++i) { + StatementAnalysis sa = analyzeStatement(evaled[i], env, ctx); + if (sa != SA_FALLTHROUGH) + return sa; + } + return SA_FALLTHROUGH; + } - case EXPR_STATEMENT: - return SA_FALLTHROUGH; + case EXPR_STATEMENT: + return SA_FALLTHROUGH; - case WHILE: { - While *x = (While *) stmt.ptr(); + case WHILE: { + While *x = (While *)stmt.ptr(); - EnvPtr env2 = analyzeStatementExpressionStatements(x->conditionStatements, env); - if (env2 == nullptr) { - ctx->hasRecursivePropagation = true; - return SA_RECURSIVE; - } + EnvPtr env2 = + analyzeStatementExpressionStatements(x->conditionStatements, env); + if (env2 == nullptr) { + ctx->hasRecursivePropagation = true; + return SA_RECURSIVE; + } - analyzeStatement(x->body, env2, ctx); - return SA_FALLTHROUGH; - } + analyzeStatement(x->body, env2, ctx); + return SA_FALLTHROUGH; + } - case BREAK: - case CONTINUE: - return SA_TERMINATED; + case BREAK: + case CONTINUE: + return SA_TERMINATED; - case FOR: { - For *x = (For *) stmt.ptr(); - if (!x->desugared) - x->desugared = desugarForStatement(x); - return analyzeStatement(x->desugared, env, ctx); - } + case FOR: { + For *x = (For *)stmt.ptr(); + if (!x->desugared) + x->desugared = desugarForStatement(x); + return analyzeStatement(x->desugared, env, ctx); + } - case FOREIGN_STATEMENT: { - ForeignStatement *x = (ForeignStatement *) stmt.ptr(); - return analyzeStatement(x->statement, x->getEnv(), ctx); - } + case FOREIGN_STATEMENT: { + ForeignStatement *x = (ForeignStatement *)stmt.ptr(); + return analyzeStatement(x->statement, x->getEnv(), ctx); + } - case TRY: { - Try *x = (Try *) stmt.ptr(); - if (!exceptionsEnabled()) - return analyzeStatement(x->tryBlock, env, ctx); - if (!x->desugaredCatchBlock) - x->desugaredCatchBlock = desugarCatchBlocks(x->catchBlocks); - StatementAnalysis result1, result2; - result1 = analyzeStatement(x->tryBlock, env, ctx); + case TRY: { + Try *x = (Try *)stmt.ptr(); + if (!exceptionsEnabled()) + return analyzeStatement(x->tryBlock, env, ctx); + if (!x->desugaredCatchBlock) + x->desugaredCatchBlock = desugarCatchBlocks(x->catchBlocks); + StatementAnalysis result1, result2; + result1 = analyzeStatement(x->tryBlock, env, ctx); - EnvPtr catchEnv = new Env(env, true); + EnvPtr catchEnv = new Env(env, true); - result2 = analyzeStatement(x->desugaredCatchBlock, catchEnv, ctx); - return combineStatementAnalysis(result1, result2); - } + result2 = analyzeStatement(x->desugaredCatchBlock, catchEnv, ctx); + return combineStatementAnalysis(result1, result2); + } - case THROW: - return SA_TERMINATED; + case THROW: + return SA_TERMINATED; - case STATIC_FOR: { - StaticFor *x = (StaticFor *) stmt.ptr(); - MultiPValuePtr mpv = analyzeMulti(x->values, env, 2); - if (!mpv) { - ctx->hasRecursivePropagation = true; - return SA_RECURSIVE; - } - initializeStaticForClones(x, mpv->size()); - for (unsigned i = 0; i < mpv->size(); ++i) { - EnvPtr env2 = new Env(env); - addLocal(env2, x->variable, new PValue(mpv->values[i])); - StatementAnalysis sa = analyzeStatement(x->clonedBodies[i], env2, ctx); - if (sa != SA_FALLTHROUGH) - return sa; - } - return SA_FALLTHROUGH; - } + case STATIC_FOR: { + StaticFor *x = (StaticFor *)stmt.ptr(); + MultiPValuePtr mpv = analyzeMulti(x->values, env, 2); + if (!mpv) { + ctx->hasRecursivePropagation = true; + return SA_RECURSIVE; + } + initializeStaticForClones(x, mpv->size()); + for (unsigned i = 0; i < mpv->size(); ++i) { + EnvPtr env2 = new Env(env); + addLocal(env2, x->variable, new PValue(mpv->values[i])); + StatementAnalysis sa = + analyzeStatement(x->clonedBodies[i], env2, ctx); + if (sa != SA_FALLTHROUGH) + return sa; + } + return SA_FALLTHROUGH; + } - case FINALLY: - case ONERROR: - return SA_FALLTHROUGH; + case FINALLY: + case ONERROR: + return SA_FALLTHROUGH; - case UNREACHABLE: - return SA_TERMINATED; + case UNREACHABLE: + return SA_TERMINATED; - case STATIC_ASSERT_STATEMENT: - return SA_FALLTHROUGH; + case STATIC_ASSERT_STATEMENT: + return SA_FALLTHROUGH; - default: - assert(false); - return SA_FALLTHROUGH; - } + default: + assert(false); + return SA_FALLTHROUGH; } +} - void initializeStaticForClones(StaticForPtr x, size_t count) { - if (x->clonesInitialized) { - assert(count == x->clonedBodies.size()); - } else { - if (analysisCachingDisabled == 0) - x->clonesInitialized = true; - x->clonedBodies.clear(); - for (unsigned i = 0; i < count; ++i) - x->clonedBodies.push_back(clone(x->body)); - } +void initializeStaticForClones(StaticForPtr x, size_t count) { + if (x->clonesInitialized) { + assert(count == x->clonedBodies.size()); + } else { + if (analysisCachingDisabled == 0) + x->clonesInitialized = true; + x->clonedBodies.clear(); + for (unsigned i = 0; i < count; ++i) + x->clonedBodies.push_back(clone(x->body)); } +} - static EnvPtr analyzeBinding(BindingPtr x, EnvPtr env) { - LocationContext loc(x->location); - - switch (x->bindingKind) { - case VAR: - case REF: - case FORWARD: { - MultiPValuePtr mpv = analyzeMulti(x->values, env, x->args.size()); - if (!mpv) - return nullptr; - - if (x->hasVarArg) { - if (mpv->values.size() < x->args.size() - 1) - arityMismatchError(x->args.size() - 1, mpv->values.size(), /*hasVarArg=*/ true); - } else if (mpv->values.size() != x->args.size()) - arityMismatchError(x->args.size(), mpv->values.size(), /*hasVarArg=*/ false); +static EnvPtr analyzeBinding(BindingPtr x, EnvPtr env) { + LocationContext loc(x->location); - vector key; - for (unsigned i = 0; i < mpv->size(); ++i) { - PVData const &pv = mpv->values[i]; - key.push_back(pv.type); - } + switch (x->bindingKind) { + case VAR: + case REF: + case FORWARD: { + MultiPValuePtr mpv = analyzeMulti(x->values, env, x->args.size()); + if (!mpv) + return nullptr; - llvm::ArrayRef pvars = x->patternVars; - EnvPtr patternEnv = new Env(env); - vector cells; - vector multiCells; - initializePatternEnv(patternEnv, pvars, cells, multiCells); - - llvm::ArrayRef formalArgs = x->args; - size_t varArgSize = key.size() - formalArgs.size() + 1; - for (size_t i = 0, j = 0; i < formalArgs.size(); ++i) { - FormalArgPtr y = formalArgs[i]; - if (y->varArg) { - if (y->type.ptr()) { - ExprPtr unpack = new Unpack(y->type.ptr()); - unpack->location = y->type->location; - MultiStaticPtr types = new MultiStatic(); - for (; j < varArgSize; ++j) { - types->add(key[i + j].ptr()); - } - --j; - if (!unifyMulti(evaluateMultiPattern(new ExprList(unpack), patternEnv), types)) - matchBindingError(new MatchMultiBindingError(unsigned(formalArgs.size()), types, y)); - } else { - j = varArgSize - 1; - } - } else { - if (y->type.ptr()) { - if (!unifyPatternObj(evaluateOnePattern(y->type, patternEnv), key[i + j].ptr())) - matchBindingError(new MatchBindingError(unsigned(i + j), key[i + j], y)); - } - } - } + if (x->hasVarArg) { + if (mpv->values.size() < x->args.size() - 1) + arityMismatchError(x->args.size() - 1, mpv->values.size(), + /*hasVarArg=*/true); + } else if (mpv->values.size() != x->args.size()) + arityMismatchError(x->args.size(), mpv->values.size(), + /*hasVarArg=*/false); + + vector key; + for (unsigned i = 0; i < mpv->size(); ++i) { + PVData const &pv = mpv->values[i]; + key.push_back(pv.type); + } - EnvPtr staticEnv = new Env(env); - for (size_t i = 0; i < pvars.size(); ++i) { - if (pvars[i].isMulti) { - MultiStaticPtr ms = derefDeep(multiCells[i].ptr()); - if (!ms) - error(pvars[i].name, "unbound pattern variable"); - addLocal(staticEnv, pvars[i].name, ms.ptr()); - x->patternTypes.push_back(ms.ptr()); - } else { - ObjectPtr v = derefDeep(cells[i].ptr()); - if (!v) - error(pvars[i].name, "unbound pattern variable"); - addLocal(staticEnv, pvars[i].name, v.ptr()); - x->patternTypes.push_back(v.ptr()); + llvm::ArrayRef pvars = x->patternVars; + EnvPtr patternEnv = new Env(env); + vector cells; + vector multiCells; + initializePatternEnv(patternEnv, pvars, cells, multiCells); + + llvm::ArrayRef formalArgs = x->args; + size_t varArgSize = key.size() - formalArgs.size() + 1; + for (size_t i = 0, j = 0; i < formalArgs.size(); ++i) { + FormalArgPtr y = formalArgs[i]; + if (y->varArg) { + if (y->type.ptr()) { + ExprPtr unpack = new Unpack(y->type.ptr()); + unpack->location = y->type->location; + MultiStaticPtr types = new MultiStatic(); + for (; j < varArgSize; ++j) { + types->add(key[i + j].ptr()); } + --j; + if (!unifyMulti(evaluateMultiPattern(new ExprList(unpack), + patternEnv), + types)) + matchBindingError(new MatchMultiBindingError( + unsigned(formalArgs.size()), types, y)); + } else { + j = varArgSize - 1; } - - evaluatePredicate(x->patternVars, x->predicate, staticEnv); - - EnvPtr env2 = new Env(staticEnv); - for (size_t i = 0, j = 0; i < formalArgs.size(); ++i) { - FormalArgPtr y = formalArgs[i]; - if (y->varArg) { - MultiPValuePtr varArgs = new MultiPValue(); - for (; j < varArgSize; ++j) { - PVData parg(key[i + j], false); - varArgs->values.push_back(parg); - } - --j; - addLocal(env2, y->name, varArgs.ptr()); - } else { - addLocal(env2, y->name, new PValue(key[i + j], false)); - } + } else { + if (y->type.ptr()) { + if (!unifyPatternObj( + evaluateOnePattern(y->type, patternEnv), + key[i + j].ptr())) + matchBindingError(new MatchBindingError(unsigned(i + j), + key[i + j], y)); } - return env2; } + } - case ALIAS: { - ensureArity(x->args, 1); - ensureArity(x->values->exprs, 1); - EnvPtr env2 = new Env(env); - ExprPtr y = foreignExpr(env, x->values->exprs[0]); - addLocal(env2, x->args[0]->name, y.ptr()); - return env2; + EnvPtr staticEnv = new Env(env); + for (size_t i = 0; i < pvars.size(); ++i) { + if (pvars[i].isMulti) { + MultiStaticPtr ms = derefDeep(multiCells[i].ptr()); + if (!ms) + error(pvars[i].name, "unbound pattern variable"); + addLocal(staticEnv, pvars[i].name, ms.ptr()); + x->patternTypes.push_back(ms.ptr()); + } else { + ObjectPtr v = derefDeep(cells[i].ptr()); + if (!v) + error(pvars[i].name, "unbound pattern variable"); + addLocal(staticEnv, pvars[i].name, v.ptr()); + x->patternTypes.push_back(v.ptr()); } + } - default: - assert(false); - return nullptr; + evaluatePredicate(x->patternVars, x->predicate, staticEnv); + + EnvPtr env2 = new Env(staticEnv); + for (size_t i = 0, j = 0; i < formalArgs.size(); ++i) { + FormalArgPtr y = formalArgs[i]; + if (y->varArg) { + MultiPValuePtr varArgs = new MultiPValue(); + for (; j < varArgSize; ++j) { + PVData parg(key[i + j], false); + varArgs->values.push_back(parg); + } + --j; + addLocal(env2, y->name, varArgs.ptr()); + } else { + addLocal(env2, y->name, new PValue(key[i + j], false)); + } } + return env2; } - bool returnKindToByRef(ReturnKind returnKind, PVData const &pv) { - switch (returnKind) { - case RETURN_VALUE: return false; - case RETURN_REF: return true; - case RETURN_FORWARD: return !pv.isRValue; - default: assert(false); - return false; - } + case ALIAS: { + ensureArity(x->args, 1); + ensureArity(x->values->exprs, 1); + EnvPtr env2 = new Env(env); + ExprPtr y = foreignExpr(env, x->values->exprs[0]); + addLocal(env2, x->args[0]->name, y.ptr()); + return env2; } - BoolKind typeBoolKind(TypePtr type) { - if (type == boolType) { - return BOOL_EXPR; - } else if (type->typeKind == STATIC_TYPE) { - StaticType *staticType = (StaticType *) type.ptr(); - if (staticType->obj->objKind != VALUE_HOLDER) { - error("expecting value holder"); - } - ValueHolder *valueHolder = (ValueHolder *) staticType->obj.ptr(); - if (valueHolder->type != boolType) { - typeError(boolType, valueHolder->type); - } - bool staticValue = valueHolder->as(); - return staticValue ? BOOL_STATIC_TRUE : BOOL_STATIC_FALSE; - } else { - typeError("Bool or static Bool", type); - return BOOL_STATIC_TRUE; - } + default: + assert(false); + return nullptr; } +} - ExprPtr implicitUnpackExpr(size_t wantCount, const ExprListPtr &exprs) { - if (wantCount >= 1 && exprs->size() == 1 && exprs->exprs[0]->exprKind != UNPACK) - return exprs->exprs[0]; - else - return nullptr; +bool returnKindToByRef(ReturnKind returnKind, PVData const &pv) { + switch (returnKind) { + case RETURN_VALUE: + return false; + case RETURN_REF: + return true; + case RETURN_FORWARD: + return !pv.isRValue; + default: + assert(false); + return false; + } +} + +BoolKind typeBoolKind(TypePtr type) { + if (type == boolType) { + return BOOL_EXPR; + } else if (type->typeKind == STATIC_TYPE) { + StaticType *staticType = (StaticType *)type.ptr(); + if (staticType->obj->objKind != VALUE_HOLDER) { + error("expecting value holder"); + } + ValueHolder *valueHolder = (ValueHolder *)staticType->obj.ptr(); + if (valueHolder->type != boolType) { + typeError(boolType, valueHolder->type); + } + bool staticValue = valueHolder->as(); + return staticValue ? BOOL_STATIC_TRUE : BOOL_STATIC_FALSE; + } else { + typeError("Bool or static Bool", type); + return BOOL_STATIC_TRUE; } } + +ExprPtr implicitUnpackExpr(size_t wantCount, const ExprListPtr &exprs) { + if (wantCount >= 1 && exprs->size() == 1 && + exprs->exprs[0]->exprKind != UNPACK) + return exprs->exprs[0]; + else + return nullptr; +} +} // namespace clay diff --git a/compiler/analyzer.hpp b/compiler/analyzer.hpp index ee73296b..81940127 100644 --- a/compiler/analyzer.hpp +++ b/compiler/analyzer.hpp @@ -2,139 +2,109 @@ #include "clay.hpp" +#include "invoketables.hpp" #include "types.hpp" namespace clay { - void disableAnalysisCaching(); - void enableAnalysisCaching(); - - struct AnalysisCachingDisabler { - AnalysisCachingDisabler() { disableAnalysisCaching(); } - ~AnalysisCachingDisabler() { enableAnalysisCaching(); } - }; - - void initializeStaticForClones(StaticForPtr x, size_t count); - bool returnKindToByRef(ReturnKind returnKind, PVData const &pv); - - ObjectPtr unwrapStaticType(TypePtr t); - - bool staticToBool(ObjectPtr x, bool &out, TypePtr &type); - bool staticToBool(MultiStaticPtr x, unsigned index); - bool staticToCallingConv(ObjectPtr x, CallingConv &out); - CallingConv staticToCallingConv(MultiStaticPtr x, unsigned index); - - static PVData staticPValue(const ObjectPtr& x) { - const TypePtr t = staticType(x); - return {t, true}; - } - - enum BoolKind { - BOOL_EXPR, - BOOL_STATIC_TRUE, - BOOL_STATIC_FALSE - }; - - BoolKind typeBoolKind(TypePtr type); - - PVData safeAnalyzeOne(ExprPtr expr, EnvPtr env); - MultiPValuePtr safeAnalyzeMulti(ExprListPtr exprs, EnvPtr env, size_t wantCount); - MultiPValuePtr safeAnalyzeExpr(ExprPtr expr, EnvPtr env); - MultiPValuePtr safeAnalyzeIndexingExpr(ExprPtr indexable, - ExprListPtr args, - EnvPtr env); - MultiPValuePtr safeAnalyzeMultiArgs(ExprListPtr exprs, - EnvPtr env, - vector &dispatchIndices); - InvokeEntry *safeAnalyzeCallable(ObjectPtr x, - llvm::ArrayRef args); - MultiPValuePtr safeAnalyzeCallByName(InvokeEntry *entry, - ExprPtr callable, - ExprListPtr args, - EnvPtr env); - MultiPValuePtr safeAnalyzeGVarInstance(GVarInstancePtr x); - - MultiPValuePtr analyzeMulti(ExprListPtr exprs, EnvPtr env, size_t wantCount); - PVData analyzeOne(ExprPtr expr, EnvPtr env); - - MultiPValuePtr analyzeMultiArgs(ExprListPtr exprs, - EnvPtr env, - vector &dispatchIndices); - PVData analyzeOneArg(ExprPtr x, - EnvPtr env, - unsigned startIndex, - vector &dispatchIndices); - MultiPValuePtr analyzeArgExpr(ExprPtr x, - EnvPtr env, - unsigned startIndex, - vector &dispatchIndices); - - MultiPValuePtr analyzeExpr(ExprPtr expr, EnvPtr env); - MultiPValuePtr analyzeStaticObject(ObjectPtr x); - - GVarInstancePtr lookupGVarInstance(GlobalVariablePtr x, - llvm::ArrayRef params); - GVarInstancePtr defaultGVarInstance(GlobalVariablePtr x); - GVarInstancePtr analyzeGVarIndexing(GlobalVariablePtr x, - ExprListPtr args, - EnvPtr env); - MultiPValuePtr analyzeGVarInstance(GVarInstancePtr x); - - PVData analyzeExternalVariable(ExternalVariablePtr x); - void analyzeExternalProcedure(ExternalProcedurePtr x); - void verifyAttributes(ExternalProcedurePtr x); - void verifyAttributes(ExternalVariablePtr x); - void verifyAttributes(ModulePtr x); - MultiPValuePtr analyzeIndexingExpr(ExprPtr indexable, - ExprListPtr args, +void disableAnalysisCaching(); +void enableAnalysisCaching(); + +struct AnalysisCachingDisabler { + AnalysisCachingDisabler() { disableAnalysisCaching(); } + ~AnalysisCachingDisabler() { enableAnalysisCaching(); } +}; + +void initializeStaticForClones(StaticForPtr x, size_t count); +bool returnKindToByRef(ReturnKind returnKind, PVData const &pv); + +ObjectPtr unwrapStaticType(TypePtr t); + +bool staticToBool(ObjectPtr x, bool &out, TypePtr &type); +bool staticToBool(MultiStaticPtr x, unsigned index); +bool staticToCallingConv(ObjectPtr x, CallingConv &out); +CallingConv staticToCallingConv(MultiStaticPtr x, unsigned index); + +static PVData staticPValue(const ObjectPtr &x) { + const TypePtr t = staticType(x); + return {t, true}; +} + +enum BoolKind { BOOL_EXPR, BOOL_STATIC_TRUE, BOOL_STATIC_FALSE }; + +BoolKind typeBoolKind(TypePtr type); + +PVData safeAnalyzeOne(ExprPtr expr, EnvPtr env); +MultiPValuePtr safeAnalyzeMulti(ExprListPtr exprs, EnvPtr env, + size_t wantCount); +MultiPValuePtr safeAnalyzeExpr(ExprPtr expr, EnvPtr env); +MultiPValuePtr safeAnalyzeIndexingExpr(ExprPtr indexable, ExprListPtr args, EnvPtr env); - bool unwrapByRef(TypePtr &t); - TypePtr constructType(ObjectPtr constructor, MultiStaticPtr args); - PVData analyzeTypeConstructor(ObjectPtr obj, MultiStaticPtr args); - MultiPValuePtr analyzeAliasIndexing(GlobalAliasPtr x, - ExprListPtr args, - EnvPtr env); - MultiPValuePtr analyzeReturn(llvm::ArrayRef returnIsRef, - llvm::ArrayRef returnTypes); - MultiPValuePtr analyzeCallExpr(ExprPtr callable, - ExprListPtr args, +MultiPValuePtr safeAnalyzeMultiArgs(ExprListPtr exprs, EnvPtr env, + vector &dispatchIndices); +InvokeEntry *safeAnalyzeCallable(ObjectPtr x, llvm::ArrayRef args); +MultiPValuePtr safeAnalyzeCallByName(InvokeEntry *entry, ExprPtr callable, + ExprListPtr args, EnvPtr env); +MultiPValuePtr safeAnalyzeGVarInstance(GVarInstancePtr x); + +MultiPValuePtr analyzeMulti(ExprListPtr exprs, EnvPtr env, size_t wantCount); +PVData analyzeOne(ExprPtr expr, EnvPtr env); + +MultiPValuePtr analyzeMultiArgs(ExprListPtr exprs, EnvPtr env, + vector &dispatchIndices); +PVData analyzeOneArg(ExprPtr x, EnvPtr env, unsigned startIndex, + vector &dispatchIndices); +MultiPValuePtr analyzeArgExpr(ExprPtr x, EnvPtr env, unsigned startIndex, + vector &dispatchIndices); + +MultiPValuePtr analyzeExpr(ExprPtr expr, EnvPtr env); +MultiPValuePtr analyzeStaticObject(ObjectPtr x); + +GVarInstancePtr lookupGVarInstance(GlobalVariablePtr x, + llvm::ArrayRef params); +GVarInstancePtr defaultGVarInstance(GlobalVariablePtr x); +GVarInstancePtr analyzeGVarIndexing(GlobalVariablePtr x, ExprListPtr args, + EnvPtr env); +MultiPValuePtr analyzeGVarInstance(GVarInstancePtr x); + +PVData analyzeExternalVariable(ExternalVariablePtr x); +void analyzeExternalProcedure(ExternalProcedurePtr x); +void verifyAttributes(ExternalProcedurePtr x); +void verifyAttributes(ExternalVariablePtr x); +void verifyAttributes(ModulePtr x); +MultiPValuePtr analyzeIndexingExpr(ExprPtr indexable, ExprListPtr args, EnvPtr env); - PVData analyzeDispatchIndex(PVData const &pv, unsigned tag); - MultiPValuePtr analyzeDispatch(ObjectPtr obj, - MultiPValuePtr args, - llvm::ArrayRef dispatchIndices); - MultiPValuePtr analyzeCallValue(PVData const &callable, - MultiPValuePtr args); - MultiPValuePtr analyzeCallPointer(PVData const &x, - MultiPValuePtr args); - bool analyzeIsDefined(ObjectPtr x, - llvm::ArrayRef args); - InvokeEntry *analyzeCallable(ObjectPtr x, - llvm::ArrayRef args); - - MultiPValuePtr analyzeCallByName(InvokeEntry *entry, - ExprPtr callable, - ExprListPtr args, - EnvPtr env); - - void analyzeCodeBody(InvokeEntry *entry); - - struct AnalysisContext { - vector returnIsRef; - vector returnTypes; - bool hasRecursivePropagation: 1; - bool returnInitialized: 1; - - AnalysisContext() - : hasRecursivePropagation(false), - returnInitialized(false) { - } - }; - - enum StatementAnalysis { - SA_FALLTHROUGH, - SA_RECURSIVE, - SA_TERMINATED - }; - - ExprPtr implicitUnpackExpr(size_t wantCount, const ExprListPtr &exprs); -} +bool unwrapByRef(TypePtr &t); +TypePtr constructType(ObjectPtr constructor, MultiStaticPtr args); +PVData analyzeTypeConstructor(ObjectPtr obj, MultiStaticPtr args); +MultiPValuePtr analyzeAliasIndexing(GlobalAliasPtr x, ExprListPtr args, + EnvPtr env); +MultiPValuePtr analyzeReturn(llvm::ArrayRef returnIsRef, + llvm::ArrayRef returnTypes); +MultiPValuePtr analyzeCallExpr(ExprPtr callable, ExprListPtr args, EnvPtr env); +PVData analyzeDispatchIndex(PVData const &pv, unsigned tag); +MultiPValuePtr analyzeDispatch(ObjectPtr obj, MultiPValuePtr args, + llvm::ArrayRef dispatchIndices); +MultiPValuePtr analyzeCallValue(PVData const &callable, MultiPValuePtr args); +MultiPValuePtr analyzeCallPointer(PVData const &x, MultiPValuePtr args); +bool analyzeIsDefined(ObjectPtr x, llvm::ArrayRef args); +InvokeEntry *analyzeCallable(ObjectPtr x, llvm::ArrayRef args); + +MultiPValuePtr analyzeCallByName(InvokeEntry *entry, ExprPtr callable, + ExprListPtr args, EnvPtr env); + +void analyzeCodeBody(InvokeEntry *entry); + +struct AnalysisContext { + vector returnIsRef; + vector returnTypes; + bool hasRecursivePropagation : 1; + bool returnInitialized : 1; + + AnalysisContext() + : hasRecursivePropagation(false), returnInitialized(false) {} +}; + +enum StatementAnalysis { SA_FALLTHROUGH, SA_RECURSIVE, SA_TERMINATED }; + +ExprPtr implicitUnpackExpr(size_t wantCount, const ExprListPtr &exprs); +} // namespace clay diff --git a/compiler/analyzer_op.cpp b/compiler/analyzer_op.cpp index b1ace831..c93a66a1 100644 --- a/compiler/analyzer_op.cpp +++ b/compiler/analyzer_op.cpp @@ -1,1060 +1,1053 @@ -#include "error.hpp" -#include "objects.hpp" -#include "evaluator.hpp" +#include "analyzer_op.hpp" +#include "analyzer.hpp" #include "constructors.hpp" -#include "loader.hpp" #include "env.hpp" -#include "analyzer.hpp" -#include "analyzer_op.hpp" +#include "error.hpp" +#include "evaluator.hpp" #include "invoketables.hpp" +#include "loader.hpp" +#include "objects.hpp" namespace clay { - static size_t staticToSizeTOrIntValue(MultiPValue *args, size_t index) { - ObjectPtr obj = unwrapStaticType(args->values[index].type); - if (obj->objKind == VALUE_HOLDER) { - ValueHolderPtr vh = (ValueHolder *) obj.ptr(); - if (vh->type == cSizeTType) { - return *((size_t *) vh->buf); - } else if (vh->type == cIntType) { - return (size_t) *((int *) vh->buf); - } - } - argumentError(index, "expecting static SizeT or Int value", args->values[index]); - } - - static TypePtr numericTypeOfValue(MultiPValuePtr x, unsigned index) { - TypePtr t = x->values[index].type; - switch (t->typeKind) { - case INTEGER_TYPE: - case FLOAT_TYPE: - return t; - default: - argumentTypeError(index, "numeric type", t); - return nullptr; +static size_t staticToSizeTOrIntValue(MultiPValue *args, size_t index) { + ObjectPtr obj = unwrapStaticType(args->values[index].type); + if (obj->objKind == VALUE_HOLDER) { + ValueHolderPtr vh = (ValueHolder *)obj.ptr(); + if (vh->type == cSizeTType) { + return *((size_t *)vh->buf); + } else if (vh->type == cIntType) { + return (size_t)*((int *)vh->buf); } } + argumentError(index, "expecting static SizeT or Int value", + args->values[index]); +} - static IntegerTypePtr integerTypeOfValue(MultiPValuePtr x, unsigned index) { - TypePtr t = x->values[index].type; - if (t->typeKind != INTEGER_TYPE) - argumentTypeError(index, "integer type", t); - return (IntegerType *) t.ptr(); +static TypePtr numericTypeOfValue(MultiPValuePtr x, unsigned index) { + TypePtr t = x->values[index].type; + switch (t->typeKind) { + case INTEGER_TYPE: + case FLOAT_TYPE: + return t; + default: + argumentTypeError(index, "numeric type", t); + return nullptr; } +} - static PointerTypePtr pointerTypeOfValue(MultiPValuePtr x, unsigned index) { - TypePtr t = x->values[index].type; - if (t->typeKind != POINTER_TYPE) - argumentTypeError(index, "pointer type", t); - return (PointerType *) t.ptr(); - } +static IntegerTypePtr integerTypeOfValue(MultiPValuePtr x, unsigned index) { + TypePtr t = x->values[index].type; + if (t->typeKind != INTEGER_TYPE) + argumentTypeError(index, "integer type", t); + return (IntegerType *)t.ptr(); +} - static CCodePointerTypePtr cCodePointerTypeOfValue(MultiPValuePtr x, - unsigned index) { - TypePtr t = x->values[index].type; - if (t->typeKind != CCODE_POINTER_TYPE) - argumentTypeError(index, "external code pointer type", t); - return (CCodePointerType *) t.ptr(); - } +static PointerTypePtr pointerTypeOfValue(MultiPValuePtr x, unsigned index) { + TypePtr t = x->values[index].type; + if (t->typeKind != POINTER_TYPE) + argumentTypeError(index, "pointer type", t); + return (PointerType *)t.ptr(); +} - static ArrayTypePtr arrayTypeOfValue(MultiPValuePtr x, unsigned index) { - TypePtr t = x->values[index].type; - if (t->typeKind != ARRAY_TYPE) - argumentTypeError(index, "array type", t); - return (ArrayType *) t.ptr(); - } +static CCodePointerTypePtr cCodePointerTypeOfValue(MultiPValuePtr x, + unsigned index) { + TypePtr t = x->values[index].type; + if (t->typeKind != CCODE_POINTER_TYPE) + argumentTypeError(index, "external code pointer type", t); + return (CCodePointerType *)t.ptr(); +} - static TupleTypePtr tupleTypeOfValue(MultiPValuePtr x, unsigned index) { - TypePtr t = x->values[index].type; - if (t->typeKind != TUPLE_TYPE) - argumentTypeError(index, "tuple type", t); - return (TupleType *) t.ptr(); - } +static ArrayTypePtr arrayTypeOfValue(MultiPValuePtr x, unsigned index) { + TypePtr t = x->values[index].type; + if (t->typeKind != ARRAY_TYPE) + argumentTypeError(index, "array type", t); + return (ArrayType *)t.ptr(); +} - static RecordTypePtr recordTypeOfValue(MultiPValuePtr x, unsigned index) { - TypePtr t = x->values[index].type; - if (t->typeKind != RECORD_TYPE) - argumentTypeError(index, "record type", t); - return (RecordType *) t.ptr(); - } +static TupleTypePtr tupleTypeOfValue(MultiPValuePtr x, unsigned index) { + TypePtr t = x->values[index].type; + if (t->typeKind != TUPLE_TYPE) + argumentTypeError(index, "tuple type", t); + return (TupleType *)t.ptr(); +} - static TypePtr valueToType(MultiPValuePtr x, unsigned index) { - ObjectPtr obj = unwrapStaticType(x->values[index].type); - if (!obj) - argumentError(index, "expecting a type"); - TypePtr t; - if (!staticToType(obj, t)) - argumentError(index, "expecting a type"); +static RecordTypePtr recordTypeOfValue(MultiPValuePtr x, unsigned index) { + TypePtr t = x->values[index].type; + if (t->typeKind != RECORD_TYPE) + argumentTypeError(index, "record type", t); + return (RecordType *)t.ptr(); +} + +static TypePtr valueToType(MultiPValuePtr x, unsigned index) { + ObjectPtr obj = unwrapStaticType(x->values[index].type); + if (!obj) + argumentError(index, "expecting a type"); + TypePtr t; + if (!staticToType(obj, t)) + argumentError(index, "expecting a type"); + return t; +} + +static TypePtr valueToNumericType(MultiPValuePtr x, unsigned index) { + TypePtr t = valueToType(x, index); + switch (t->typeKind) { + case INTEGER_TYPE: + case FLOAT_TYPE: return t; + default: + argumentTypeError(index, "numeric type", t); + return nullptr; } +} - static TypePtr valueToNumericType(MultiPValuePtr x, unsigned index) { - TypePtr t = valueToType(x, index); - switch (t->typeKind) { - case INTEGER_TYPE: - case FLOAT_TYPE: - return t; - default: - argumentTypeError(index, "numeric type", t); - return nullptr; - } - } +static IntegerTypePtr valueToIntegerType(MultiPValuePtr x, unsigned index) { + TypePtr t = valueToType(x, index); + if (t->typeKind != INTEGER_TYPE) + argumentTypeError(index, "integer type", t); + return (IntegerType *)t.ptr(); +} + +static TypePtr valueToPointerLikeType(MultiPValuePtr x, unsigned index) { + TypePtr t = valueToType(x, index); + if (!isPointerOrCodePointerType(t)) + argumentTypeError(index, "pointer or code-pointer type", t); + return t; +} - static IntegerTypePtr valueToIntegerType(MultiPValuePtr x, unsigned index) { - TypePtr t = valueToType(x, index); - if (t->typeKind != INTEGER_TYPE) - argumentTypeError(index, "integer type", t); - return (IntegerType *) t.ptr(); +static EnumTypePtr valueToEnumType(MultiPValuePtr x, unsigned index) { + TypePtr t = valueToType(x, index); + if (t->typeKind != ENUM_TYPE) + argumentTypeError(index, "enum type", t); + return (EnumType *)t.ptr(); +} + +static std::pair, InvokeEntry *> +invokeEntryForCallableArguments(MultiPValuePtr args, unsigned callableIndex, + unsigned firstArgTypeIndex) { + if (args->size() < firstArgTypeIndex) + arityError2(firstArgTypeIndex, args->size()); + ObjectPtr callable = unwrapStaticType(args->values[callableIndex].type); + if (!callable) + argumentError(callableIndex, "static callable expected"); + switch (callable->objKind) { + case TYPE: + case RECORD_DECL: + case VARIANT_DECL: + case PROCEDURE: + case GLOBAL_ALIAS: + break; + case PRIM_OP: + if (!isOverloadablePrimOp(callable)) + argumentError(callableIndex, "invalid callable"); + break; + default: + argumentError(callableIndex, "invalid callable"); + } + vector argTypes; + vector argsPVData; + for (unsigned i = firstArgTypeIndex; i < args->size(); ++i) { + TypePtr t = valueToType(args, i); + argTypes.push_back(t); + argsPVData.push_back(PVData(t, false)); } - static TypePtr valueToPointerLikeType(MultiPValuePtr x, unsigned index) { - TypePtr t = valueToType(x, index); - if (!isPointerOrCodePointerType(t)) - argumentTypeError(index, "pointer or code-pointer type", t); - return t; + CompileContextPusher pusher(callable, argsPVData); + + return std::make_pair(argTypes, analyzeCallable(callable, argsPVData)); +} + +MultiPValuePtr analyzePrimOp(PrimOpPtr x, MultiPValuePtr args) { + switch (x->primOpCode) { + case PRIM_TypeP: + return new MultiPValue(PVData(boolType, true)); + + case PRIM_TypeSize: + return new MultiPValue(PVData(cSizeTType, true)); + + case PRIM_TypeAlignment: + return new MultiPValue(PVData(cSizeTType, true)); + + case PRIM_OperatorP: + case PRIM_SymbolP: + case PRIM_StaticCallDefinedP: + return new MultiPValue(PVData(boolType, true)); + + case PRIM_StaticCallOutputTypes: { + std::pair, InvokeEntry *> entry = + invokeEntryForCallableArguments(args, 0, 1); + MultiPValuePtr values = new MultiPValue(); + for (size_t i = 0; i < entry.second->returnTypes.size(); ++i) + values->add(staticPValue(entry.second->returnTypes[i].ptr())); + return values; } - static EnumTypePtr valueToEnumType(MultiPValuePtr x, unsigned index) { - TypePtr t = valueToType(x, index); - if (t->typeKind != ENUM_TYPE) - argumentTypeError(index, "enum type", t); - return (EnumType *) t.ptr(); + case PRIM_StaticMonoP: { + return new MultiPValue(PVData(boolType, true)); } - static std::pair, InvokeEntry *> - invokeEntryForCallableArguments(MultiPValuePtr args, unsigned callableIndex, unsigned firstArgTypeIndex) { - if (args->size() < firstArgTypeIndex) - arityError2(firstArgTypeIndex, args->size()); - ObjectPtr callable = unwrapStaticType(args->values[callableIndex].type); + case PRIM_StaticMonoInputTypes: { + ensureArity(args, 1); + ObjectPtr callable = unwrapStaticType(args->values[0].type); if (!callable) - argumentError(callableIndex, "static callable expected"); + argumentError(0, "static callable expected"); + switch (callable->objKind) { - case TYPE: - case RECORD_DECL: - case VARIANT_DECL: - case PROCEDURE: - case GLOBAL_ALIAS: - break; - case PRIM_OP: - if (!isOverloadablePrimOp(callable)) - argumentError(callableIndex, "invalid callable"); - break; - default: - argumentError(callableIndex, "invalid callable"); + case PROCEDURE: { + Procedure *proc = (Procedure *)callable.ptr(); + if (proc->mono.monoState != Procedure_MonoOverload) { + argumentError(0, "not a static monomorphic callable"); + } + + MultiPValuePtr values = new MultiPValue(); + for (size_t i = 0; i < proc->mono.monoTypes.size(); ++i) + values->add(staticPValue(proc->mono.monoTypes[i].ptr())); + + return values; } - vector argTypes; - vector argsPVData; - for (unsigned i = firstArgTypeIndex; i < args->size(); ++i) { - TypePtr t = valueToType(args, i); - argTypes.push_back(t); - argsPVData.push_back(PVData(t, false)); + + default: + argumentError(0, "not a static monomorphic callable"); } + } - CompileContextPusher pusher(callable, argsPVData); + case PRIM_bitcopy: + return new MultiPValue(); + + case PRIM_boolNot: + return new MultiPValue(PVData(boolType, true)); + + case PRIM_integerEqualsP: + case PRIM_integerLesserP: + case PRIM_floatOrderedEqualsP: + case PRIM_floatOrderedLesserP: + case PRIM_floatOrderedLesserEqualsP: + case PRIM_floatOrderedGreaterP: + case PRIM_floatOrderedGreaterEqualsP: + case PRIM_floatOrderedNotEqualsP: + case PRIM_floatOrderedP: + case PRIM_floatUnorderedEqualsP: + case PRIM_floatUnorderedLesserP: + case PRIM_floatUnorderedLesserEqualsP: + case PRIM_floatUnorderedGreaterP: + case PRIM_floatUnorderedGreaterEqualsP: + case PRIM_floatUnorderedNotEqualsP: + case PRIM_floatUnorderedP: + ensureArity(args, 2); + return new MultiPValue(PVData(boolType, true)); + + case PRIM_numericAdd: + case PRIM_numericSubtract: + case PRIM_numericMultiply: + case PRIM_floatDivide: { + ensureArity(args, 2); + TypePtr t = numericTypeOfValue(args, 0); + return new MultiPValue(PVData(t, true)); + } - return std::make_pair( - argTypes, - analyzeCallable(callable, argsPVData)); + case PRIM_numericNegate: { + ensureArity(args, 1); + TypePtr t = numericTypeOfValue(args, 0); + return new MultiPValue(PVData(t, true)); } - MultiPValuePtr analyzePrimOp(PrimOpPtr x, MultiPValuePtr args) { - switch (x->primOpCode) { - case PRIM_TypeP: - return new MultiPValue(PVData(boolType, true)); + case PRIM_integerQuotient: + case PRIM_integerRemainder: + case PRIM_integerShiftLeft: + case PRIM_integerShiftRight: + case PRIM_integerBitwiseAnd: + case PRIM_integerBitwiseOr: + case PRIM_integerBitwiseXor: + case PRIM_integerAddChecked: + case PRIM_integerSubtractChecked: + case PRIM_integerMultiplyChecked: + case PRIM_integerQuotientChecked: + case PRIM_integerRemainderChecked: + case PRIM_integerShiftLeftChecked: { + ensureArity(args, 2); + IntegerTypePtr t = integerTypeOfValue(args, 0); + return new MultiPValue(PVData(t.ptr(), true)); + } - case PRIM_TypeSize: - return new MultiPValue(PVData(cSizeTType, true)); + case PRIM_integerBitwiseNot: + case PRIM_integerNegateChecked: { + ensureArity(args, 1); + IntegerTypePtr t = integerTypeOfValue(args, 0); + return new MultiPValue(PVData(t.ptr(), true)); + } - case PRIM_TypeAlignment: - return new MultiPValue(PVData(cSizeTType, true)); + case PRIM_numericConvert: { + ensureArity(args, 2); + TypePtr t = valueToNumericType(args, 0); + return new MultiPValue(PVData(t, true)); + } - case PRIM_OperatorP: - case PRIM_SymbolP: - case PRIM_StaticCallDefinedP: - return new MultiPValue(PVData(boolType, true)); + case PRIM_integerConvertChecked: { + ensureArity(args, 2); + IntegerTypePtr t = valueToIntegerType(args, 0); + return new MultiPValue(PVData(t.ptr(), true)); + } - case PRIM_StaticCallOutputTypes: { - std::pair, InvokeEntry *> entry = - invokeEntryForCallableArguments(args, 0, 1); - MultiPValuePtr values = new MultiPValue(); - for (size_t i = 0; i < entry.second->returnTypes.size(); ++i) - values->add(staticPValue(entry.second->returnTypes[i].ptr())); - return values; - } + case PRIM_Pointer: + error("no Pointer type constructor overload found"); - case PRIM_StaticMonoP: { - return new MultiPValue(PVData(boolType, true)); - } + case PRIM_addressOf: { + ensureArity(args, 1); + TypePtr t = pointerType(args->values[0].type); + return new MultiPValue(PVData(t, true)); + } - case PRIM_StaticMonoInputTypes: { - ensureArity(args, 1); - ObjectPtr callable = unwrapStaticType(args->values[0].type); - if (!callable) - argumentError(0, "static callable expected"); - - switch (callable->objKind) { - case PROCEDURE: { - Procedure *proc = (Procedure *) callable.ptr(); - if (proc->mono.monoState != Procedure_MonoOverload) { - argumentError(0, "not a static monomorphic callable"); - } - - MultiPValuePtr values = new MultiPValue(); - for (size_t i = 0; i < proc->mono.monoTypes.size(); ++i) - values->add(staticPValue(proc->mono.monoTypes[i].ptr())); - - return values; - } - - default: - argumentError(0, "not a static monomorphic callable"); - } - } + case PRIM_pointerDereference: { + ensureArity(args, 1); + PointerTypePtr pt = pointerTypeOfValue(args, 0); + return new MultiPValue(PVData(pt->pointeeType, false)); + } - case PRIM_bitcopy: - return new MultiPValue(); - - case PRIM_boolNot: - return new MultiPValue(PVData(boolType, true)); - - case PRIM_integerEqualsP: - case PRIM_integerLesserP: - case PRIM_floatOrderedEqualsP: - case PRIM_floatOrderedLesserP: - case PRIM_floatOrderedLesserEqualsP: - case PRIM_floatOrderedGreaterP: - case PRIM_floatOrderedGreaterEqualsP: - case PRIM_floatOrderedNotEqualsP: - case PRIM_floatOrderedP: - case PRIM_floatUnorderedEqualsP: - case PRIM_floatUnorderedLesserP: - case PRIM_floatUnorderedLesserEqualsP: - case PRIM_floatUnorderedGreaterP: - case PRIM_floatUnorderedGreaterEqualsP: - case PRIM_floatUnorderedNotEqualsP: - case PRIM_floatUnorderedP: - ensureArity(args, 2); - return new MultiPValue(PVData(boolType, true)); - - case PRIM_numericAdd: - case PRIM_numericSubtract: - case PRIM_numericMultiply: - case PRIM_floatDivide: { - ensureArity(args, 2); - TypePtr t = numericTypeOfValue(args, 0); - return new MultiPValue(PVData(t, true)); - } + case PRIM_pointerOffset: { + ensureArity(args, 2); + PointerTypePtr pt = pointerTypeOfValue(args, 0); + return new MultiPValue(PVData(pt.ptr(), true)); + } - case PRIM_numericNegate: { - ensureArity(args, 1); - TypePtr t = numericTypeOfValue(args, 0); - return new MultiPValue(PVData(t, true)); - } + case PRIM_pointerToInt: { + ensureArity(args, 2); + IntegerTypePtr t = valueToIntegerType(args, 0); + return new MultiPValue(PVData(t.ptr(), true)); + } - case PRIM_integerQuotient: - case PRIM_integerRemainder: - case PRIM_integerShiftLeft: - case PRIM_integerShiftRight: - case PRIM_integerBitwiseAnd: - case PRIM_integerBitwiseOr: - case PRIM_integerBitwiseXor: - case PRIM_integerAddChecked: - case PRIM_integerSubtractChecked: - case PRIM_integerMultiplyChecked: - case PRIM_integerQuotientChecked: - case PRIM_integerRemainderChecked: - case PRIM_integerShiftLeftChecked: { - ensureArity(args, 2); - IntegerTypePtr t = integerTypeOfValue(args, 0); - return new MultiPValue(PVData(t.ptr(), true)); - } + case PRIM_intToPointer: { + ensureArity(args, 2); + TypePtr t = valueToPointerLikeType(args, 0); + return new MultiPValue(PVData(t, true)); + } - case PRIM_integerBitwiseNot: - case PRIM_integerNegateChecked: { - ensureArity(args, 1); - IntegerTypePtr t = integerTypeOfValue(args, 0); - return new MultiPValue(PVData(t.ptr(), true)); - } + case PRIM_nullPointer: { + ensureArity(args, 1); + TypePtr t = valueToPointerLikeType(args, 0); + return new MultiPValue(PVData(t, true)); + } - case PRIM_numericConvert: { - ensureArity(args, 2); - TypePtr t = valueToNumericType(args, 0); - return new MultiPValue(PVData(t, true)); - } + case PRIM_CodePointer: + error("no CodePointer type constructor overload found"); + + case PRIM_makeCodePointer: { + std::pair, InvokeEntry *> entry = + invokeEntryForCallableArguments(args, 0, 1); + if (entry.second->callByName) + argumentError(0, "cannot create pointer to call-by-name code"); + if (!entry.second->analyzed) + return nullptr; + TypePtr cpType = codePointerType(entry.first, entry.second->returnIsRef, + entry.second->returnTypes); + return new MultiPValue(PVData(cpType, true)); + } - case PRIM_integerConvertChecked: { - ensureArity(args, 2); - IntegerTypePtr t = valueToIntegerType(args, 0); - return new MultiPValue(PVData(t.ptr(), true)); - } + case PRIM_ExternalCodePointer: + error("no ExternalCodePointer type constructor overload found"); + + case PRIM_makeExternalCodePointer: { + std::pair, InvokeEntry *> entry = + invokeEntryForCallableArguments(args, 0, 3); + if (entry.second->callByName) + argumentError(0, "cannot create pointer to call-by-name code"); + if (!entry.second->analyzed) + return nullptr; + + ObjectPtr ccObj = unwrapStaticType(args->values[1].type); + CallingConv cc; + if (!staticToCallingConv(ccObj, cc)) + argumentError(1, "expecting a calling convention attribute"); + + ObjectPtr isVarArgObj = unwrapStaticType(args->values[2].type); + bool isVarArg; + TypePtr type; + if (!staticToBool(isVarArgObj, isVarArg, type)) + argumentTypeError(2, "static Bool", type); + + if (isVarArg) + argumentError(2, "implementation of external variadic functions is " + "not yet supported"); + + TypePtr returnType; + if (entry.second->returnTypes.empty()) { + returnType = nullptr; + } else if (entry.second->returnTypes.size() == 1) { + if (entry.second->returnIsRef[0]) { + argumentError(0, "cannot create external code pointer to " + " return-by-reference code"); + } + returnType = entry.second->returnTypes[0]; + } else { + argumentError(0, "cannot create external code pointer to " + "multi-return code"); + } + TypePtr ccpType = + cCodePointerType(cc, entry.first, isVarArg, returnType); + return new MultiPValue(PVData(ccpType, true)); + } - case PRIM_Pointer: - error("no Pointer type constructor overload found"); + case PRIM_callExternalCodePointer: { + if (args->size() < 1) + arityError2(1, args->size()); + CCodePointerTypePtr y = cCodePointerTypeOfValue(args, 0); + if (!y->returnType) + return new MultiPValue(); + return new MultiPValue(PVData(y->returnType, true)); + } - case PRIM_addressOf: { - ensureArity(args, 1); - TypePtr t = pointerType(args->values[0].type); - return new MultiPValue(PVData(t, true)); - } + case PRIM_bitcast: { + ensureArity(args, 2); + TypePtr t = valueToType(args, 0); + return new MultiPValue(PVData(t, false)); + } - case PRIM_pointerDereference: { - ensureArity(args, 1); - PointerTypePtr pt = pointerTypeOfValue(args, 0); - return new MultiPValue(PVData(pt->pointeeType, false)); - } + case PRIM_Array: + error("no Array type constructor overload found"); - case PRIM_pointerOffset: { - ensureArity(args, 2); - PointerTypePtr pt = pointerTypeOfValue(args, 0); - return new MultiPValue(PVData(pt.ptr(), true)); - } + case PRIM_arrayRef: { + ensureArity(args, 2); + ArrayTypePtr t = arrayTypeOfValue(args, 0); + return new MultiPValue(PVData(t->elementType, false)); + } - case PRIM_pointerToInt: { - ensureArity(args, 2); - IntegerTypePtr t = valueToIntegerType(args, 0); - return new MultiPValue(PVData(t.ptr(), true)); - } + case PRIM_arrayElements: { + ensureArity(args, 1); + ArrayTypePtr t = arrayTypeOfValue(args, 0); + MultiPValuePtr mpv = new MultiPValue(); + for (size_t i = 0; i < t->size; ++i) + mpv->add(PVData(t->elementType, false)); + return mpv; + } - case PRIM_intToPointer: { - ensureArity(args, 2); - TypePtr t = valueToPointerLikeType(args, 0); - return new MultiPValue(PVData(t, true)); - } + case PRIM_Vec: + error("no Vec type constructor overload found"); - case PRIM_nullPointer: { - ensureArity(args, 1); - TypePtr t = valueToPointerLikeType(args, 0); - return new MultiPValue(PVData(t, true)); - } + case PRIM_Tuple: + error("no Tuple type constructor overload found"); - case PRIM_CodePointer: - error("no CodePointer type constructor overload found"); - - case PRIM_makeCodePointer: { - std::pair, InvokeEntry *> entry = - invokeEntryForCallableArguments(args, 0, 1); - if (entry.second->callByName) - argumentError(0, "cannot create pointer to call-by-name code"); - if (!entry.second->analyzed) - return nullptr; - TypePtr cpType = codePointerType(entry.first, - entry.second->returnIsRef, - entry.second->returnTypes); - return new MultiPValue(PVData(cpType, true)); - } + case PRIM_TupleElementCount: + return new MultiPValue(PVData(cSizeTType, true)); - case PRIM_ExternalCodePointer: - error("no ExternalCodePointer type constructor overload found"); - - case PRIM_makeExternalCodePointer: { - std::pair, InvokeEntry *> entry = - invokeEntryForCallableArguments(args, 0, 3); - if (entry.second->callByName) - argumentError(0, "cannot create pointer to call-by-name code"); - if (!entry.second->analyzed) - return nullptr; - - ObjectPtr ccObj = unwrapStaticType(args->values[1].type); - CallingConv cc; - if (!staticToCallingConv(ccObj, cc)) - argumentError(1, "expecting a calling convention attribute"); - - ObjectPtr isVarArgObj = unwrapStaticType(args->values[2].type); - bool isVarArg; - TypePtr type; - if (!staticToBool(isVarArgObj, isVarArg, type)) - argumentTypeError(2, "static Bool", type); - - if (isVarArg) - argumentError(2, "implementation of external variadic functions is not yet supported"); - - TypePtr returnType; - if (entry.second->returnTypes.empty()) { - returnType = nullptr; - } else if (entry.second->returnTypes.size() == 1) { - if (entry.second->returnIsRef[0]) { - argumentError(0, "cannot create external code pointer to " - " return-by-reference code"); - } - returnType = entry.second->returnTypes[0]; - } else { - argumentError(0, "cannot create external code pointer to " - "multi-return code"); - } - TypePtr ccpType = cCodePointerType(cc, - entry.first, - isVarArg, - returnType); - return new MultiPValue(PVData(ccpType, true)); - } + case PRIM_tupleRef: { + ensureArity(args, 2); + TupleTypePtr t = tupleTypeOfValue(args, 0); + size_t i = staticToSizeTOrIntValue(args.ptr(), 1); + if (i >= t->elementTypes.size()) + argumentIndexRangeError(1, "tuple element index", i, + t->elementTypes.size()); + return new MultiPValue(PVData(t->elementTypes[i], false)); + } - case PRIM_callExternalCodePointer: { - if (args->size() < 1) - arityError2(1, args->size()); - CCodePointerTypePtr y = cCodePointerTypeOfValue(args, 0); - if (!y->returnType) - return new MultiPValue(); - return new MultiPValue(PVData(y->returnType, true)); - } + case PRIM_tupleElements: { + ensureArity(args, 1); + TupleTypePtr t = tupleTypeOfValue(args, 0); + MultiPValuePtr mpv = new MultiPValue(); + for (size_t i = 0; i < t->elementTypes.size(); ++i) + mpv->add(PVData(t->elementTypes[i], false)); + return mpv; + } - case PRIM_bitcast: { - ensureArity(args, 2); - TypePtr t = valueToType(args, 0); - return new MultiPValue(PVData(t, false)); - } + case PRIM_Union: + error("no Union type constructor overload found"); - case PRIM_Array: - error("no Array type constructor overload found"); + case PRIM_UnionMemberCount: + return new MultiPValue(PVData(cSizeTType, true)); - case PRIM_arrayRef: { - ensureArity(args, 2); - ArrayTypePtr t = arrayTypeOfValue(args, 0); - return new MultiPValue(PVData(t->elementType, false)); - } + case PRIM_RecordP: + return new MultiPValue(PVData(boolType, true)); - case PRIM_arrayElements: { - ensureArity(args, 1); - ArrayTypePtr t = arrayTypeOfValue(args, 0); - MultiPValuePtr mpv = new MultiPValue(); - for (size_t i = 0; i < t->size; ++i) - mpv->add(PVData(t->elementType, false)); - return mpv; - } + case PRIM_RecordFieldCount: + return new MultiPValue(PVData(cSizeTType, true)); - case PRIM_Vec: - error("no Vec type constructor overload found"); + case PRIM_RecordFieldName: { + ensureArity(args, 2); + ObjectPtr first = unwrapStaticType(args->values[0].type); + if (!first) + argumentError(0, "expecting a record type"); + TypePtr t; + if (!staticToType(first, t)) + argumentError(0, "expecting a record type"); + if (t->typeKind != RECORD_TYPE) + argumentError(0, "expecting a record type"); + RecordType *rt = (RecordType *)t.ptr(); + size_t i = staticToSizeTOrIntValue(args.ptr(), 1); + const vector fieldNames = recordFieldNames(rt); + if (i >= fieldNames.size()) + argumentIndexRangeError(1, "record field index", i, + fieldNames.size()); + return new MultiPValue(staticPValue(fieldNames[i].ptr())); + } - case PRIM_Tuple: - error("no Tuple type constructor overload found"); + case PRIM_RecordWithFieldP: + return new MultiPValue(PVData(boolType, true)); + + case PRIM_recordFieldRef: { + ensureArity(args, 2); + RecordTypePtr t = recordTypeOfValue(args, 0); + size_t i = staticToSizeTOrIntValue(args.ptr(), 1); + llvm::ArrayRef fieldTypes = recordFieldTypes(t); + if (i >= t->fieldCount()) + argumentIndexRangeError(1, "record field index", i, + t->fieldCount()); + + MultiPValuePtr mpv = new MultiPValue(); + if (t->hasVarField && i >= t->varFieldPosition) + if (i == t->varFieldPosition) + for (size_t j = 0; j < t->varFieldSize(); ++j) + mpv->add(PVData(fieldTypes[i + j], false)); + else + mpv->add(PVData(fieldTypes[i + t->varFieldSize() - 1], false)); + else + mpv->add(PVData(fieldTypes[i], false)); + return mpv; + } - case PRIM_TupleElementCount: - return new MultiPValue(PVData(cSizeTType, true)); + case PRIM_recordFieldRefByName: { + ensureArity(args, 2); + RecordTypePtr t = recordTypeOfValue(args, 0); + ObjectPtr obj = unwrapStaticType(args->values[1].type); + if (!obj || (obj->objKind != IDENTIFIER)) + argumentError(1, "expecting field name identifier"); + IdentifierPtr fname = (Identifier *)obj.ptr(); + const llvm::StringMap &fieldIndexMap = recordFieldIndexMap(t); + llvm::StringMap::const_iterator fi = + fieldIndexMap.find(fname->str); + if (fi == fieldIndexMap.end()) { + string buf; + llvm::raw_string_ostream sout(buf); + sout << "field not found: " << fname->str; + argumentError(1, sout.str()); + } + llvm::ArrayRef fieldTypes = recordFieldTypes(t); + MultiPValuePtr mpv = new MultiPValue(); + size_t i = fi->second; + if (t->hasVarField && i >= t->varFieldPosition) + if (i == t->varFieldPosition) + for (size_t j = 0; j < t->varFieldSize(); ++j) + mpv->add(PVData(fieldTypes[i + j], false)); + else + mpv->add(PVData(fieldTypes[i + t->varFieldSize() - 1], false)); + else + mpv->add(PVData(fieldTypes[i], false)); + return mpv; + } - case PRIM_tupleRef: { - ensureArity(args, 2); - TupleTypePtr t = tupleTypeOfValue(args, 0); - size_t i = staticToSizeTOrIntValue(args.ptr(), 1); - if (i >= t->elementTypes.size()) - argumentIndexRangeError(1, "tuple element index", - i, t->elementTypes.size()); - return new MultiPValue(PVData(t->elementTypes[i], false)); - } + case PRIM_recordFields: { + ensureArity(args, 1); + RecordTypePtr t = recordTypeOfValue(args, 0); + llvm::ArrayRef fieldTypes = recordFieldTypes(t); + MultiPValuePtr mpv = new MultiPValue(); + for (size_t i = 0; i < fieldTypes.size(); ++i) + mpv->add(PVData(fieldTypes[i], false)); + return mpv; + } - case PRIM_tupleElements: { - ensureArity(args, 1); - TupleTypePtr t = tupleTypeOfValue(args, 0); - MultiPValuePtr mpv = new MultiPValue(); - for (size_t i = 0; i < t->elementTypes.size(); ++i) - mpv->add(PVData(t->elementTypes[i], false)); - return mpv; - } + case PRIM_recordVariadicField: { + ensureArity(args, 1); + RecordTypePtr t = recordTypeOfValue(args, 0); + if (!t->hasVarField) + argumentError(0, "expecting a record with a variadic field"); + llvm::ArrayRef fieldTypes = recordFieldTypes(t); + MultiPValuePtr mpv = new MultiPValue(); + size_t varEnd = t->varFieldPosition + t->varFieldSize(); + for (size_t i = t->varFieldPosition; i < varEnd; ++i) + mpv->add(PVData(fieldTypes[i], false)); + return mpv; + } - case PRIM_Union: - error("no Union type constructor overload found"); - - case PRIM_UnionMemberCount: - return new MultiPValue(PVData(cSizeTType, true)); - - case PRIM_RecordP: - return new MultiPValue(PVData(boolType, true)); - - case PRIM_RecordFieldCount: - return new MultiPValue(PVData(cSizeTType, true)); - - case PRIM_RecordFieldName: { - ensureArity(args, 2); - ObjectPtr first = unwrapStaticType(args->values[0].type); - if (!first) - argumentError(0, "expecting a record type"); - TypePtr t; - if (!staticToType(first, t)) - argumentError(0, "expecting a record type"); - if (t->typeKind != RECORD_TYPE) - argumentError(0, "expecting a record type"); - RecordType *rt = (RecordType *) t.ptr(); - size_t i = staticToSizeTOrIntValue(args.ptr(), 1); - const vector fieldNames = recordFieldNames(rt); - if (i >= fieldNames.size()) - argumentIndexRangeError(1, "record field index", - i, fieldNames.size()); - return new MultiPValue(staticPValue(fieldNames[i].ptr())); - } + case PRIM_VariantP: + return new MultiPValue(PVData(boolType, true)); - case PRIM_RecordWithFieldP: - return new MultiPValue(PVData(boolType, true)); - - case PRIM_recordFieldRef: { - ensureArity(args, 2); - RecordTypePtr t = recordTypeOfValue(args, 0); - size_t i = staticToSizeTOrIntValue(args.ptr(), 1); - llvm::ArrayRef fieldTypes = recordFieldTypes(t); - if (i >= t->fieldCount()) - argumentIndexRangeError(1, "record field index", - i, t->fieldCount()); - - MultiPValuePtr mpv = new MultiPValue(); - if (t->hasVarField && i >= t->varFieldPosition) - if (i == t->varFieldPosition) - for (size_t j = 0; j < t->varFieldSize(); ++j) - mpv->add(PVData(fieldTypes[i + j], false)); - else - mpv->add(PVData(fieldTypes[i + t->varFieldSize() - 1], false)); - else - mpv->add(PVData(fieldTypes[i], false)); - return mpv; - } + case PRIM_VariantMemberIndex: + return new MultiPValue(PVData(cSizeTType, true)); - case PRIM_recordFieldRefByName: { - ensureArity(args, 2); - RecordTypePtr t = recordTypeOfValue(args, 0); - ObjectPtr obj = unwrapStaticType(args->values[1].type); - if (!obj || (obj->objKind != IDENTIFIER)) - argumentError(1, "expecting field name identifier"); - IdentifierPtr fname = (Identifier *) obj.ptr(); - const llvm::StringMap &fieldIndexMap = recordFieldIndexMap(t); - llvm::StringMap::const_iterator fi = - fieldIndexMap.find(fname->str); - if (fi == fieldIndexMap.end()) { - string buf; - llvm::raw_string_ostream sout(buf); - sout << "field not found: " << fname->str; - argumentError(1, sout.str()); - } - llvm::ArrayRef fieldTypes = recordFieldTypes(t); - MultiPValuePtr mpv = new MultiPValue(); - size_t i = fi->second; - if (t->hasVarField && i >= t->varFieldPosition) - if (i == t->varFieldPosition) - for (size_t j = 0; j < t->varFieldSize(); ++j) - mpv->add(PVData(fieldTypes[i + j], false)); - else - mpv->add(PVData(fieldTypes[i + t->varFieldSize() - 1], false)); - else - mpv->add(PVData(fieldTypes[i], false)); - return mpv; - } + case PRIM_VariantMemberCount: + return new MultiPValue(PVData(cSizeTType, true)); - case PRIM_recordFields: { - ensureArity(args, 1); - RecordTypePtr t = recordTypeOfValue(args, 0); - llvm::ArrayRef fieldTypes = recordFieldTypes(t); - MultiPValuePtr mpv = new MultiPValue(); - for (size_t i = 0; i < fieldTypes.size(); ++i) - mpv->add(PVData(fieldTypes[i], false)); - return mpv; - } + case PRIM_VariantMembers: { + ensureArity(args, 1); + ObjectPtr typeObj = unwrapStaticType(args->values[0].type); + if (!typeObj) + argumentError(0, "expecting a variant type"); + TypePtr t; + if (!staticToType(typeObj, t)) + argumentError(0, "expecting a variant type"); + if (t->typeKind != VARIANT_TYPE) + argumentError(0, "expecting a variant type"); + VariantType *vt = (VariantType *)t.ptr(); + llvm::ArrayRef members = variantMemberTypes(vt); + + MultiPValuePtr mpv = new MultiPValue(); + for (TypePtr const *i = members.begin(), *end = members.end(); i != end; + ++i) { + mpv->add(staticPValue(i->ptr())); + } + return mpv; + } - case PRIM_recordVariadicField: { - ensureArity(args, 1); - RecordTypePtr t = recordTypeOfValue(args, 0); - if (!t->hasVarField) - argumentError(0, "expecting a record with a variadic field"); - llvm::ArrayRef fieldTypes = recordFieldTypes(t); - MultiPValuePtr mpv = new MultiPValue(); - size_t varEnd = t->varFieldPosition + t->varFieldSize(); - for (size_t i = t->varFieldPosition; i < varEnd; ++i) - mpv->add(PVData(fieldTypes[i], false)); - return mpv; - } + case PRIM_BaseType: { + ensureArity(args, 1); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + if (!obj && obj->objKind != TYPE) + argumentError(0, "static type expected"); + Type *type = (Type *)obj.ptr(); + MultiPValuePtr mpv = new MultiPValue(); + if (type->typeKind == NEW_TYPE) { + NewType *nt = (NewType *)type; + mpv->add(staticPValue(newtypeReprType(nt).ptr())); + } else { + mpv->add(staticPValue(type)); + } + return mpv; + } - case PRIM_VariantP: - return new MultiPValue(PVData(boolType, true)); - - case PRIM_VariantMemberIndex: - return new MultiPValue(PVData(cSizeTType, true)); - - case PRIM_VariantMemberCount: - return new MultiPValue(PVData(cSizeTType, true)); - - case PRIM_VariantMembers: { - ensureArity(args, 1); - ObjectPtr typeObj = unwrapStaticType(args->values[0].type); - if (!typeObj) - argumentError(0, "expecting a variant type"); - TypePtr t; - if (!staticToType(typeObj, t)) - argumentError(0, "expecting a variant type"); - if (t->typeKind != VARIANT_TYPE) - argumentError(0, "expecting a variant type"); - VariantType *vt = (VariantType *) t.ptr(); - llvm::ArrayRef members = variantMemberTypes(vt); - - MultiPValuePtr mpv = new MultiPValue(); - for (TypePtr const *i = members.begin(), *end = members.end(); - i != end; - ++i) { - mpv->add(staticPValue(i->ptr())); - } - return mpv; - } + case PRIM_Static: + error("no Static type constructor overload found"); + + case PRIM_staticIntegers: { + ensureArity(args, 1); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + if (!obj || (obj->objKind != VALUE_HOLDER)) + argumentError(0, "expecting a static SizeT or Int value"); + MultiPValuePtr mpv = new MultiPValue(); + ValueHolder *vh = (ValueHolder *)obj.ptr(); + if (vh->type == cIntType) { + int count = *((int *)vh->buf); + if (count < 0) + argumentError(0, "negative values are not allowed"); + for (int i = 0; i < count; ++i) { + ValueHolderPtr vhi = intToValueHolder(i); + mpv->add(PVData(staticType(vhi.ptr()), true)); + } + } else if (vh->type == cSizeTType) { + size_t count = *((size_t *)vh->buf); + for (size_t i = 0; i < count; ++i) { + ValueHolderPtr vhi = sizeTToValueHolder(i); + mpv->add(PVData(staticType(vhi.ptr()), true)); + } + } else { + argumentError(0, "expecting a static SizeT or Int value"); + } + return mpv; + } - case PRIM_BaseType: { - ensureArity(args, 1); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - if (!obj && obj->objKind != TYPE) - argumentError(0, "static type expected"); - Type *type = (Type *) obj.ptr(); - MultiPValuePtr mpv = new MultiPValue(); - if (type->typeKind == NEW_TYPE) { - NewType *nt = (NewType *) type; - mpv->add(staticPValue(newtypeReprType(nt).ptr())); - } else { - mpv->add(staticPValue(type)); - } - return mpv; - } + case PRIM_integers: { + ensureArity(args, 1); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + if (!obj || (obj->objKind != VALUE_HOLDER)) + argumentError(0, "expecting a static SizeT or Int value"); + MultiPValuePtr mpv = new MultiPValue(); + ValueHolder *vh = (ValueHolder *)obj.ptr(); + if (vh->type == cIntType) { + int count = *((int *)vh->buf); + if (count < 0) + argumentError(0, "negative values are not allowed"); + for (int i = 0; i < count; ++i) + mpv->add(PVData(cIntType, true)); + } else if (vh->type == cSizeTType) { + size_t count = *((size_t *)vh->buf); + for (size_t i = 0; i < count; ++i) + mpv->add(PVData(cSizeTType, true)); + } else { + argumentError(0, "expecting a static SizeT or Int value"); + } + return mpv; + } - case PRIM_Static: - error("no Static type constructor overload found"); - - case PRIM_staticIntegers: { - ensureArity(args, 1); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - if (!obj || (obj->objKind != VALUE_HOLDER)) - argumentError(0, "expecting a static SizeT or Int value"); - MultiPValuePtr mpv = new MultiPValue(); - ValueHolder *vh = (ValueHolder *) obj.ptr(); - if (vh->type == cIntType) { - int count = *((int *) vh->buf); - if (count < 0) - argumentError(0, "negative values are not allowed"); - for (int i = 0; i < count; ++i) { - ValueHolderPtr vhi = intToValueHolder(i); - mpv->add(PVData(staticType(vhi.ptr()), true)); - } - } else if (vh->type == cSizeTType) { - size_t count = *((size_t *) vh->buf); - for (size_t i = 0; i < count; ++i) { - ValueHolderPtr vhi = sizeTToValueHolder(i); - mpv->add(PVData(staticType(vhi.ptr()), true)); - } - } else { - argumentError(0, "expecting a static SizeT or Int value"); - } - return mpv; - } + case PRIM_staticFieldRef: { + ensureArity(args, 2); + ObjectPtr moduleObj = unwrapStaticType(args->values[0].type); + if (!moduleObj || (moduleObj->objKind != MODULE)) + argumentError(0, "expecting a module"); + ObjectPtr identObj = unwrapStaticType(args->values[1].type); + if (!identObj || (identObj->objKind != IDENTIFIER)) + argumentError(1, "expecting a string literal value"); + Module *module = (Module *)moduleObj.ptr(); + Identifier *ident = (Identifier *)identObj.ptr(); + ObjectPtr obj = safeLookupPublic(module, ident); + return analyzeStaticObject(obj); + } - case PRIM_integers: { - ensureArity(args, 1); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - if (!obj || (obj->objKind != VALUE_HOLDER)) - argumentError(0, "expecting a static SizeT or Int value"); - MultiPValuePtr mpv = new MultiPValue(); - ValueHolder *vh = (ValueHolder *) obj.ptr(); - if (vh->type == cIntType) { - int count = *((int *) vh->buf); - if (count < 0) - argumentError(0, "negative values are not allowed"); - for (int i = 0; i < count; ++i) - mpv->add(PVData(cIntType, true)); - } else if (vh->type == cSizeTType) { - size_t count = *((size_t *) vh->buf); - for (size_t i = 0; i < count; ++i) - mpv->add(PVData(cSizeTType, true)); - } else { - argumentError(0, "expecting a static SizeT or Int value"); - } - return mpv; - } + case PRIM_EnumP: + return new MultiPValue(PVData(boolType, true)); - case PRIM_staticFieldRef: { - ensureArity(args, 2); - ObjectPtr moduleObj = unwrapStaticType(args->values[0].type); - if (!moduleObj || (moduleObj->objKind != MODULE)) - argumentError(0, "expecting a module"); - ObjectPtr identObj = unwrapStaticType(args->values[1].type); - if (!identObj || (identObj->objKind != IDENTIFIER)) - argumentError(1, "expecting a string literal value"); - Module *module = (Module *) moduleObj.ptr(); - Identifier *ident = (Identifier *) identObj.ptr(); - ObjectPtr obj = safeLookupPublic(module, ident); - return analyzeStaticObject(obj); - } + case PRIM_EnumMemberCount: + return new MultiPValue(PVData(cSizeTType, true)); - case PRIM_EnumP: - return new MultiPValue(PVData(boolType, true)); + case PRIM_EnumMemberName: { + ensureArity(args, 2); + EnumTypePtr et = valueToEnumType(args, 0); + size_t i = staticToSizeTOrIntValue(args.ptr(), 1); - case PRIM_EnumMemberCount: - return new MultiPValue(PVData(cSizeTType, true)); + EnumDeclPtr e = et->enumeration; + if (i >= e->members.size()) + argumentIndexRangeError(1, "enum member index", i, + e->members.size()); - case PRIM_EnumMemberName: { - ensureArity(args, 2); - EnumTypePtr et = valueToEnumType(args, 0); - size_t i = staticToSizeTOrIntValue(args.ptr(), 1); + return analyzeStaticObject(e->members[i]->name.ptr()); + } - EnumDeclPtr e = et->enumeration; - if (i >= e->members.size()) - argumentIndexRangeError(1, "enum member index", - i, e->members.size()); + case PRIM_enumToInt: + return new MultiPValue(PVData(cIntType, true)); - return analyzeStaticObject(e->members[i]->name.ptr()); - } + case PRIM_intToEnum: { + ensureArity(args, 2); + EnumTypePtr t = valueToEnumType(args, 0); + initializeEnumType(t); + return new MultiPValue(PVData(t.ptr(), true)); + } - case PRIM_enumToInt: - return new MultiPValue(PVData(cIntType, true)); + case PRIM_StringLiteralP: + return new MultiPValue(PVData(boolType, true)); + + case PRIM_stringLiteralByteIndex: + return new MultiPValue(PVData(cIntType, true)); + + case PRIM_stringLiteralBytes: { + ensureArity(args, 1); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + if (!obj || (obj->objKind != IDENTIFIER)) + argumentError(0, "expecting a string literal value"); + Identifier *ident = (Identifier *)obj.ptr(); + MultiPValuePtr result = new MultiPValue(); + for (size_t i = 0, sz = ident->str.size(); i < sz; ++i) + result->add(PVData(cIntType, true)); + return result; + } - case PRIM_intToEnum: { - ensureArity(args, 2); - EnumTypePtr t = valueToEnumType(args, 0); - initializeEnumType(t); - return new MultiPValue(PVData(t.ptr(), true)); - } + case PRIM_stringLiteralByteSize: + return new MultiPValue(PVData(cSizeTType, true)); + + case PRIM_stringLiteralByteSlice: { + ensureArity(args, 3); + ObjectPtr identObj = unwrapStaticType(args->values[0].type); + if (!identObj || (identObj->objKind != IDENTIFIER)) + argumentError(0, "expecting a string literal value"); + Identifier *ident = (Identifier *)identObj.ptr(); + ObjectPtr beginObj = unwrapStaticType(args->values[1].type); + ObjectPtr endObj = unwrapStaticType(args->values[2].type); + size_t begin = staticToSizeTOrIntValue(args.ptr(), 1); + size_t end = staticToSizeTOrIntValue(args.ptr(), 2); + if (end > ident->str.size()) { + argumentIndexRangeError(2, "ending index", end, ident->str.size()); + } + if (begin > end) + argumentIndexRangeError(1, "starting index", begin, end); + llvm::StringRef result(&ident->str[unsigned(begin)], end - begin); + return analyzeStaticObject(Identifier::get(result)); + } - case PRIM_StringLiteralP: - return new MultiPValue(PVData(boolType, true)); - - case PRIM_stringLiteralByteIndex: - return new MultiPValue(PVData(cIntType, true)); - - case PRIM_stringLiteralBytes: { - ensureArity(args, 1); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - if (!obj || (obj->objKind != IDENTIFIER)) - argumentError(0, "expecting a string literal value"); - Identifier *ident = (Identifier *) obj.ptr(); - MultiPValuePtr result = new MultiPValue(); - for (size_t i = 0, sz = ident->str.size(); i < sz; ++i) - result->add(PVData(cIntType, true)); - return result; - } + case PRIM_stringLiteralConcat: { + llvm::SmallString<32> result; + for (size_t i = 0, sz = args->size(); i < sz; ++i) { + ObjectPtr obj = unwrapStaticType(args->values[unsigned(i)].type); + if (!obj || (obj->objKind != IDENTIFIER)) + argumentError(i, "expecting a string literal value"); + Identifier *ident = (Identifier *)obj.ptr(); + result.append(ident->str.begin(), ident->str.end()); + } + return analyzeStaticObject(Identifier::get(result)); + } - case PRIM_stringLiteralByteSize: - return new MultiPValue(PVData(cSizeTType, true)); - - case PRIM_stringLiteralByteSlice: { - ensureArity(args, 3); - ObjectPtr identObj = unwrapStaticType(args->values[0].type); - if (!identObj || (identObj->objKind != IDENTIFIER)) - argumentError(0, "expecting a string literal value"); - Identifier *ident = (Identifier *) identObj.ptr(); - ObjectPtr beginObj = unwrapStaticType(args->values[1].type); - ObjectPtr endObj = unwrapStaticType(args->values[2].type); - size_t begin = staticToSizeTOrIntValue(args.ptr(), 1); - size_t end = staticToSizeTOrIntValue(args.ptr(), 2); - if (end > ident->str.size()) { - argumentIndexRangeError(2, "ending index", - end, ident->str.size()); - } - if (begin > end) - argumentIndexRangeError(1, "starting index", - begin, end); - llvm::StringRef result(&ident->str[unsigned(begin)], end - begin); - return analyzeStaticObject(Identifier::get(result)); - } + case PRIM_stringLiteralFromBytes: { + std::string result; + for (size_t i = 0, sz = args->size(); i < sz; ++i) { + size_t byte = staticToSizeTOrIntValue(args.ptr(), i); + if (byte > 255) { + string buf; + llvm::raw_string_ostream os(buf); + os << byte << " is too large for a string literal byte"; + argumentError(i, os.str()); + } + result.push_back((char)byte); + } + return analyzeStaticObject(Identifier::get(result)); + } - case PRIM_stringLiteralConcat: { - llvm::SmallString<32> result; - for (size_t i = 0, sz = args->size(); i < sz; ++i) { - ObjectPtr obj = unwrapStaticType(args->values[unsigned(i)].type); - if (!obj || (obj->objKind != IDENTIFIER)) - argumentError(i, "expecting a string literal value"); - Identifier *ident = (Identifier *) obj.ptr(); - result.append(ident->str.begin(), ident->str.end()); - } - return analyzeStaticObject(Identifier::get(result)); - } + case PRIM_stringTableConstant: + return new MultiPValue(PVData(pointerType(cSizeTType), true)); - case PRIM_stringLiteralFromBytes: { - std::string result; - for (size_t i = 0, sz = args->size(); i < sz; ++i) { - size_t byte = staticToSizeTOrIntValue(args.ptr(), i); - if (byte > 255) { - string buf; - llvm::raw_string_ostream os(buf); - os << byte << " is too large for a string literal byte"; - argumentError(i, os.str()); - } - result.push_back((char) byte); - } - return analyzeStaticObject(Identifier::get(result)); - } + case PRIM_StaticName: { + ensureArity(args, 1); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + if (!obj) + argumentError(0, "expecting static object"); + llvm::SmallString<128> buf; + llvm::raw_svector_ostream sout(buf); + printStaticName(sout, obj); + return analyzeStaticObject(Identifier::get(sout.str())); + } - case PRIM_stringTableConstant: - return new MultiPValue(PVData(pointerType(cSizeTType), true)); - - case PRIM_StaticName: { - ensureArity(args, 1); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - if (!obj) - argumentError(0, "expecting static object"); - llvm::SmallString<128> buf; - llvm::raw_svector_ostream sout(buf); - printStaticName(sout, obj); - return analyzeStaticObject(Identifier::get(sout.str())); - } + case PRIM_MainModule: { + ensureArity(args, 0); + assert(globalMainModule != nullptr); + return analyzeStaticObject(globalMainModule.ptr()); + } - case PRIM_MainModule: { - ensureArity(args, 0); - assert(globalMainModule != nullptr); - return analyzeStaticObject(globalMainModule.ptr()); - } + case PRIM_StaticModule: { + ensureArity(args, 1); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + if (!obj) + argumentError(0, "expecting static object"); + ModulePtr m = staticModule(obj); + if (!m) + argumentError(0, "value has no associated module"); + return analyzeStaticObject(m.ptr()); + } - case PRIM_StaticModule: { - ensureArity(args, 1); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - if (!obj) - argumentError(0, "expecting static object"); - ModulePtr m = staticModule(obj); - if (!m) - argumentError(0, "value has no associated module"); - return analyzeStaticObject(m.ptr()); - } + case PRIM_ModuleName: { + ensureArity(args, 1); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + if (!obj) + argumentError(0, "expecting static object"); + ModulePtr m = staticModule(obj); + if (!m) + argumentError(0, "value has no associated module"); + return analyzeStaticObject(Identifier::get(m->moduleName)); + } - case PRIM_ModuleName: { - ensureArity(args, 1); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - if (!obj) - argumentError(0, "expecting static object"); - ModulePtr m = staticModule(obj); - if (!m) - argumentError(0, "value has no associated module"); - return analyzeStaticObject(Identifier::get(m->moduleName)); - } + case PRIM_ModuleMemberNames: { + ensureArity(args, 1); + ObjectPtr moduleObj = unwrapStaticType(args->values[0].type); + if (!moduleObj || (moduleObj->objKind != MODULE)) + argumentError(0, "expecting a module"); + ModulePtr m = staticModule(moduleObj); + assert(m != nullptr); + + MultiPValuePtr result = new MultiPValue(); + + for (llvm::StringMap::const_iterator + i = m->publicGlobals.begin(), + end = m->publicGlobals.end(); + i != end; ++i) { + result->add(staticPValue(Identifier::get(i->getKey()))); + } + return result; + } - case PRIM_ModuleMemberNames: { - ensureArity(args, 1); - ObjectPtr moduleObj = unwrapStaticType(args->values[0].type); - if (!moduleObj || (moduleObj->objKind != MODULE)) - argumentError(0, "expecting a module"); - ModulePtr m = staticModule(moduleObj); - assert(m != nullptr); - - MultiPValuePtr result = new MultiPValue(); - - for (llvm::StringMap::const_iterator i = m->publicGlobals.begin(), - end = m->publicGlobals.end(); - i != end; - ++i) { - result->add(staticPValue(Identifier::get(i->getKey()))); - } - return result; - } + case PRIM_FlagP: { + return new MultiPValue(PVData(boolType, true)); + } - case PRIM_FlagP: { - return new MultiPValue(PVData(boolType, true)); - } + case PRIM_Flag: { + ensureArity(args, 1); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + if (obj != nullptr && obj->objKind == IDENTIFIER) { + Identifier *ident = (Identifier *)obj.ptr(); + + llvm::StringMap::const_iterator flag = + globalFlags.find(ident->str); + string value; + if (flag != globalFlags.end()) + value = flag->second; + + return analyzeStaticObject(Identifier::get(value)); + } else + argumentTypeError(0, "identifier", args->values[0].type); + return nullptr; + } - case PRIM_Flag: { - ensureArity(args, 1); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - if (obj != nullptr && obj->objKind == IDENTIFIER) { - Identifier *ident = (Identifier *) obj.ptr(); - - llvm::StringMap::const_iterator flag = globalFlags.find(ident->str); - string value; - if (flag != globalFlags.end()) - value = flag->second; - - return analyzeStaticObject(Identifier::get(value)); - } else - argumentTypeError(0, "identifier", args->values[0].type); - return nullptr; - } + case PRIM_atomicFence: { + ensureArity(args, 1); + return new MultiPValue(); + } - case PRIM_atomicFence: { - ensureArity(args, 1); - return new MultiPValue(); - } + case PRIM_atomicRMW: { + // order op ptr val + ensureArity(args, 4); + pointerTypeOfValue(args, 2); + return new MultiPValue(PVData(args->values[3].type, true)); + } - case PRIM_atomicRMW: { - // order op ptr val - ensureArity(args, 4); - pointerTypeOfValue(args, 2); - return new MultiPValue(PVData(args->values[3].type, true)); - } + case PRIM_atomicLoad: { + // order ptr + ensureArity(args, 2); + PointerTypePtr pt = pointerTypeOfValue(args, 1); + return new MultiPValue(PVData(pt->pointeeType, true)); + } - case PRIM_atomicLoad: { - // order ptr - ensureArity(args, 2); - PointerTypePtr pt = pointerTypeOfValue(args, 1); - return new MultiPValue(PVData(pt->pointeeType, true)); - } + case PRIM_atomicStore: { + // order ptr val + ensureArity(args, 3); + pointerTypeOfValue(args, 1); + return new MultiPValue(); + } - case PRIM_atomicStore: { - // order ptr val - ensureArity(args, 3); - pointerTypeOfValue(args, 1); - return new MultiPValue(); - } + case PRIM_atomicCompareExchange: { + // order ptr old new + ensureArity(args, 4); + PointerTypePtr pt = pointerTypeOfValue(args, 1); - case PRIM_atomicCompareExchange: { - // order ptr old new - ensureArity(args, 4); - PointerTypePtr pt = pointerTypeOfValue(args, 1); + return new MultiPValue(PVData(args->values[2].type, true)); + } - return new MultiPValue(PVData(args->values[2].type, true)); - } + case PRIM_activeException: { + ensureArity(args, 0); + return new MultiPValue(PVData(pointerType(uint8Type), true)); + } - case PRIM_activeException: { - ensureArity(args, 0); - return new MultiPValue(PVData(pointerType(uint8Type), true)); - } + case PRIM_memcpy: + case PRIM_memmove: { + ensureArity(args, 3); + PointerTypePtr toPt = pointerTypeOfValue(args, 0); + PointerTypePtr fromPt = pointerTypeOfValue(args, 1); + integerTypeOfValue(args, 2); + return new MultiPValue(); + } - case PRIM_memcpy: - case PRIM_memmove: { - ensureArity(args, 3); - PointerTypePtr toPt = pointerTypeOfValue(args, 0); - PointerTypePtr fromPt = pointerTypeOfValue(args, 1); - integerTypeOfValue(args, 2); - return new MultiPValue(); - } + case PRIM_countValues: { + return new MultiPValue(PVData(cIntType, true)); + } - case PRIM_countValues: { - return new MultiPValue(PVData(cIntType, true)); - } + case PRIM_nthValue: { + if (args->size() < 1) + arityError2(1, args->size()); + ObjectPtr obj = unwrapStaticType(args->values[0].type); + size_t i = staticToSizeTOrIntValue(args.ptr(), 0); + if (i + 1 >= args->size()) + argumentError(0, "nthValue argument out of bounds"); + return new MultiPValue(args->values[unsigned(i) + 1]); + } - case PRIM_nthValue: { - if (args->size() < 1) - arityError2(1, args->size()); - ObjectPtr obj = unwrapStaticType(args->values[0].type); - size_t i = staticToSizeTOrIntValue(args.ptr(), 0); - if (i + 1 >= args->size()) - argumentError(0, "nthValue argument out of bounds"); - return new MultiPValue(args->values[unsigned(i) + 1]); - } + case PRIM_withoutNthValue: { + if (args->size() < 1) + arityError2(1, args->size()); + size_t i = staticToSizeTOrIntValue(args.ptr(), 0); + if (i + 1 >= args->size()) + argumentError(0, "withoutNthValue argument out of bounds"); + MultiPValuePtr mpv = new MultiPValue(); + for (unsigned n = 1; n < args->size(); ++n) { + if (n == i + 1) + continue; + mpv->add(args->values[n]); + } + return mpv; + } - case PRIM_withoutNthValue: { - if (args->size() < 1) - arityError2(1, args->size()); - size_t i = staticToSizeTOrIntValue(args.ptr(), 0); - if (i + 1 >= args->size()) - argumentError(0, "withoutNthValue argument out of bounds"); - MultiPValuePtr mpv = new MultiPValue(); - for (unsigned n = 1; n < args->size(); ++n) { - if (n == i + 1) - continue; - mpv->add(args->values[n]); - } - return mpv; - } + case PRIM_takeValues: { + if (args->size() < 1) + arityError2(1, args->size()); + size_t i = staticToSizeTOrIntValue(args.ptr(), 0); + if (i + 1 >= args->size()) + i = args->size() - 1; + MultiPValuePtr mpv = new MultiPValue(); + for (unsigned n = 1; n < i + 1; ++n) + mpv->add(args->values[n]); + return mpv; + } - case PRIM_takeValues: { - if (args->size() < 1) - arityError2(1, args->size()); - size_t i = staticToSizeTOrIntValue(args.ptr(), 0); - if (i + 1 >= args->size()) - i = args->size() - 1; - MultiPValuePtr mpv = new MultiPValue(); - for (unsigned n = 1; n < i + 1; ++n) - mpv->add(args->values[n]); - return mpv; - } + case PRIM_dropValues: { + if (args->size() < 1) + arityError2(1, args->size()); + size_t i = staticToSizeTOrIntValue(args.ptr(), 0); + if (i + 1 >= args->size()) + i = args->size() - 1; + MultiPValuePtr mpv = new MultiPValue(); + for (size_t n = i + 1; n < args->size(); ++n) + mpv->add(args->values[unsigned(n)]); + return mpv; + } - case PRIM_dropValues: { - if (args->size() < 1) - arityError2(1, args->size()); - size_t i = staticToSizeTOrIntValue(args.ptr(), 0); - if (i + 1 >= args->size()) - i = args->size() - 1; - MultiPValuePtr mpv = new MultiPValue(); - for (size_t n = i + 1; n < args->size(); ++n) - mpv->add(args->values[unsigned(n)]); - return mpv; - } + case PRIM_LambdaRecordP: { + ensureArity(args, 1); + return new MultiPValue(PVData(boolType, true)); + } - case PRIM_LambdaRecordP: { - ensureArity(args, 1); - return new MultiPValue(PVData(boolType, true)); - } + case PRIM_LambdaSymbolP: { + ensureArity(args, 1); + return new MultiPValue(PVData(boolType, true)); + } - case PRIM_LambdaSymbolP: { - ensureArity(args, 1); - return new MultiPValue(PVData(boolType, true)); - } + case PRIM_LambdaMonoP: { + ensureArity(args, 1); + return new MultiPValue(PVData(boolType, true)); + } - case PRIM_LambdaMonoP: { - ensureArity(args, 1); - return new MultiPValue(PVData(boolType, true)); - } + case PRIM_LambdaMonoInputTypes: { + ensureArity(args, 1); + ObjectPtr callable = unwrapStaticType(args->values[0].type); + if (!callable) + argumentError(0, "lambda record type expected"); + + if (callable != nullptr && callable->objKind == TYPE) { + Type *t = (Type *)callable.ptr(); + if (t->typeKind == RECORD_TYPE) { + RecordType *r = (RecordType *)t; + if (r->record->lambda->mono.monoState != Procedure_MonoOverload) + argumentError(0, "not a monomorphic lambda record type"); + llvm::ArrayRef monoTypes = + r->record->lambda->mono.monoTypes; + MultiPValuePtr values = new MultiPValue(); + for (size_t i = 0; i < monoTypes.size(); ++i) + values->add(staticPValue(monoTypes[i].ptr())); - case PRIM_LambdaMonoInputTypes: { - ensureArity(args, 1); - ObjectPtr callable = unwrapStaticType(args->values[0].type); - if (!callable) - argumentError(0, "lambda record type expected"); - - if (callable != nullptr && callable->objKind == TYPE) { - Type *t = (Type *) callable.ptr(); - if (t->typeKind == RECORD_TYPE) { - RecordType *r = (RecordType *) t; - if (r->record->lambda->mono.monoState != Procedure_MonoOverload) - argumentError(0, "not a monomorphic lambda record type"); - llvm::ArrayRef monoTypes = r->record->lambda->mono.monoTypes; - MultiPValuePtr values = new MultiPValue(); - for (size_t i = 0; i < monoTypes.size(); ++i) - values->add(staticPValue(monoTypes[i].ptr())); - - return values; - } - } - - argumentError(0, "not a monomorphic lambda record type"); - return new MultiPValue(); + return values; } + } - case PRIM_GetOverload: { - std::pair, InvokeEntry *> entry = - invokeEntryForCallableArguments(args, 0, 1); - - llvm::SmallString<128> buf; - llvm::raw_svector_ostream nameout(buf); - nameout << "GetOverload("; - printStaticName(nameout, entry.second->callable); - nameout << ", "; - nameout << ")"; - - ProcedurePtr proc = new Procedure( - nullptr, Identifier::get(nameout.str()), - PRIVATE, false); - - proc->env = entry.second->env; - - CodePtr code = new Code(), origCode = entry.second->origCode; - for (vector::const_iterator arg = origCode->formalArgs.begin(), - end = origCode->formalArgs.end(); - arg != end; - ++arg) { - code->formalArgs.push_back(new FormalArg((*arg)->name, nullptr)); - } - - code->hasVarArg = origCode->hasVarArg; - - if (origCode->hasNamedReturns()) { - code->returnSpecsDeclared = true; - code->returnSpecs = origCode->returnSpecs; - code->varReturnSpec = origCode->varReturnSpec; - } - - code->body = origCode->body; - code->llvmBody = origCode->llvmBody; - - OverloadPtr overload = new Overload( - nullptr, - new ObjectExpr(proc.ptr()), - code, - entry.second->callByName, - entry.second->isInline); - overload->env = entry.second->env; - addProcedureOverload(proc, entry.second->env, overload); - - return new MultiPValue(staticPValue(proc.ptr())); - } + argumentError(0, "not a monomorphic lambda record type"); + return new MultiPValue(); + } - case PRIM_usuallyEquals: { - ensureArity(args, 2); - if (!isPrimitiveType(args->values[0].type)) - argumentTypeError(0, "primitive type", args->values[0].type); - ObjectPtr expectedValue = unwrapStaticType(args->values[1].type); - if (expectedValue == nullptr - || expectedValue->objKind != VALUE_HOLDER - || ((ValueHolder *) expectedValue.ptr())->type != args->values[0].type) - error( - "second argument to usuallyEquals must be a static value of the same type as the first argument"); - return new MultiPValue(PVData(args->values[0].type, true)); - } + case PRIM_GetOverload: { + std::pair, InvokeEntry *> entry = + invokeEntryForCallableArguments(args, 0, 1); - default: - assert(false); - return nullptr; + llvm::SmallString<128> buf; + llvm::raw_svector_ostream nameout(buf); + nameout << "GetOverload("; + printStaticName(nameout, entry.second->callable); + nameout << ", "; + nameout << ")"; + + ProcedurePtr proc = new Procedure( + nullptr, Identifier::get(nameout.str()), PRIVATE, false); + + proc->env = entry.second->env; + + CodePtr code = new Code(), origCode = entry.second->origCode; + for (vector::const_iterator + arg = origCode->formalArgs.begin(), + end = origCode->formalArgs.end(); + arg != end; ++arg) { + code->formalArgs.push_back(new FormalArg((*arg)->name, nullptr)); } + + code->hasVarArg = origCode->hasVarArg; + + if (origCode->hasNamedReturns()) { + code->returnSpecsDeclared = true; + code->returnSpecs = origCode->returnSpecs; + code->varReturnSpec = origCode->varReturnSpec; + } + + code->body = origCode->body; + code->llvmBody = origCode->llvmBody; + + OverloadPtr overload = + new Overload(nullptr, new ObjectExpr(proc.ptr()), code, + entry.second->callByName, entry.second->isInline); + overload->env = entry.second->env; + addProcedureOverload(proc, entry.second->env, overload); + + return new MultiPValue(staticPValue(proc.ptr())); + } + + case PRIM_usuallyEquals: { + ensureArity(args, 2); + if (!isPrimitiveType(args->values[0].type)) + argumentTypeError(0, "primitive type", args->values[0].type); + ObjectPtr expectedValue = unwrapStaticType(args->values[1].type); + if (expectedValue == nullptr || + expectedValue->objKind != VALUE_HOLDER || + ((ValueHolder *)expectedValue.ptr())->type != args->values[0].type) + error("second argument to usuallyEquals must be a static value of " + "the same type as the first argument"); + return new MultiPValue(PVData(args->values[0].type, true)); + } + + default: + assert(false); + return nullptr; } } +} // namespace clay diff --git a/compiler/analyzer_op.hpp b/compiler/analyzer_op.hpp index af8a2c32..60bdf3e4 100644 --- a/compiler/analyzer_op.hpp +++ b/compiler/analyzer_op.hpp @@ -3,5 +3,5 @@ #include "clay.hpp" namespace clay { - MultiPValuePtr analyzePrimOp(PrimOpPtr x, MultiPValuePtr args); +MultiPValuePtr analyzePrimOp(PrimOpPtr x, MultiPValuePtr args); } diff --git a/compiler/checkedcast.hpp b/compiler/checkedcast.hpp index a38b06b5..be7e9917 100644 --- a/compiler/checkedcast.hpp +++ b/compiler/checkedcast.hpp @@ -3,10 +3,9 @@ #include "assert.h" namespace clay { - template - To checked_cast(From *from) { - // TODO: for unknown reason this code cause SEGV in runtime - //assert(!from || dynamic_cast(from)); - return static_cast(from); - } +template To checked_cast(From *from) { + // TODO: for unknown reason this code cause SEGV in runtime + // assert(!from || dynamic_cast(from)); + return static_cast(from); } +} // namespace clay diff --git a/compiler/clay.cpp b/compiler/clay.cpp index 2b1b76db..94fb8a26 100644 --- a/compiler/clay.cpp +++ b/compiler/clay.cpp @@ -1,15 +1,15 @@ -#include -#include -#include #include +#include +#include #include +#include #include "clay.hpp" -#include "hirestimer.hpp" -#include "error.hpp" #include "codegen.hpp" -#include "loader.hpp" +#include "error.hpp" +#include "hirestimer.hpp" #include "invoketables.hpp" +#include "loader.hpp" #include "parachute.hpp" using std::string; @@ -17,9 +17,9 @@ using std::vector; // for _exit #ifdef _WIN32 -# include +#include #else -# include +#include #endif namespace clay { @@ -35,1020 +35,1090 @@ namespace clay { #define ENV_SEPARATOR ':' #endif - static bool runModule(llvm::Module *module, +static bool runModule(llvm::Module *module, const std::vector &argv, - char const *const*envp, + char const *const *envp, llvm::ArrayRef libSearchPaths, llvm::ArrayRef libs) { - auto JIT_expected = llvm::orc::LLJITBuilder().create(); - if (!JIT_expected) { - llvm::errs() << "error creating JIT: " << llvm::toString(JIT_expected.takeError()) << "\n"; - return false; - } - auto JIT = std::move(JIT_expected.get()); - llvm::orc::LLJIT &jit = *JIT; - - llvm::orc::JITDylib& mainDylib = jit.getMainJITDylib(); + auto JIT_expected = llvm::orc::LLJITBuilder().create(); + if (!JIT_expected) { + llvm::errs() << "error creating JIT: " + << llvm::toString(JIT_expected.takeError()) << "\n"; + return false; + } + auto JIT = std::move(JIT_expected.get()); + llvm::orc::LLJIT &jit = *JIT; - auto Generator_expected = llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( - jit.getDataLayout().getGlobalPrefix() - ); + llvm::orc::JITDylib &mainDylib = jit.getMainJITDylib(); - if (!Generator_expected) { - llvm::errs() << "error creating generator: " << llvm::toString(Generator_expected.takeError()) << "\n"; - return false; - } + auto Generator_expected = + llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( + jit.getDataLayout().getGlobalPrefix()); - std::unique_ptr Generator = - std::move(*Generator_expected); - - mainDylib.addGenerator(std::move(Generator)); + if (!Generator_expected) { + llvm::errs() << "error creating generator: " + << llvm::toString(Generator_expected.takeError()) << "\n"; + return false; + } - module->setDataLayout(jit.getDataLayout()); + std::unique_ptr Generator = + std::move(*Generator_expected); - auto TSM = llvm::orc::ThreadSafeModule(std::unique_ptr(module), - std::make_unique()); + mainDylib.addGenerator(std::move(Generator)); - if (llvm::Error AddIRErr = jit.addIRModule(std::move(TSM))) { - llvm::errs() << "error adding module to JIT: " << llvm::toString(std::move(AddIRErr)) << "\n"; - return false; - } + module->setDataLayout(jit.getDataLayout()); - auto mainAddr_expected = jit.lookup("main"); - if (!mainAddr_expected) { - llvm::errs() << "error resolving main: " << llvm::toString(mainAddr_expected.takeError()) << "\n"; - return false; - } + auto TSM = + llvm::orc::ThreadSafeModule(std::unique_ptr(module), + std::make_unique()); - using MainPtr = int (*)(int, char *[], char *[]); + if (llvm::Error AddIRErr = jit.addIRModule(std::move(TSM))) { + llvm::errs() << "error adding module to JIT: " + << llvm::toString(std::move(AddIRErr)) << "\n"; + return false; + } - llvm::orc::ExecutorAddr mainAddr = mainAddr_expected.get(); - auto mainFunc = reinterpret_cast(mainAddr.getValue()); + auto mainAddr_expected = jit.lookup("main"); + if (!mainAddr_expected) { + llvm::errs() << "error resolving main: " + << llvm::toString(mainAddr_expected.takeError()) << "\n"; + return false; + } - std::vector c_argv; - for (const auto& arg : argv) { - c_argv.push_back(arg.c_str()); - } - c_argv.push_back(nullptr); + using MainPtr = int (*)(int, char *[], char *[]); - mainFunc(static_cast(c_argv.size() - 1), const_cast(c_argv.data()), const_cast(envp)); + llvm::orc::ExecutorAddr mainAddr = mainAddr_expected.get(); + auto mainFunc = reinterpret_cast(mainAddr.getValue()); - return true; + std::vector c_argv; + for (const auto &arg : argv) { + c_argv.push_back(arg.c_str()); } + c_argv.push_back(nullptr); - static void optimizeLLVM(llvm::Module *module, unsigned optLevel, bool internalize) { - llvm::LoopAnalysisManager LAM; - llvm::FunctionAnalysisManager FAM; - llvm::CGSCCAnalysisManager CGAM; - llvm::ModuleAnalysisManager MAM; - llvm::PassBuilder PB; - - PB.registerModuleAnalyses(MAM); - PB.registerCGSCCAnalyses(CGAM); - PB.registerFunctionAnalyses(FAM); - PB.registerLoopAnalyses(LAM); - PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); - - llvm::OptimizationLevel O = llvm::OptimizationLevel::O0; - if (optLevel == 1) O = llvm::OptimizationLevel::O1; - else if (optLevel == 2) O = llvm::OptimizationLevel::O2; - else if (optLevel >= 3) O = llvm::OptimizationLevel::O3; - - llvm::ModulePassManager MPM = PB.buildPerModuleDefaultPipeline(O); - - if (optLevel > 2 && internalize) { - MPM.addPass(llvm::InternalizePass([=](const llvm::GlobalValue &GV) { - return GV.getName() == "main"; - })); - } + mainFunc(static_cast(c_argv.size() - 1), + const_cast(c_argv.data()), const_cast(envp)); - MPM.addPass(llvm::VerifierPass()); + return true; +} - MPM.run(*module, MAM); +static void optimizeLLVM(llvm::Module *module, unsigned optLevel, + bool internalize) { + llvm::LoopAnalysisManager LAM; + llvm::FunctionAnalysisManager FAM; + llvm::CGSCCAnalysisManager CGAM; + llvm::ModuleAnalysisManager MAM; + llvm::PassBuilder PB; + + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + llvm::OptimizationLevel O = llvm::OptimizationLevel::O0; + if (optLevel == 1) + O = llvm::OptimizationLevel::O1; + else if (optLevel == 2) + O = llvm::OptimizationLevel::O2; + else if (optLevel >= 3) + O = llvm::OptimizationLevel::O3; + + llvm::ModulePassManager MPM = PB.buildPerModuleDefaultPipeline(O); + + if (optLevel > 2 && internalize) { + MPM.addPass(llvm::InternalizePass([=](const llvm::GlobalValue &GV) { + return GV.getName() == "main"; + })); } - static void generateLLVM(llvm::Module *module, bool emitAsm, llvm::raw_ostream *out) { - llvm::ModuleAnalysisManager MAM; - llvm::ModulePassManager passes; + MPM.addPass(llvm::VerifierPass()); - if (emitAsm) - passes.addPass(llvm::PrintModulePass(*out)); - else - passes.addPass(llvm::BitcodeWriterPass(*out)); + MPM.run(*module, MAM); +} - passes.run(*module, MAM); - } +static void generateLLVM(llvm::Module *module, bool emitAsm, + llvm::raw_ostream *out) { + llvm::ModuleAnalysisManager MAM; + llvm::ModulePassManager passes; - static void generateAssembly(llvm::Module *module, - llvm::TargetMachine *targetMachine, - llvm::raw_pwrite_stream *out, - bool emitObject) { - llvm::legacy::PassManager passes; + if (emitAsm) + passes.addPass(llvm::PrintModulePass(*out)); + else + passes.addPass(llvm::BitcodeWriterPass(*out)); - passes.add(llvm::createVerifierPass()); + passes.run(*module, MAM); +} - llvm::CodeGenFileType fileType = emitObject - ? llvm::CodeGenFileType::ObjectFile - : llvm::CodeGenFileType::AssemblyFile; +static void generateAssembly(llvm::Module *module, + llvm::TargetMachine *targetMachine, + llvm::raw_pwrite_stream *out, bool emitObject) { + llvm::legacy::PassManager passes; - if (targetMachine->addPassesToEmitFile(passes, *out, nullptr, fileType)) { - llvm::errs() << "error: adding codegen passes failed\n"; - return; - } + passes.add(llvm::createVerifierPass()); + + llvm::CodeGenFileType fileType = emitObject + ? llvm::CodeGenFileType::ObjectFile + : llvm::CodeGenFileType::AssemblyFile; - passes.run(*module); + if (targetMachine->addPassesToEmitFile(passes, *out, nullptr, fileType)) { + llvm::errs() << "error: adding codegen passes failed\n"; + return; } - [[maybe_unused]] static std::string joinCmdArgs(llvm::ArrayRef args) - { - std::string s; - llvm::raw_string_ostream ss(s); - for (const llvm::StringRef &arg : args) { - if (&arg != args.begin()) { - ss << " "; - } - ss << arg; + passes.run(*module); +} + +[[maybe_unused]] static std::string +joinCmdArgs(llvm::ArrayRef args) { + std::string s; + llvm::raw_string_ostream ss(s); + for (const llvm::StringRef &arg : args) { + if (&arg != args.begin()) { + ss << " "; } - return s; + ss << arg; } + return s; +} - static bool generateBinary(llvm::Module *module, - llvm::TargetMachine *targetMachine, - llvm::Twine const &outputFilePath, - llvm::StringRef const &clangPath, - bool /*exceptions*/, - bool sharedLib, - bool debug, - llvm::ArrayRef arguments, - bool verbose) { - int fd; - PathString tempObj; - if (std::error_code ec = llvm::sys::fs::createUniqueFile("clayobj-%%%%%%%%.obj", fd, tempObj)) { - llvm::errs() << "error creating temporary object file: " << ec.message() << '\n'; - return false; - } - llvm::FileRemover removeTempObj(tempObj); +static bool generateBinary(llvm::Module *module, + llvm::TargetMachine *targetMachine, + llvm::Twine const &outputFilePath, + llvm::StringRef const &clangPath, + bool /*exceptions*/, bool sharedLib, bool debug, + llvm::ArrayRef arguments, bool verbose) { + int fd; + PathString tempObj; + if (std::error_code ec = llvm::sys::fs::createUniqueFile( + "clayobj-%%%%%%%%.obj", fd, tempObj)) { + llvm::errs() << "error creating temporary object file: " << ec.message() + << '\n'; + return false; + } + llvm::FileRemover removeTempObj(tempObj); - { - llvm::raw_fd_ostream objOut(fd, /*shouldClose=*/ true); + { + llvm::raw_fd_ostream objOut(fd, /*shouldClose=*/true); - generateAssembly(module, targetMachine, &objOut, true); - } + generateAssembly(module, targetMachine, &objOut, true); + } - string outputFilePathStr = outputFilePath.str(); + string outputFilePathStr = outputFilePath.str(); - std::vector clangArgs; - clangArgs.emplace_back(clangPath.data()); + std::vector clangArgs; + clangArgs.emplace_back(clangPath.data()); - switch (llvmDataLayout->getPointerSizeInBits()) { - case 32: - clangArgs.emplace_back("-m32"); - break; - case 64: - clangArgs.emplace_back("-m64"); - break; - default: - assert(false); - } + switch (llvmDataLayout->getPointerSizeInBits()) { + case 32: + clangArgs.emplace_back("-m32"); + break; + case 64: + clangArgs.emplace_back("-m64"); + break; + default: + assert(false); + } - llvm::Triple triple(llvmModule->getTargetTriple()); - if (sharedLib) { - clangArgs.emplace_back("-shared"); + llvm::Triple triple(llvmModule->getTargetTriple()); + if (sharedLib) { + clangArgs.emplace_back("-shared"); - if (triple.isOSWindows()) { - string linkerFlags; - PathString defPath; - outputFilePath.toVector(defPath); - llvm::sys::path::replace_extension(defPath, "def"); + if (triple.isOSWindows()) { + string linkerFlags; + PathString defPath; + outputFilePath.toVector(defPath); + llvm::sys::path::replace_extension(defPath, "def"); - linkerFlags = "-Wl,--output-def," + string(defPath.begin(), defPath.end()); + linkerFlags = + "-Wl,--output-def," + string(defPath.begin(), defPath.end()); - clangArgs.emplace_back(linkerFlags); - } - } - if (debug) { - if (triple.getOS() == llvm::Triple::Win32) - clangArgs.emplace_back("-Wl,/debug"); - } - clangArgs.emplace_back("-o"); - clangArgs.emplace_back(outputFilePathStr); - clangArgs.push_back(tempObj); - for (const auto & argument : arguments) - clangArgs.emplace_back(argument); - - if (verbose) { - llvm::errs() << "executing clang to generate binary:\n"; - llvm::errs() << " " << joinCmdArgs(clangArgs) << "\n"; + clangArgs.emplace_back(linkerFlags); } + } + if (debug) { + if (triple.getOS() == llvm::Triple::Win32) + clangArgs.emplace_back("-Wl,/debug"); + } + clangArgs.emplace_back("-o"); + clangArgs.emplace_back(outputFilePathStr); + clangArgs.push_back(tempObj); + for (const auto &argument : arguments) + clangArgs.emplace_back(argument); + + if (verbose) { + llvm::errs() << "executing clang to generate binary:\n"; + llvm::errs() << " " << joinCmdArgs(clangArgs) << "\n"; + } - int result = llvm::sys::ExecuteAndWait(clangPath, clangArgs); - - if (debug && triple.isOSDarwin()) { - llvm::ErrorOr dsymutilPathOrErr = llvm::sys::findProgramByName("dsymutil"); - if (std::error_code ec = dsymutilPathOrErr.getError()) - llvm::errs() << "error creating dsymutil: " << ec.message() << '\n'; + int result = llvm::sys::ExecuteAndWait(clangPath, clangArgs); - std::string dsymutilPath = dsymutilPathOrErr ? *dsymutilPathOrErr : ""; + if (debug && triple.isOSDarwin()) { + llvm::ErrorOr dsymutilPathOrErr = + llvm::sys::findProgramByName("dsymutil"); + if (std::error_code ec = dsymutilPathOrErr.getError()) + llvm::errs() << "error creating dsymutil: " << ec.message() << '\n'; - if (!dsymutilPath.empty()) { - string outputDSYMPath = outputFilePathStr; - outputDSYMPath.append(".dSYM"); + std::string dsymutilPath = dsymutilPathOrErr ? *dsymutilPathOrErr : ""; - std::vector dsymutilArgs; - dsymutilArgs.emplace_back(dsymutilPath); - dsymutilArgs.emplace_back("-o"); - dsymutilArgs.emplace_back(outputDSYMPath); - dsymutilArgs.emplace_back(outputFilePathStr); + if (!dsymutilPath.empty()) { + string outputDSYMPath = outputFilePathStr; + outputDSYMPath.append(".dSYM"); - if (verbose) { - llvm::errs() << "executing dsymutil:"; - llvm::errs() << " " << joinCmdArgs(dsymutilArgs) << "\n"; - } + std::vector dsymutilArgs; + dsymutilArgs.emplace_back(dsymutilPath); + dsymutilArgs.emplace_back("-o"); + dsymutilArgs.emplace_back(outputDSYMPath); + dsymutilArgs.emplace_back(outputFilePathStr); - int dsymResult = llvm::sys::ExecuteAndWait(dsymutilPath, dsymutilArgs); + if (verbose) { + llvm::errs() << "executing dsymutil:"; + llvm::errs() << " " << joinCmdArgs(dsymutilArgs) << "\n"; + } - if (dsymResult != 0) - llvm::errs() << "warning: dsymutil exited with error code " << dsymResult << "\n"; - } else - llvm::errs() << - "warning: unable to find dsymutil on the path; debug info for executable will not be generated\n"; - } + int dsymResult = + llvm::sys::ExecuteAndWait(dsymutilPath, dsymutilArgs); - return (result == 0); + if (dsymResult != 0) + llvm::errs() << "warning: dsymutil exited with error code " + << dsymResult << "\n"; + } else + llvm::errs() << "warning: unable to find dsymutil on the path; " + "debug info for executable will not be generated\n"; } - static void usage(const char *argv0) { - llvm::errs() << "usage: " << argv0 << " \n"; - llvm::errs() << " " << argv0 << " -e \n"; - llvm::errs() << "options:\n"; - llvm::errs() << " -o specify output file\n"; - llvm::errs() << " -target set target platform for code generation\n"; - llvm::errs() << " -mcpu set target CPU for code generation\n"; - llvm::errs() << " -mattr set target features for code generation\n" - << " use +feature to enable a feature\n" - << " or -feature to disable it\n" - << " for example, -mattr +feature1,-feature2\n"; - llvm::errs() << " -soft-float generate software floating point library calls\n"; - llvm::errs() << " -shared create a dynamically linkable library\n"; - llvm::errs() << " -emit-llvm emit llvm code\n"; - llvm::errs() << " -S emit assembler code\n"; - llvm::errs() << " -c emit object code\n"; - llvm::errs() << " -DFLAG[=value] set flag value\n" - << " (queryable with Flag?() and Flag())\n"; - llvm::errs() << " -O0 -O1 -O2 -O3 set optimization level\n"; - llvm::errs() << " (default -O2, or -O0 with -g)\n"; - llvm::errs() << " -g keep debug symbol information\n"; - llvm::errs() << " -exceptions enable exception handling\n"; - llvm::errs() << " -no-exceptions disable exception handling\n"; - llvm::errs() << " -inline inline procedures marked 'forceinline'\n"; - llvm::errs() << " and enable 'inline' hints (default)\n"; - llvm::errs() << " -no-inline ignore 'inline' and 'forceinline' keyword\n"; - llvm::errs() << " -import-externals include externals from imported modules\n" - << " in compilation unit\n" - << " (default when building standalone or -shared)\n"; - llvm::errs() << " -no-import-externals don't include externals from imported modules\n" - << " in compilation unit\n" - << " (default when building -c or -S)\n"; - llvm::errs() << " -pic generate position independent code\n"; - llvm::errs() << " -run execute the program without writing to disk\n"; - llvm::errs() << " -timing show timing information\n"; - llvm::errs() << " -verbose be verbose\n"; - llvm::errs() << " -full-match-errors show universal patterns in match failure errors\n"; - llvm::errs() << " -log-match \n" - << " log overload matching behavior for calls to \n" - << " in module \n"; + return (result == 0); +} + +static void usage(const char *argv0) { + llvm::errs() << "usage: " << argv0 << " \n"; + llvm::errs() << " " << argv0 << " -e \n"; + llvm::errs() << "options:\n"; + llvm::errs() << " -o specify output file\n"; + llvm::errs() + << " -target set target platform for code generation\n"; + llvm::errs() + << " -mcpu set target CPU for code generation\n"; + llvm::errs() + << " -mattr set target features for code generation\n" + << " use +feature to enable a feature\n" + << " or -feature to disable it\n" + << " for example, -mattr +feature1,-feature2\n"; + llvm::errs() << " -soft-float generate software floating point " + "library calls\n"; + llvm::errs() + << " -shared create a dynamically linkable library\n"; + llvm::errs() << " -emit-llvm emit llvm code\n"; + llvm::errs() << " -S emit assembler code\n"; + llvm::errs() << " -c emit object code\n"; + llvm::errs() + << " -DFLAG[=value] set flag value\n" + << " (queryable with Flag?() and Flag())\n"; + llvm::errs() << " -O0 -O1 -O2 -O3 set optimization level\n"; + llvm::errs() << " (default -O2, or -O0 with -g)\n"; + llvm::errs() << " -g keep debug symbol information\n"; + llvm::errs() << " -exceptions enable exception handling\n"; + llvm::errs() << " -no-exceptions disable exception handling\n"; + llvm::errs() + << " -inline inline procedures marked 'forceinline'\n"; + llvm::errs() + << " and enable 'inline' hints (default)\n"; + llvm::errs() << " -no-inline ignore 'inline' and 'forceinline' " + "keyword\n"; + llvm::errs() + << " -import-externals include externals from imported modules\n" + << " in compilation unit\n" + << " (default when building standalone or " + "-shared)\n"; + llvm::errs() + << " -no-import-externals don't include externals from imported " + "modules\n" + << " in compilation unit\n" + << " (default when building -c or -S)\n"; + llvm::errs() + << " -pic generate position independent code\n"; + llvm::errs() << " -run execute the program without " + "writing to disk\n"; + llvm::errs() << " -timing show timing information\n"; + llvm::errs() << " -verbose be verbose\n"; + llvm::errs() << " -full-match-errors show universal patterns in match " + "failure errors\n"; + llvm::errs() << " -log-match \n" + << " log overload matching behavior " + "for calls to \n" + << " in module \n"; #ifdef __APPLE__ - llvm::errs() << " -arch build for Darwin architecture \n"; - llvm::errs() << " -F add to framework search path\n"; - llvm::errs() << " -framework link with framework \n"; + llvm::errs() + << " -arch build for Darwin architecture \n"; + llvm::errs() + << " -F add to framework search path\n"; + llvm::errs() << " -framework link with framework \n"; #endif - llvm::errs() << " -L add to library search path\n"; - llvm::errs() << " -Wl, pass flags to linker\n"; - llvm::errs() << " -l link with library \n"; - llvm::errs() << " -I add to clay module search path\n"; - llvm::errs() << " -deps keep track of the dependencies of the currently\n"; - llvm::errs() << " compiling file and write them to the file\n"; - llvm::errs() << " specified by -o-deps\n"; - llvm::errs() << " -no-deps don't generate dependencies file\n"; - llvm::errs() << " -o-deps write the dependencies to this file\n"; - llvm::errs() << " (defaults to .d)\n"; - llvm::errs() << " -e compile and run (implies -run)\n"; - llvm::errs() << " -M \"import .*;\" for -e\n"; - llvm::errs() << " -version display version info\n"; - - llvm::errs() << " -final-overloads enable final overloads (temporary option)\n"; - } + llvm::errs() + << " -L add to library search path\n"; + llvm::errs() << " -Wl, pass flags to linker\n"; + llvm::errs() << " -l link with library \n"; + llvm::errs() + << " -I add to clay module search path\n"; + llvm::errs() << " -deps keep track of the dependencies of " + "the currently\n"; + llvm::errs() << " compiling file and write them to " + "the file\n"; + llvm::errs() << " specified by -o-deps\n"; + llvm::errs() + << " -no-deps don't generate dependencies file\n"; + llvm::errs() + << " -o-deps write the dependencies to this file\n"; + llvm::errs() << " (defaults to .d)\n"; + llvm::errs() + << " -e compile and run (implies -run)\n"; + llvm::errs() << " -M \"import .*;\" for -e\n"; + llvm::errs() << " -version display version info\n"; + + llvm::errs() << " -final-overloads enable final overloads (temporary " + "option)\n"; +} - static string sharedExtensionForTarget(llvm::Triple const &triple) { - if (triple.isOSWindows()) { - return ".dll"; - } - if (triple.isOSDarwin()) { - return ".dylib"; - } - return ".so"; +static string sharedExtensionForTarget(llvm::Triple const &triple) { + if (triple.isOSWindows()) { + return ".dll"; + } + if (triple.isOSDarwin()) { + return ".dylib"; } + return ".so"; +} - static string objExtensionForTarget(llvm::Triple const &triple) { - if (triple.isOSWindows()) { - return ".obj"; - } - return ".o"; +static string objExtensionForTarget(llvm::Triple const &triple) { + if (triple.isOSWindows()) { + return ".obj"; } + return ".o"; +} - static string exeExtensionForTarget(llvm::Triple const &triple) { - if (triple.isOSWindows()) { - return ".exe"; - } - return ""; +static string exeExtensionForTarget(llvm::Triple const &triple) { + if (triple.isOSWindows()) { + return ".exe"; } + return ""; +} - static void printVersion() { - llvm::errs() << "clay compiler version " CLAY_COMPILER_VERSION - ", language version " CLAY_LANGUAGE_VERSION " (" +static void printVersion() { + llvm::errs() << "clay compiler version " CLAY_COMPILER_VERSION + ", language version " CLAY_LANGUAGE_VERSION " (" #ifdef GIT_ID - << "git id " << GIT_ID << ", " + << "git id " << GIT_ID << ", " #endif #ifdef HG_ID - << "hg id " << HG_ID << ", " + << "hg id " << HG_ID << ", " #endif #ifdef SVN_REVISION - << "llvm r" << SVN_REVISION << ", " + << "llvm r" << SVN_REVISION << ", " #endif - << __DATE__ << ")\n"; - } + << __DATE__ << ")\n"; +} - int main2(int argc, char **argv, char const *const*envp) { - if (argc == 1) { - usage(argv[0]); - return 2; - } +int main2(int argc, char **argv, char const *const *envp) { + if (argc == 1) { + usage(argv[0]); + return 2; + } - bool emitLLVM = false; - bool emitAsm = false; - bool emitObject = false; - bool sharedLib = false; - bool genPIC = false; - bool inlineEnabled = true; - bool exceptions = true; - bool run = false; - bool repl = false; - bool verbose = false; - bool crossCompiling = false; - bool showTiming = false; - bool codegenExternals = false; - bool codegenExternalsSet = false; - - bool generateDeps = false; - - unsigned optLevel = 2; - bool optLevelSet = false; - - bool finalOverloadsEnabled = false; - bool softFloat = false; + bool emitLLVM = false; + bool emitAsm = false; + bool emitObject = false; + bool sharedLib = false; + bool genPIC = false; + bool inlineEnabled = true; + bool exceptions = true; + bool run = false; + bool repl = false; + bool verbose = false; + bool crossCompiling = false; + bool showTiming = false; + bool codegenExternals = false; + bool codegenExternalsSet = false; + + bool generateDeps = false; + + unsigned optLevel = 2; + bool optLevelSet = false; + + bool finalOverloadsEnabled = false; + bool softFloat = false; #ifdef __APPLE__ - genPIC = true; + genPIC = true; - string arch; + string arch; #endif - string clayFile; - string outputFile; - string targetTriple = llvm::sys::getDefaultTargetTriple(); + string clayFile; + string outputFile; + string targetTriple = llvm::sys::getDefaultTargetTriple(); - string targetCPU; - string targetFeatures; + string targetCPU; + string targetFeatures; - string clayScriptImports; - string clayScript; + string clayScriptImports; + string clayScript; - vector libSearchPathArgs; - vector libSearchPath; - string linkerFlags; - vector librariesArgs; - vector libraries; - vector searchPath; + vector libSearchPathArgs; + vector libSearchPath; + string linkerFlags; + vector librariesArgs; + vector libraries; + vector searchPath; - string dependenciesOutputFile; + string dependenciesOutputFile; #ifdef __APPLE__ - vector frameworkSearchPath; - vector frameworks; + vector frameworkSearchPath; + vector frameworks; #endif - bool debug = false; - - for (int i = 1; i < argc; ++i) { - if ((strcmp(argv[i], "-shared") == 0)) { - sharedLib = true; - } else if (strcmp(argv[i], "-emit-llvm") == 0) { - emitLLVM = true; - } else if (strcmp(argv[i], "-S") == 0) { - emitAsm = true; - } else if (strcmp(argv[i], "-c") == 0) { - emitObject = true; - } else if (strcmp(argv[i], "-g") == 0) { - debug = true; - if (!optLevelSet) - optLevel = 0; - } else if (strcmp(argv[i], "-O0") == 0) { + bool debug = false; + + for (int i = 1; i < argc; ++i) { + if ((strcmp(argv[i], "-shared") == 0)) { + sharedLib = true; + } else if (strcmp(argv[i], "-emit-llvm") == 0) { + emitLLVM = true; + } else if (strcmp(argv[i], "-S") == 0) { + emitAsm = true; + } else if (strcmp(argv[i], "-c") == 0) { + emitObject = true; + } else if (strcmp(argv[i], "-g") == 0) { + debug = true; + if (!optLevelSet) optLevel = 0; - optLevelSet = true; - } else if (strcmp(argv[i], "-O1") == 0) { - optLevel = 1; - optLevelSet = true; - } else if (strcmp(argv[i], "-O2") == 0) { - optLevel = 2; - optLevelSet = true; - } else if (strcmp(argv[i], "-O3") == 0) { - optLevel = 3; - optLevelSet = true; - } else if (strcmp(argv[i], "-inline") == 0) { - inlineEnabled = true; - } else if (strcmp(argv[i], "-no-inline") == 0) { - inlineEnabled = false; - } else if (strcmp(argv[i], "-exceptions") == 0) { - exceptions = true; - } else if (strcmp(argv[i], "-no-exceptions") == 0) { - exceptions = false; - } else if (strcmp(argv[i], "-pic") == 0) { - genPIC = true; - } else if (strcmp(argv[i], "-verbose") == 0 || strcmp(argv[i], "-v") == 0) { - verbose = true; - } else if (strcmp(argv[i], "-run") == 0) { - run = true; - } else if (strcmp(argv[i], "-repl") == 0) { - repl = true; - } else if (strcmp(argv[i], "-timing") == 0) { - showTiming = true; - } else if (strcmp(argv[i], "-full-match-errors") == 0) { - shouldPrintFullMatchErrors = true; - } else if (strcmp(argv[i], "-log-match") == 0) { - if (i + 1 == argc) { - llvm::errs() << "error: symbol name missing after -log-match\n"; - return 1; - } - ++i; - char const *dot = strrchr(argv[i], '.'); - if (dot == nullptr) { - logMatchSymbols.insert(make_pair(string("*"), argv[i])); - } else { - logMatchSymbols.insert(make_pair(string(static_cast(argv[i]), dot), string(dot + 1))); - } - } else if (strcmp(argv[i], "-e") == 0) { - if (i + 1 == argc) { - llvm::errs() << "error: source string missing after -e\n"; - return 1; - } - ++i; - run = true; - clayScript += argv[i]; - clayScript += "\n"; - } else if (strncmp(argv[i], "-M", 2) == 0) { - string modulespec = argv[i] + 2; - if (modulespec.empty()) { - llvm::errs() << "error: module missing after -M\n"; - return 1; - } - clayScriptImports += "import " + modulespec + ".*; "; - } else if (strcmp(argv[i], "-o") == 0) { - ++i; - if (i == argc) { - llvm::errs() << "error: filename missing after -o\n"; - return 1; - } - if (!outputFile.empty()) { - llvm::errs() << "error: output file already specified: " - << outputFile - << ", specified again as " << argv[i] << '\n'; - return 1; - } - outputFile = argv[i]; + } else if (strcmp(argv[i], "-O0") == 0) { + optLevel = 0; + optLevelSet = true; + } else if (strcmp(argv[i], "-O1") == 0) { + optLevel = 1; + optLevelSet = true; + } else if (strcmp(argv[i], "-O2") == 0) { + optLevel = 2; + optLevelSet = true; + } else if (strcmp(argv[i], "-O3") == 0) { + optLevel = 3; + optLevelSet = true; + } else if (strcmp(argv[i], "-inline") == 0) { + inlineEnabled = true; + } else if (strcmp(argv[i], "-no-inline") == 0) { + inlineEnabled = false; + } else if (strcmp(argv[i], "-exceptions") == 0) { + exceptions = true; + } else if (strcmp(argv[i], "-no-exceptions") == 0) { + exceptions = false; + } else if (strcmp(argv[i], "-pic") == 0) { + genPIC = true; + } else if (strcmp(argv[i], "-verbose") == 0 || + strcmp(argv[i], "-v") == 0) { + verbose = true; + } else if (strcmp(argv[i], "-run") == 0) { + run = true; + } else if (strcmp(argv[i], "-repl") == 0) { + repl = true; + } else if (strcmp(argv[i], "-timing") == 0) { + showTiming = true; + } else if (strcmp(argv[i], "-full-match-errors") == 0) { + shouldPrintFullMatchErrors = true; + } else if (strcmp(argv[i], "-log-match") == 0) { + if (i + 1 == argc) { + llvm::errs() << "error: symbol name missing after -log-match\n"; + return 1; } + ++i; + char const *dot = strrchr(argv[i], '.'); + if (dot == nullptr) { + logMatchSymbols.insert(make_pair(string("*"), argv[i])); + } else { + logMatchSymbols.insert( + make_pair(string(static_cast(argv[i]), dot), + string(dot + 1))); + } + } else if (strcmp(argv[i], "-e") == 0) { + if (i + 1 == argc) { + llvm::errs() << "error: source string missing after -e\n"; + return 1; + } + ++i; + run = true; + clayScript += argv[i]; + clayScript += "\n"; + } else if (strncmp(argv[i], "-M", 2) == 0) { + string modulespec = argv[i] + 2; + if (modulespec.empty()) { + llvm::errs() << "error: module missing after -M\n"; + return 1; + } + clayScriptImports += "import " + modulespec + ".*; "; + } else if (strcmp(argv[i], "-o") == 0) { + ++i; + if (i == argc) { + llvm::errs() << "error: filename missing after -o\n"; + return 1; + } + if (!outputFile.empty()) { + llvm::errs() + << "error: output file already specified: " << outputFile + << ", specified again as " << argv[i] << '\n'; + return 1; + } + outputFile = argv[i]; + } #ifdef __APPLE__ - else if (strstr(argv[i], "-F") == argv[i]) { - string frameworkDir = argv[i] + strlen("-F"); - if (frameworkDir.empty()) { - if (i + 1 == argc) { - llvm::errs() << "error: directory missing after -F\n"; - return 1; - } - ++i; - frameworkDir = argv[i]; - if (frameworkDir.empty() || (frameworkDir[0] == '-')) { - llvm::errs() << "error: directory missing after -F\n"; - return 1; - } - } - frameworkSearchPath.push_back("-F" + frameworkDir); - } else if (strcmp(argv[i], "-framework") == 0) { - if (i + 1 == argc) { - llvm::errs() << "error: framework name missing after -framework\n"; - return 1; - } - ++i; - string framework = argv[i]; - if (framework.empty() || (framework[0] == '-')) { - llvm::errs() << "error: framework name missing after -framework\n"; - return 1; - } - frameworks.emplace_back("-framework"); - frameworks.push_back(framework); - } else if (strcmp(argv[i], "-arch") == 0) { + else if (strstr(argv[i], "-F") == argv[i]) { + string frameworkDir = argv[i] + strlen("-F"); + if (frameworkDir.empty()) { if (i + 1 == argc) { - llvm::errs() << "error: architecture name missing after -arch\n"; + llvm::errs() << "error: directory missing after -F\n"; return 1; } ++i; - if (!arch.empty()) { - llvm::errs() << "error: multiple -arch flags currently unsupported\n"; - return 1; - } - arch = argv[i]; - if (arch.empty() || (arch[0] == '-')) { - llvm::errs() << "error: architecture name missing after -arch\n"; + frameworkDir = argv[i]; + if (frameworkDir.empty() || (frameworkDir[0] == '-')) { + llvm::errs() << "error: directory missing after -F\n"; return 1; } + } + frameworkSearchPath.push_back("-F" + frameworkDir); + } else if (strcmp(argv[i], "-framework") == 0) { + if (i + 1 == argc) { + llvm::errs() + << "error: framework name missing after -framework\n"; + return 1; + } + ++i; + string framework = argv[i]; + if (framework.empty() || (framework[0] == '-')) { + llvm::errs() + << "error: framework name missing after -framework\n"; + return 1; + } + frameworks.emplace_back("-framework"); + frameworks.push_back(framework); + } else if (strcmp(argv[i], "-arch") == 0) { + if (i + 1 == argc) { + llvm::errs() + << "error: architecture name missing after -arch\n"; + return 1; + } + ++i; + if (!arch.empty()) { + llvm::errs() + << "error: multiple -arch flags currently unsupported\n"; + return 1; + } + arch = argv[i]; + if (arch.empty() || (arch[0] == '-')) { + llvm::errs() + << "error: architecture name missing after -arch\n"; + return 1; + } - if (arch == "i386") { - targetTriple = "i386-apple-darwin10"; - } else if (arch == "x86_64") { - targetTriple = "x86_64-apple-darwin10"; - } else if (arch == "ppc") { - targetTriple = "powerpc-apple-darwin10"; - } else if (arch == "ppc64") { - targetTriple = "powerpc64-apple-darwin10"; - } else if (arch == "armv6") { - targetTriple = "armv6-apple-darwin4.1-iphoneos"; - } else if (arch == "armv7") { - targetTriple = "thumbv7-apple-darwin4.1-iphoneos"; - } else { - llvm::errs() << "error: unrecognized -arch value " << arch << "\n"; - return 1; - } + if (arch == "i386") { + targetTriple = "i386-apple-darwin10"; + } else if (arch == "x86_64") { + targetTriple = "x86_64-apple-darwin10"; + } else if (arch == "ppc") { + targetTriple = "powerpc-apple-darwin10"; + } else if (arch == "ppc64") { + targetTriple = "powerpc64-apple-darwin10"; + } else if (arch == "armv6") { + targetTriple = "armv6-apple-darwin4.1-iphoneos"; + } else if (arch == "armv7") { + targetTriple = "thumbv7-apple-darwin4.1-iphoneos"; + } else { + llvm::errs() + << "error: unrecognized -arch value " << arch << "\n"; + return 1; } + } #endif - else if (strcmp(argv[i], "-target") == 0) { + else if (strcmp(argv[i], "-target") == 0) { + if (i + 1 == argc) { + llvm::errs() << "error: target name missing after -target\n"; + return 1; + } + ++i; + targetTriple = argv[i]; + if (targetTriple.empty() || (targetTriple[0] == '-')) { + llvm::errs() << "error: target name missing after -target\n"; + return 1; + } + crossCompiling = + targetTriple != llvm::sys::getDefaultTargetTriple(); + } else if (strcmp(argv[i], "-mcpu") == 0) { + if (i + 1 == argc) { + llvm::errs() << "error: CPU name missing after -mcpu\n"; + return 1; + } + ++i; + targetCPU = argv[i]; + if (targetCPU.empty() || (targetCPU[0] == '-')) { + llvm::errs() << "error: CPU name missing after -mcpu\n"; + return 1; + } + } else if (strcmp(argv[i], "-mattr") == 0) { + if (i + 1 == argc) { + llvm::errs() << "error: features missing after -mattr\n"; + return 1; + } + ++i; + targetFeatures = argv[i]; + if (targetFeatures.empty() || (targetFeatures[0] == '-')) { + llvm::errs() << "error: features missing after -mattr\n"; + return 1; + } + } else if (strcmp(argv[i], "-soft-float") == 0) { + softFloat = true; + } else if (strstr(argv[i], "-Wl") == argv[i]) { + linkerFlags += argv[i] + strlen("-Wl"); + } else if (strstr(argv[i], "-L") == argv[i]) { + string libDir = argv[i] + strlen("-L"); + if (libDir.empty()) { if (i + 1 == argc) { - llvm::errs() << "error: target name missing after -target\n"; + llvm::errs() << "error: directory missing after -L\n"; return 1; } ++i; - targetTriple = argv[i]; - if (targetTriple.empty() || (targetTriple[0] == '-')) { - llvm::errs() << "error: target name missing after -target\n"; + libDir = argv[i]; + if (libDir.empty() || (libDir[0] == '-')) { + llvm::errs() << "error: directory missing after -L\n"; return 1; } - crossCompiling = targetTriple != llvm::sys::getDefaultTargetTriple(); - } else if (strcmp(argv[i], "-mcpu") == 0) { + } + libSearchPath.push_back(libDir); + libSearchPathArgs.push_back("-L" + libDir); + } else if (strstr(argv[i], "-l") == argv[i]) { + string lib = argv[i] + strlen("-l"); + if (lib.empty()) { if (i + 1 == argc) { - llvm::errs() << "error: CPU name missing after -mcpu\n"; + llvm::errs() << "error: library missing after -l\n"; return 1; } ++i; - targetCPU = argv[i]; - if (targetCPU.empty() || (targetCPU[0] == '-')) { - llvm::errs() << "error: CPU name missing after -mcpu\n"; + lib = argv[i]; + if (lib.empty() || (lib[0] == '-')) { + llvm::errs() << "error: library missing after -l\n"; return 1; } - } else if (strcmp(argv[i], "-mattr") == 0) { + } + libraries.push_back(lib); + librariesArgs.push_back("-l" + lib); + } else if (strstr(argv[i], "-D") == argv[i]) { + char *namep = argv[i] + strlen("-D"); + if (namep[0] == '\0') { if (i + 1 == argc) { - llvm::errs() << "error: features missing after -mattr\n"; + llvm::errs() << "error: definition missing after -D\n"; return 1; } ++i; - targetFeatures = argv[i]; - if (targetFeatures.empty() || (targetFeatures[0] == '-')) { - llvm::errs() << "error: features missing after -mattr\n"; + namep = argv[i]; + if (namep[0] == '\0' || namep[0] == '-') { + llvm::errs() << "error: definition missing after -D\n"; return 1; } - } else if (strcmp(argv[i], "-soft-float") == 0) { - softFloat = true; - } else if (strstr(argv[i], "-Wl") == argv[i]) { - linkerFlags += argv[i] + strlen("-Wl"); - } else if (strstr(argv[i], "-L") == argv[i]) { - string libDir = argv[i] + strlen("-L"); - if (libDir.empty()) { - if (i + 1 == argc) { - llvm::errs() << "error: directory missing after -L\n"; - return 1; - } - ++i; - libDir = argv[i]; - if (libDir.empty() || (libDir[0] == '-')) { - llvm::errs() << "error: directory missing after -L\n"; - return 1; - } - } - libSearchPath.push_back(libDir); - libSearchPathArgs.push_back("-L" + libDir); - } else if (strstr(argv[i], "-l") == argv[i]) { - string lib = argv[i] + strlen("-l"); - if (lib.empty()) { - if (i + 1 == argc) { - llvm::errs() << "error: library missing after -l\n"; - return 1; - } - ++i; - lib = argv[i]; - if (lib.empty() || (lib[0] == '-')) { - llvm::errs() << "error: library missing after -l\n"; - return 1; - } - } - libraries.push_back(lib); - librariesArgs.push_back("-l" + lib); - } else if (strstr(argv[i], "-D") == argv[i]) { - char *namep = argv[i] + strlen("-D"); - if (namep[0] == '\0') { - if (i + 1 == argc) { - llvm::errs() << "error: definition missing after -D\n"; - return 1; - } - ++i; - namep = argv[i]; - if (namep[0] == '\0' || namep[0] == '-') { - llvm::errs() << "error: definition missing after -D\n"; - return 1; - } - } - char *equalSignp = strchr(namep, '='); - string name = equalSignp == nullptr - ? string(namep) - : string(namep, equalSignp); - string value = equalSignp == nullptr - ? string() - : string(equalSignp + 1); - - globalFlags[name] = value; - } else if (strstr(argv[i], "-I") == argv[i]) { - string path = argv[i] + strlen("-I"); - if (path.empty()) { - if (i + 1 == argc) { - llvm::errs() << "error: path missing after -I\n"; - return 1; - } - ++i; - path = argv[i]; - if (path.empty() || (path[0] == '-')) { - llvm::errs() << "error: path missing after -I\n"; - return 1; - } - } - searchPath.emplace_back(path); - } else if (strstr(argv[i], "-version") == argv[i] - || strcmp(argv[i], "--version") == 0) { - printVersion(); - return 0; - } else if (strcmp(argv[i], "-import-externals") == 0) { - codegenExternals = true; - codegenExternalsSet = true; - } else if (strcmp(argv[i], "-no-import-externals") == 0) { - codegenExternals = false; - codegenExternalsSet = true; - } else if (strcmp(argv[i], "-deps") == 0) { - generateDeps = true; - } else if (strcmp(argv[i], "-no-deps") == 0) { - generateDeps = false; - } else if (strcmp(argv[i], "-o-deps") == 0) { - ++i; - if (i == argc) { - llvm::errs() << "error: filename missing after -o-deps\n"; - return 1; - } - if (!dependenciesOutputFile.empty()) { - llvm::errs() << "error: dependencies output file already specified: " - << dependenciesOutputFile - << ", specified again as " << argv[i] << '\n'; + } + char *equalSignp = strchr(namep, '='); + string name = equalSignp == nullptr ? string(namep) + : string(namep, equalSignp); + string value = + equalSignp == nullptr ? string() : string(equalSignp + 1); + + globalFlags[name] = value; + } else if (strstr(argv[i], "-I") == argv[i]) { + string path = argv[i] + strlen("-I"); + if (path.empty()) { + if (i + 1 == argc) { + llvm::errs() << "error: path missing after -I\n"; return 1; } - dependenciesOutputFile = argv[i]; - } else if (strcmp(argv[i], "--") == 0) { ++i; - if (clayFile.empty()) { - if (i != argc - 1) { - llvm::errs() << "error: clay file already specified: " << argv[i] - << ", unrecognized parameter: " << argv[i + 1] << '\n'; - return 1; - } - clayFile = argv[i]; - } else { - if (i != argc) { - llvm::errs() << "error: clay file already specified: " << clayFile - << ", unrecognized parameter: " << argv[i] << '\n'; - return 1; - } - } - } else if (strcmp(argv[i], "-help") == 0 - || strcmp(argv[i], "--help") == 0 - || strcmp(argv[i], "/?") == 0) { - usage(argv[0]); - return 2; - } else if (strstr(argv[i], "-") != argv[i]) { - if (!clayFile.empty()) { - llvm::errs() << "error: clay file already specified: " << clayFile - << ", unrecognized parameter: " << argv[i] << '\n'; + path = argv[i]; + if (path.empty() || (path[0] == '-')) { + llvm::errs() << "error: path missing after -I\n"; return 1; } - clayFile = argv[i]; - } else if (strcmp(argv[i], "-final-overloads") == 0) { - finalOverloadsEnabled = true; - } else { - llvm::errs() << "error: unrecognized option " << argv[i] << '\n'; - return 1; } - } - - if (verbose) { + searchPath.emplace_back(path); + } else if (strstr(argv[i], "-version") == argv[i] || + strcmp(argv[i], "--version") == 0) { printVersion(); - } - - if (repl && clayScript.empty() && clayFile.empty()) { - clayScript = "/*empty module if file not specified*/"; - } else { - if (clayScript.empty() && clayFile.empty()) { - llvm::errs() << "error: clay file not specified\n"; + return 0; + } else if (strcmp(argv[i], "-import-externals") == 0) { + codegenExternals = true; + codegenExternalsSet = true; + } else if (strcmp(argv[i], "-no-import-externals") == 0) { + codegenExternals = false; + codegenExternalsSet = true; + } else if (strcmp(argv[i], "-deps") == 0) { + generateDeps = true; + } else if (strcmp(argv[i], "-no-deps") == 0) { + generateDeps = false; + } else if (strcmp(argv[i], "-o-deps") == 0) { + ++i; + if (i == argc) { + llvm::errs() << "error: filename missing after -o-deps\n"; + return 1; + } + if (!dependenciesOutputFile.empty()) { + llvm::errs() + << "error: dependencies output file already specified: " + << dependenciesOutputFile << ", specified again as " + << argv[i] << '\n'; return 1; } - if (!clayScript.empty() && !clayFile.empty()) { - llvm::errs() << "error: -e cannot be specified with input file\n"; + dependenciesOutputFile = argv[i]; + } else if (strcmp(argv[i], "--") == 0) { + ++i; + if (clayFile.empty()) { + if (i != argc - 1) { + llvm::errs() + << "error: clay file already specified: " << argv[i] + << ", unrecognized parameter: " << argv[i + 1] << '\n'; + return 1; + } + clayFile = argv[i]; + } else { + if (i != argc) { + llvm::errs() + << "error: clay file already specified: " << clayFile + << ", unrecognized parameter: " << argv[i] << '\n'; + return 1; + } + } + } else if (strcmp(argv[i], "-help") == 0 || + strcmp(argv[i], "--help") == 0 || + strcmp(argv[i], "/?") == 0) { + usage(argv[0]); + return 2; + } else if (strstr(argv[i], "-") != argv[i]) { + if (!clayFile.empty()) { + llvm::errs() + << "error: clay file already specified: " << clayFile + << ", unrecognized parameter: " << argv[i] << '\n'; return 1; } + clayFile = argv[i]; + } else if (strcmp(argv[i], "-final-overloads") == 0) { + finalOverloadsEnabled = true; + } else { + llvm::errs() << "error: unrecognized option " << argv[i] << '\n'; + return 1; } + } - if (!clayScriptImports.empty() && clayScript.empty()) { - llvm::errs() << "error: -M specified without -e\n"; - } + if (verbose) { + printVersion(); + } - if (emitAsm && emitObject) { - llvm::errs() << "error: -S or -c cannot be used together\n"; + if (repl && clayScript.empty() && clayFile.empty()) { + clayScript = "/*empty module if file not specified*/"; + } else { + if (clayScript.empty() && clayFile.empty()) { + llvm::errs() << "error: clay file not specified\n"; return 1; } - - if (crossCompiling && run) { - llvm::errs() << "error: cannot use -run when cross compiling\n"; + if (!clayScript.empty() && !clayFile.empty()) { + llvm::errs() << "error: -e cannot be specified with input file\n"; return 1; } + } + + if (!clayScriptImports.empty() && clayScript.empty()) { + llvm::errs() << "error: -M specified without -e\n"; + } + + if (emitAsm && emitObject) { + llvm::errs() << "error: -S or -c cannot be used together\n"; + return 1; + } + + if (crossCompiling && run) { + llvm::errs() << "error: cannot use -run when cross compiling\n"; + return 1; + } - if (crossCompiling && !(emitLLVM || emitAsm || emitObject) + if (crossCompiling && !(emitLLVM || emitAsm || emitObject) #ifdef __APPLE__ - && arch.empty() + && arch.empty() #endif - ) { - llvm::errs() << "error: must use -emit-llvm, -S, or -c when cross compiling\n"; - return 1; - } + ) { + llvm::errs() + << "error: must use -emit-llvm, -S, or -c when cross compiling\n"; + return 1; + } - if (!codegenExternalsSet) - codegenExternals = !(emitLLVM || emitAsm || emitObject); + if (!codegenExternalsSet) + codegenExternals = !(emitLLVM || emitAsm || emitObject); - if ((emitLLVM || emitAsm || emitObject) && run) - run = false; + if ((emitLLVM || emitAsm || emitObject) && run) + run = false; - setInlineEnabled(inlineEnabled); - setExceptionsEnabled(exceptions); + setInlineEnabled(inlineEnabled); + setExceptionsEnabled(exceptions); - setFinalOverloadsEnabled(finalOverloadsEnabled); + setFinalOverloadsEnabled(finalOverloadsEnabled); - llvm::Triple llvmTriple(targetTriple); - targetTriple = llvmTriple.str(); + llvm::Triple llvmTriple(targetTriple); + targetTriple = llvmTriple.str(); - std::string moduleName = clayScript.empty() ? clayFile : "-e"; + std::string moduleName = clayScript.empty() ? clayFile : "-e"; - llvm::TargetMachine *targetMachine = initLLVM(targetTriple, - targetCPU, targetFeatures, softFloat, moduleName, "", - (sharedLib || genPIC), debug, optLevel); - if (targetMachine == nullptr) { - llvm::errs() << "error: unable to initialize LLVM for target " << targetTriple << "\n"; - return 1; - } + llvm::TargetMachine *targetMachine = + initLLVM(targetTriple, targetCPU, targetFeatures, softFloat, moduleName, + "", (sharedLib || genPIC), debug, optLevel); + if (targetMachine == nullptr) { + llvm::errs() << "error: unable to initialize LLVM for target " + << targetTriple << "\n"; + return 1; + } - initTypes(); - initExternalTarget(targetTriple); - - // Try environment variables first - if (char *libclayPath = getenv("CLAY_PATH")) { - // Parse the environment variable - // Format expected is standard PATH form, i.e. - // CLAY_PATH=path1:path2:path3 (on Unix) - // CLAY_PATH=path1;path2;path3 (on Windows) - char *begin = libclayPath; - char *end; - do { - end = begin; - while (*end && (*end != ENV_SEPARATOR)) - ++end; - searchPath.emplace_back(llvm::StringRef(begin, static_cast(end - begin))); - begin = end + 1; - } while (*end); - } - // Add the relative path from the executable - PathString clayExe(llvm::sys::fs::getMainExecutable(argv[0], reinterpret_cast(&usage))); - llvm::StringRef clayDir = llvm::sys::path::parent_path(clayExe); + initTypes(); + initExternalTarget(targetTriple); + + // Try environment variables first + if (char *libclayPath = getenv("CLAY_PATH")) { + // Parse the environment variable + // Format expected is standard PATH form, i.e. + // CLAY_PATH=path1:path2:path3 (on Unix) + // CLAY_PATH=path1;path2;path3 (on Windows) + char *begin = libclayPath; + char *end; + do { + end = begin; + while (*end && (*end != ENV_SEPARATOR)) + ++end; + searchPath.emplace_back( + llvm::StringRef(begin, static_cast(end - begin))); + begin = end + 1; + } while (*end); + } + // Add the relative path from the executable + PathString clayExe(llvm::sys::fs::getMainExecutable( + argv[0], reinterpret_cast(&usage))); + llvm::StringRef clayDir = llvm::sys::path::parent_path(clayExe); - PathString libDirDevelopment(clayDir); - PathString libDirProduction1(clayDir); - PathString libDirProduction2(clayDir); + PathString libDirDevelopment(clayDir); + PathString libDirProduction1(clayDir); + PathString libDirProduction2(clayDir); - llvm::sys::path::append(libDirDevelopment, "../../lib-clay"); - llvm::sys::path::append(libDirProduction1, "../lib/lib-clay"); - llvm::sys::path::append(libDirProduction2, "lib-clay"); + llvm::sys::path::append(libDirDevelopment, "../../lib-clay"); + llvm::sys::path::append(libDirProduction1, "../lib/lib-clay"); + llvm::sys::path::append(libDirProduction2, "lib-clay"); - searchPath.push_back(libDirDevelopment); - searchPath.push_back(libDirProduction1); - searchPath.push_back(libDirProduction2); - searchPath.emplace_back("."); + searchPath.push_back(libDirDevelopment); + searchPath.push_back(libDirProduction1); + searchPath.push_back(libDirProduction2); + searchPath.emplace_back("."); - if (verbose) { - llvm::errs() << "using search path:\n"; + if (verbose) { + llvm::errs() << "using search path:\n"; - for (const auto & it : searchPath) { - llvm::errs() << " " << it << "\n"; - } + for (const auto &it : searchPath) { + llvm::errs() << " " << it << "\n"; } + } - setSearchPath(searchPath); - - if (outputFile.empty()) { - llvm::StringRef clayFileBasename = llvm::sys::path::stem(clayFile); - outputFile = string(clayFileBasename.begin(), clayFileBasename.end()); - - if (emitLLVM && emitAsm) - outputFile += ".ll"; - else if (emitAsm) - outputFile += ".s"; - else if (emitObject || emitLLVM) - outputFile += objExtensionForTarget(llvmTriple); - else if (sharedLib) - outputFile += sharedExtensionForTarget(llvmTriple); - else - outputFile += exeExtensionForTarget(llvmTriple); - } - if (!run) { - bool isDir; - if (!llvm::sys::fs::is_directory(outputFile, isDir) && isDir) { - llvm::errs() << "error: output file '" << outputFile << "' is a directory\n"; - return 1; - } - llvm::sys::RemoveFileOnSignal(outputFile); + setSearchPath(searchPath); + + if (outputFile.empty()) { + llvm::StringRef clayFileBasename = llvm::sys::path::stem(clayFile); + outputFile = string(clayFileBasename.begin(), clayFileBasename.end()); + + if (emitLLVM && emitAsm) + outputFile += ".ll"; + else if (emitAsm) + outputFile += ".s"; + else if (emitObject || emitLLVM) + outputFile += objExtensionForTarget(llvmTriple); + else if (sharedLib) + outputFile += sharedExtensionForTarget(llvmTriple); + else + outputFile += exeExtensionForTarget(llvmTriple); + } + if (!run) { + bool isDir; + if (!llvm::sys::fs::is_directory(outputFile, isDir) && isDir) { + llvm::errs() << "error: output file '" << outputFile + << "' is a directory\n"; + return 1; } + llvm::sys::RemoveFileOnSignal(outputFile); + } - if (generateDeps) { - if (run) { - llvm::errs() << "error: '-deps' can not be used together with '-e' or '-run'\n"; - return 1; - } - if (dependenciesOutputFile.empty()) { - dependenciesOutputFile = outputFile; - dependenciesOutputFile += ".d"; - } + if (generateDeps) { + if (run) { + llvm::errs() << "error: '-deps' can not be used together with '-e' " + "or '-run'\n"; + return 1; } + if (dependenciesOutputFile.empty()) { + dependenciesOutputFile = outputFile; + dependenciesOutputFile += ".d"; + } + } - if (generateDeps) { - bool isDir; - if (!llvm::sys::fs::is_directory(dependenciesOutputFile, isDir) && isDir) { - llvm::errs() << "error: dependencies output file '" << dependenciesOutputFile << "' is a directory\n"; - return 1; - } - llvm::sys::RemoveFileOnSignal(dependenciesOutputFile); + if (generateDeps) { + bool isDir; + if (!llvm::sys::fs::is_directory(dependenciesOutputFile, isDir) && + isDir) { + llvm::errs() << "error: dependencies output file '" + << dependenciesOutputFile << "' is a directory\n"; + return 1; } + llvm::sys::RemoveFileOnSignal(dependenciesOutputFile); + } - HiResTimer loadTimer, compileTimer, optTimer, outputTimer; + HiResTimer loadTimer, compileTimer, optTimer, outputTimer; - //compiler + // compiler - loadTimer.start(); - try { - initLoader(); + loadTimer.start(); + try { + initLoader(); - ModulePtr m; - vector sourceFiles; - if (!clayScript.empty()) { - string clayScriptSource; - clayScriptSource = clayScriptImports + "main() {\n" + clayScript + "}"; - m = loadProgramSource("-e", clayScriptSource, verbose, repl); - } else if (generateDeps) - m = loadProgram(clayFile, &sourceFiles, verbose, repl); - else - m = loadProgram(clayFile, nullptr, verbose, repl); + ModulePtr m; + vector sourceFiles; + if (!clayScript.empty()) { + string clayScriptSource; + clayScriptSource = + clayScriptImports + "main() {\n" + clayScript + "}"; + m = loadProgramSource("-e", clayScriptSource, verbose, repl); + } else if (generateDeps) + m = loadProgram(clayFile, &sourceFiles, verbose, repl); + else + m = loadProgram(clayFile, nullptr, verbose, repl); - loadTimer.stop(); - compileTimer.start(); - codegenEntryPoints(m, codegenExternals); - compileTimer.stop(); + loadTimer.stop(); + compileTimer.start(); + codegenEntryPoints(m, codegenExternals); + compileTimer.stop(); - if (generateDeps) { - std::error_code ec; + if (generateDeps) { + std::error_code ec; - if (verbose) { - llvm::errs() << "generating dependencies into " << dependenciesOutputFile << "\n"; - } + if (verbose) { + llvm::errs() << "generating dependencies into " + << dependenciesOutputFile << "\n"; + } - llvm::raw_fd_ostream dependenciesOut(dependenciesOutputFile, - ec, - llvm::sys::fs::OF_None); - if (ec) { - llvm::errs() << "error creating dependencies file: " << ec.message() << '\n'; - return 1; - } - dependenciesOut << outputFile << ": \\\n"; - for (size_t i = 0; i < sourceFiles.size(); ++i) { - dependenciesOut << " " << sourceFiles[i]; - if (i < sourceFiles.size() - 1) - dependenciesOut << " \\\n"; - } + llvm::raw_fd_ostream dependenciesOut(dependenciesOutputFile, ec, + llvm::sys::fs::OF_None); + if (ec) { + llvm::errs() + << "error creating dependencies file: " << ec.message() + << '\n'; + return 1; } + dependenciesOut << outputFile << ": \\\n"; + for (size_t i = 0; i < sourceFiles.size(); ++i) { + dependenciesOut << " " << sourceFiles[i]; + if (i < sourceFiles.size() - 1) + dependenciesOut << " \\\n"; + } + } - bool internalize = true; - if (debug || sharedLib || run || !codegenExternals) - internalize = false; + bool internalize = true; + if (debug || sharedLib || run || !codegenExternals) + internalize = false; - optTimer.start(); + optTimer.start(); - if (!repl) { - if (optLevel > 0) - optimizeLLVM(llvmModule, optLevel, internalize); + if (!repl) { + if (optLevel > 0) + optimizeLLVM(llvmModule, optLevel, internalize); + } + optTimer.stop(); + + if (run) { + vector runArgs; + runArgs.push_back(clayFile); + runModule(llvmModule, runArgs, envp, libSearchPath, libraries); + } else if (repl) { + // TODO: future me task + runInteractive(llvmModule, m); + } else if (emitLLVM || emitAsm || emitObject) { + std::error_code ec; + + llvm::raw_fd_ostream out(outputFile, ec, llvm::sys::fs::OF_None); + if (ec) { + llvm::errs() + << "error creating output file: " << ec.message() << '\n'; + return 1; } - optTimer.stop(); - - if (run) { - vector runArgs; - runArgs.push_back(clayFile); - runModule(llvmModule, runArgs, envp, libSearchPath, libraries); - } else if (repl) { - // TODO: future me task - runInteractive(llvmModule, m); - } else if (emitLLVM || emitAsm || emitObject) { - std::error_code ec; - - llvm::raw_fd_ostream out(outputFile, - ec, - llvm::sys::fs::OF_None); - if (ec) { - llvm::errs() << "error creating output file: " << ec.message() << '\n'; - return 1; - } - outputTimer.start(); - if (emitLLVM) - generateLLVM(llvmModule, emitAsm, &out); - else if (emitAsm || emitObject) - generateAssembly(llvmModule, targetMachine, &out, emitObject); - outputTimer.stop(); - } else { - bool result; - llvm::ErrorOr clangPathOrErr = llvm::sys::findProgramByName("clang"); - if (std::error_code ec = clangPathOrErr.getError()) { - llvm::errs() << "error: unable to find clang on the path: " << ec.message() << "\n"; - return 1; - } - const std::string& clangPath = clangPathOrErr.get(); + outputTimer.start(); + if (emitLLVM) + generateLLVM(llvmModule, emitAsm, &out); + else if (emitAsm || emitObject) + generateAssembly(llvmModule, targetMachine, &out, emitObject); + outputTimer.stop(); + } else { + bool result; + llvm::ErrorOr clangPathOrErr = + llvm::sys::findProgramByName("clang"); + if (std::error_code ec = clangPathOrErr.getError()) { + llvm::errs() << "error: unable to find clang on the path: " + << ec.message() << "\n"; + return 1; + } + const std::string &clangPath = clangPathOrErr.get(); - vector arguments; + vector arguments; #ifdef __APPLE__ - if (!arch.empty()) { - arguments.emplace_back("-arch"); - arguments.push_back(arch); - } + if (!arch.empty()) { + arguments.emplace_back("-arch"); + arguments.push_back(arch); + } #endif - if (!linkerFlags.empty()) - arguments.push_back("-Wl" + linkerFlags); + if (!linkerFlags.empty()) + arguments.push_back("-Wl" + linkerFlags); #ifdef __APPLE__ - copy( - frameworkSearchPath.begin(), - frameworkSearchPath.end(), - back_inserter(arguments) - ); - copy(frameworks.begin(), frameworks.end(), back_inserter(arguments)); + copy(frameworkSearchPath.begin(), frameworkSearchPath.end(), + back_inserter(arguments)); + copy(frameworks.begin(), frameworks.end(), + back_inserter(arguments)); #endif - copy( - libSearchPathArgs.begin(), - libSearchPathArgs.end(), - back_inserter(arguments) - ); - copy(librariesArgs.begin(), librariesArgs.end(), back_inserter(arguments)); - - outputTimer.start(); - result = generateBinary(llvmModule, targetMachine, outputFile, clangPath, - exceptions, sharedLib, debug, arguments, verbose); - outputTimer.stop(); - if (!result) - return 1; - } - } catch (const CompilerError &) { - return 1; - } - if (showTiming) { - llvm::errs() << "load time = " << static_cast(loadTimer.elapsedMillis()) << " ms\n"; - llvm::errs() << "compile time = " << static_cast(compileTimer.elapsedMillis()) << " ms\n"; - llvm::errs() << "optimization time = " << static_cast(optTimer.elapsedMillis()) << " ms\n"; - llvm::errs() << "codegen time = " << static_cast(outputTimer.elapsedMillis()) << " ms\n"; - llvm::errs().flush(); + copy(libSearchPathArgs.begin(), libSearchPathArgs.end(), + back_inserter(arguments)); + copy(librariesArgs.begin(), librariesArgs.end(), + back_inserter(arguments)); + + outputTimer.start(); + result = generateBinary(llvmModule, targetMachine, outputFile, + clangPath, exceptions, sharedLib, debug, + arguments, verbose); + outputTimer.stop(); + if (!result) + return 1; } - - _exit(0); + } catch (const CompilerError &) { + return 1; + } + if (showTiming) { + llvm::errs() << "load time = " + << static_cast(loadTimer.elapsedMillis()) + << " ms\n"; + llvm::errs() << "compile time = " + << static_cast(compileTimer.elapsedMillis()) + << " ms\n"; + llvm::errs() << "optimization time = " + << static_cast(optTimer.elapsedMillis()) + << " ms\n"; + llvm::errs() << "codegen time = " + << static_cast(outputTimer.elapsedMillis()) + << " ms\n"; + llvm::errs().flush(); } + + _exit(0); } +} // namespace clay -int main(int argc, char **argv, char const *const*envp) { +int main(int argc, char **argv, char const *const *envp) { return clay::parachute(clay::main2, argc, argv, envp); } diff --git a/compiler/clay.hpp b/compiler/clay.hpp index bde527a9..6c8147f4 100644 --- a/compiler/clay.hpp +++ b/compiler/clay.hpp @@ -5,68 +5,68 @@ #define _SCL_SECURE_NO_WARNINGS #endif -#include -#include +#include #include #include -#include +#include +#include #ifdef _MSC_VER // LLVM headers spew warnings on MSVC #pragma warning(push) -#pragma warning(disable: 4146 4244 4267 4355 4146 4800 4996) +#pragma warning(disable : 4146 4244 4267 4355 4146 4800 4996) #endif +#include #include #include #include #include #include #include +#include #include -#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include #include -#include -#include -#include -#include #include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include #include #include -#include #include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include +#include #include @@ -77,31 +77,28 @@ #include "refcounted.hpp" namespace clay { - template - struct StaticAssertChecker; - - template<> - struct StaticAssertChecker { - typedef int type; - }; - - template<> - struct StaticAssertChecker { - }; - -#define _CLAY_CAT(a,b) a##b -#define CLAY_CAT(a,b) _CLAY_CAT(a,b) - -#define CLAY_STATIC_ASSERT(cond) \ - static const ::clay::StaticAssertChecker<(cond)>::type CLAY_CAT(static_assert_, __LINE__); - - using std::string; - using std::vector; - using std::pair; - using std::make_pair; - using std::map; - using std::set; -} +template struct StaticAssertChecker; + +template <> struct StaticAssertChecker { + typedef int type; +}; + +template <> struct StaticAssertChecker {}; + +#define _CLAY_CAT(a, b) a##b +#define CLAY_CAT(a, b) _CLAY_CAT(a, b) + +#define CLAY_STATIC_ASSERT(cond) \ + static const ::clay::StaticAssertChecker<(cond)>::type CLAY_CAT( \ + static_assert_, __LINE__); + +using std::make_pair; +using std::map; +using std::pair; +using std::set; +using std::string; +using std::vector; +} // namespace clay #ifdef _MSC_VER @@ -114,34 +111,36 @@ namespace clay { #include namespace clay { - typedef std::complex clay_cfloat; - typedef std::complex clay_cdouble; - typedef std::complex clay_cldouble; +typedef std::complex clay_cfloat; +typedef std::complex clay_cdouble; +typedef std::complex clay_cldouble; - template - inline T clay_creal(std::complex const &c) { return std::real(c); } +template inline T clay_creal(std::complex const &c) { + return std::real(c); +} - template - inline T clay_cimag(std::complex const &c) { return std::imag(c); } +template inline T clay_cimag(std::complex const &c) { + return std::imag(c); } +} // namespace clay #else #define CLAY_ALIGN(n) __attribute__((aligned(n))) namespace clay { - typedef std::complex clay_cfloat; - typedef std::complex clay_cdouble; - typedef std::complex clay_cldouble; +typedef std::complex clay_cfloat; +typedef std::complex clay_cdouble; +typedef std::complex clay_cldouble; - inline float clay_creal(const clay_cfloat &c) { return c.real(); } - inline double clay_creal(const clay_cdouble &c) { return c.real(); } - inline long double clay_creal(const clay_cldouble &c) { return c.real(); } +inline float clay_creal(const clay_cfloat &c) { return c.real(); } +inline double clay_creal(const clay_cdouble &c) { return c.real(); } +inline long double clay_creal(const clay_cldouble &c) { return c.real(); } - inline float clay_cimag(const clay_cfloat &c) { return c.imag(); } - inline double clay_cimag(const clay_cdouble &c) { return c.imag(); } - inline long double clay_cimag(const clay_cldouble &c) { return c.imag(); } -} +inline float clay_cimag(const clay_cfloat &c) { return c.imag(); } +inline double clay_cimag(const clay_cdouble &c) { return c.imag(); } +inline long double clay_cimag(const clay_cldouble &c) { return c.imag(); } +} // namespace clay #endif @@ -149,2741 +148,2394 @@ namespace clay { #define CLAY_COMPILER_VERSION "0.2git" namespace clay { - // - // container typedefs - // - - typedef llvm::SmallString<260> PathString; - - // - // Target-specific types - // - typedef int ptrdiff32_t; - typedef long long ptrdiff64_t; - - typedef unsigned size32_t; - typedef unsigned long long size64_t; - - // - // ObjectKind - // - -#define OBJECT_KIND_MAP(XX) \ - XX(SOURCE) \ - XX(LOCATION) \ -\ - XX(IDENTIFIER) \ - XX(DOTTED_NAME) \ -\ - XX(EXPRESSION) \ - XX(EXPR_LIST) \ - XX(STATEMENT) \ - XX(CASE_BLOCK) \ - XX(CATCH) \ -\ - XX(FORMAL_ARG) \ - XX(RETURN_SPEC) \ - XX(LLVM_CODE) \ - XX(CODE) \ -\ - XX(RECORD_DECL) \ - XX(RECORD_BODY) \ - XX(RECORD_FIELD) \ - XX(VARIANT_DECL) \ - XX(INSTANCE_DECL) \ - XX(NEW_TYPE_DECL) \ - XX(OVERLOAD) \ - XX(PROCEDURE) \ - XX(INTRINSIC) \ - XX(ENUM_DECL) \ - XX(ENUM_MEMBER) \ - XX(GLOBAL_VARIABLE) \ - XX(EXTERNAL_PROCEDURE) \ - XX(EXTERNAL_ARG) \ - XX(EXTERNAL_VARIABLE) \ - XX(EVAL_TOPLEVEL) \ -\ - XX(GLOBAL_ALIAS) \ -\ - XX(IMPORT) \ - XX(MODULE_DECLARATION) \ - XX(MODULE) \ -\ - XX(ENV) \ -\ - XX(PRIM_OP) \ -\ - XX(TYPE) \ -\ - XX(PATTERN) \ - XX(MULTI_PATTERN) \ -\ - XX(VALUE_HOLDER) \ - XX(MULTI_STATIC) \ -\ - XX(PVALUE) \ - XX(MULTI_PVALUE) \ -\ - XX(EVALUE) \ - XX(MULTI_EVALUE) \ -\ - XX(CVALUE) \ - XX(MULTI_CVALUE) \ -\ - XX(DOCUMENTATION) \ -\ +// +// container typedefs +// + +typedef llvm::SmallString<260> PathString; + +// +// Target-specific types +// +typedef int ptrdiff32_t; +typedef long long ptrdiff64_t; + +typedef unsigned size32_t; +typedef unsigned long long size64_t; + +// +// ObjectKind +// + +#define OBJECT_KIND_MAP(XX) \ + XX(SOURCE) \ + XX(LOCATION) \ + \ + XX(IDENTIFIER) \ + XX(DOTTED_NAME) \ + \ + XX(EXPRESSION) \ + XX(EXPR_LIST) \ + XX(STATEMENT) \ + XX(CASE_BLOCK) \ + XX(CATCH) \ + \ + XX(FORMAL_ARG) \ + XX(RETURN_SPEC) \ + XX(LLVM_CODE) \ + XX(CODE) \ + \ + XX(RECORD_DECL) \ + XX(RECORD_BODY) \ + XX(RECORD_FIELD) \ + XX(VARIANT_DECL) \ + XX(INSTANCE_DECL) \ + XX(NEW_TYPE_DECL) \ + XX(OVERLOAD) \ + XX(PROCEDURE) \ + XX(INTRINSIC) \ + XX(ENUM_DECL) \ + XX(ENUM_MEMBER) \ + XX(GLOBAL_VARIABLE) \ + XX(EXTERNAL_PROCEDURE) \ + XX(EXTERNAL_ARG) \ + XX(EXTERNAL_VARIABLE) \ + XX(EVAL_TOPLEVEL) \ + \ + XX(GLOBAL_ALIAS) \ + \ + XX(IMPORT) \ + XX(MODULE_DECLARATION) \ + XX(MODULE) \ + \ + XX(ENV) \ + \ + XX(PRIM_OP) \ + \ + XX(TYPE) \ + \ + XX(PATTERN) \ + XX(MULTI_PATTERN) \ + \ + XX(VALUE_HOLDER) \ + XX(MULTI_STATIC) \ + \ + XX(PVALUE) \ + XX(MULTI_PVALUE) \ + \ + XX(EVALUE) \ + XX(MULTI_EVALUE) \ + \ + XX(CVALUE) \ + XX(MULTI_CVALUE) \ + \ + XX(DOCUMENTATION) \ + \ XX(STATIC_ASSERT_TOP_LEVEL) #define OBJECT_KIND_GEN(e) e, - enum ObjectKind { - OBJECT_KIND_MAP(OBJECT_KIND_GEN) - }; +enum ObjectKind { OBJECT_KIND_MAP(OBJECT_KIND_GEN) }; #undef OBJECT_KIND_GEN - llvm::raw_ostream &operator<<(llvm::raw_ostream &os, ObjectKind); +llvm::raw_ostream &operator<<(llvm::raw_ostream &os, ObjectKind); + +// +// Object +// + +struct Object : public RefCounted { + const ObjectKind objKind; + + Object(ObjectKind objKind) : objKind(objKind) {} + + virtual ~Object() {} + + // print to stderr, for debugging + void print() const; + + // use only in debugger + std::string toString() const; +}; + +typedef Pointer ObjectPtr; + +// +// forwards +// + +struct Source; + +struct ANode; +struct Identifier; +struct DottedName; + +struct Expr; +struct BoolLiteral; +struct IntLiteral; +struct FloatLiteral; +struct CharLiteral; +struct StringLiteral; +struct NameRef; +struct FILEExpr; +struct LINEExpr; +struct COLUMNExpr; +struct ARGExpr; +struct Tuple; +struct Paren; +struct Indexing; +struct Call; +struct FieldRef; +struct StaticIndexing; +struct VariadicOp; +struct And; +struct Or; +struct Lambda; +struct Unpack; +struct StaticExpr; +struct DispatchExpr; +struct ForeignExpr; +struct ObjectExpr; +struct EvalExpr; + +struct ExprList; + +struct Statement; +struct Block; +struct Label; +struct Binding; +struct Assignment; +struct InitAssignment; +struct VariadicAssignment; +struct Goto; +struct Switch; +struct CaseBlock; +struct Return; +struct If; +struct ExprStatement; +struct While; +struct Break; +struct Continue; +struct For; +struct ForeignStatement; +struct Try; +struct Catch; +struct Throw; +struct StaticFor; +struct Finally; +struct OnError; +struct Unreachable; +struct EvalStatement; +struct StaticAssertStatement; + +struct FormalArg; +struct ReturnSpec; +struct LLVMCode; +struct Code; + +struct TopLevelItem; +struct RecordDecl; +struct RecordBody; +struct RecordField; +struct VariantDecl; +struct InstanceDecl; +struct NewTypeDecl; +struct Overload; +struct Procedure; +struct IntrinsicSymbol; +struct EnumDecl; +struct EnumMember; +struct GlobalVariable; +struct GVarInstance; +struct ExternalProcedure; +struct ExternalArg; +struct ExternalVariable; +struct EvalTopLevel; +struct StaticAssertTopLevel; +struct Documentation; + +struct GlobalAlias; + +struct Import; +struct ImportModule; +struct ImportStar; +struct ImportMembers; +struct Module; +struct ModuleDeclaration; + +struct Env; + +struct PrimOp; + +struct Type; +struct BoolType; +struct IntegerType; +struct FloatType; +struct ComplexType; +struct ArrayType; +struct VecType; +struct TupleType; +struct UnionType; +struct PointerType; +struct CodePointerType; +struct CCodePointerType; +struct RecordType; +struct VariantType; +struct StaticType; +struct EnumType; +struct NewType; + +struct Pattern; +struct PatternCell; +struct PatternStruct; + +struct MultiPattern; +struct MultiPatternCell; +struct MultiPatternList; + +struct ValueHolder; +struct MultiStatic; + +struct PValue; +struct MultiPValue; + +struct EValue; +struct MultiEValue; + +struct CValue; +struct MultiCValue; + +struct ObjectTable; + +struct ValueStackEntry; + +struct MatchResult; +struct MatchFailureError; + +// +// Pointer typedefs +// + +typedef Pointer SourcePtr; + +typedef Pointer ANodePtr; +typedef Pointer IdentifierPtr; +typedef Pointer DottedNamePtr; + +typedef Pointer ExprPtr; +typedef Pointer BoolLiteralPtr; +typedef Pointer IntLiteralPtr; +typedef Pointer FloatLiteralPtr; +typedef Pointer CharLiteralPtr; +typedef Pointer StringLiteralPtr; +typedef Pointer NameRefPtr; +typedef Pointer FILEExprPtr; +typedef Pointer LINEExprPtr; +typedef Pointer COLUMNExprPtr; +typedef Pointer ARGExprPtr; +typedef Pointer TuplePtr; +typedef Pointer ParenPtr; +typedef Pointer IndexingPtr; +typedef Pointer CallPtr; +typedef Pointer FieldRefPtr; +typedef Pointer StaticIndexingPtr; +typedef Pointer VariadicOpPtr; +typedef Pointer AndPtr; +typedef Pointer OrPtr; +typedef Pointer LambdaPtr; +typedef Pointer UnpackPtr; +typedef Pointer StaticExprPtr; +typedef Pointer DispatchExprPtr; +typedef Pointer ForeignExprPtr; +typedef Pointer ObjectExprPtr; +typedef Pointer EvalExprPtr; + +typedef Pointer ExprListPtr; + +typedef Pointer StatementPtr; +typedef Pointer BlockPtr; +typedef Pointer