1
0
mirror of https://github.com/exaloop/codon.git synced 2025-06-03 15:03:52 +08:00

Merge pull request #12 from exaloop/auto-class-deduction

Automatic class slot deduction
This commit is contained in:
Ibrahim Numanagić 2022-02-28 09:39:03 -08:00 committed by GitHub
commit cc55bf9a21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 1000 additions and 326 deletions

View File

@ -16,8 +16,16 @@ if(CODON_JUPYTER)
endif()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden -pedantic -Wno-return-type-c-linkage -Wno-gnu-zero-variadic-macro-arguments")
set(CMAKE_CXX_FLAGS_DEBUG "-g -fno-limit-debug-info")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -fvisibility-inlines-hidden -Wno-return-type-c-linkage -Wno-gnu-zero-variadic-macro-arguments")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-return-type")
endif()
set(CMAKE_CXX_FLAGS_DEBUG "-g")
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-limit-debug-info")
endif()
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
include_directories(.)
@ -74,8 +82,8 @@ else()
-Wl,--no-whole-archive)
endif()
if(ASAN)
target_compile_options(codonrt PRIVATE "-fno-omit-frame-pointer" "-fsanitize=address")
target_link_libraries(codonrt PRIVATE "-fno-omit-frame-pointer" "-fsanitize=address")
target_compile_options(codonrt PRIVATE "-fno-omit-frame-pointer" "-fsanitize=address" "-fsanitize-recover=address")
target_link_libraries(codonrt PRIVATE "-fno-omit-frame-pointer" "-fsanitize=address" "-fsanitize-recover=address")
endif()
add_custom_command(TARGET codonrt POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:omp> ${CMAKE_BINARY_DIR})
@ -209,7 +217,7 @@ set(CODON_HPPFILES
codon/util/toml++/toml_node.h
codon/util/toml++/toml_parser.hpp
codon/util/toml++/toml_utf8_streams.h
extra/jupyter/src/codon.h)
extra/jupyter/jupyter.h)
set(CODON_CPPFILES
codon/compiler/compiler.cpp
codon/compiler/debug_listener.cpp
@ -288,7 +296,7 @@ set(CODON_CPPFILES
codon/sir/var.cpp
codon/util/common.cpp
codon/util/fmt/format.cpp
extra/jupyter/src/codon.cpp)
extra/jupyter/jupyter.cpp)
add_library(codonc SHARED ${CODON_HPPFILES})
target_sources(codonc PRIVATE ${CODON_CPPFILES} codon_rules.cpp omp_rules.cpp)
if(CODON_JUPYTER)
@ -297,8 +305,8 @@ if(CODON_JUPYTER)
target_link_libraries(codonc PRIVATE xeus-static)
endif()
if(ASAN)
target_compile_options(codonc PRIVATE "-fno-omit-frame-pointer" "-fsanitize=address")
target_link_libraries(codonc PRIVATE "-fno-omit-frame-pointer" "-fsanitize=address")
target_compile_options(codonc PRIVATE "-fno-omit-frame-pointer" "-fsanitize=address" "-fsanitize-recover=address")
target_link_libraries(codonc PRIVATE "-fno-omit-frame-pointer" "-fsanitize=address" "-fsanitize-recover=address")
endif()
if(CMAKE_BUILD_TYPE MATCHES Debug)
set_source_files_properties(codon_rules.cpp codon/parser/peg/peg.cpp PROPERTIES COMPILE_FLAGS "-O2")

View File

@ -66,10 +66,11 @@ if(bdwgc_ADDED)
endif()
CPMAddPackage(
GITHUB_REPOSITORY "llvm-mirror/openmp"
VERSION 9.0
GIT_TAG release_90
OPTIONS "OPENMP_ENABLE_LIBOMPTARGET OFF"
NAME openmp
GITHUB_REPOSITORY "exaloop/openmp"
VERSION 13.0.0-patch1
OPTIONS "CMAKE_BUILD_TYPE Release"
"OPENMP_ENABLE_LIBOMPTARGET OFF"
"OPENMP_STANDALONE_BUILD ON")
CPMAddPackage(
@ -125,8 +126,8 @@ if(CODON_JUPYTER)
NAME libzmq
VERSION 4.3.4
URL https://github.com/zeromq/libzmq/releases/download/v4.3.4/zeromq-4.3.4.tar.gz
OPTIONS "WITH_PERF_TOOL OFF"
"ZMQ_BUILD_TESTS OFF"
OPTIONS "WITH_PERF_TOOL OFF"
"ZMQ_BUILD_TESTS OFF"
"ENABLE_CPACK OFF"
"BUILD_SHARED ON"
"WITH_LIBSODIUM OFF")
@ -144,16 +145,17 @@ if(CODON_JUPYTER)
CPMAddPackage(
NAME json
GITHUB_REPOSITORY "nlohmann/json"
VERSION 3.10.4)
VERSION 3.10.1)
CPMAddPackage(
NAME xeus
GITHUB_REPOSITORY "jupyter-xeus/xeus"
VERSION 2.2.0
GIT_TAG 2.2.0
PATCH_COMMAND sed -i bak "s/-Wunused-parameter -Wextra -Wreorder//g" CMakeLists.txt
PATCH_COMMAND sed -ibak "s/-Wunused-parameter -Wextra -Wreorder//g" CMakeLists.txt
OPTIONS "BUILD_EXAMPLES OFF"
"XEUS_BUILD_SHARED_LIBS OFF"
"XEUS_STATIC_DEPENDENCIES ON")
"XEUS_STATIC_DEPENDENCIES ON"
"CMAKE_POSITION_INDEPENDENT_CODE ON")
if (xeus_ADDED)
install(TARGETS nlohmann_json EXPORT xeus-targets)
endif()

View File

@ -1,6 +1,7 @@
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
@ -55,6 +56,12 @@ void display(const codon::error::ParserErrorInfo &e) {
}
}
void initLogFlags(const llvm::cl::opt<std::string> &log) {
codon::getLogger().parse(log);
if (auto *d = getenv("CODON_DEBUG"))
codon::getLogger().parse(std::string(d));
}
enum BuildKind { LLVM, Bitcode, Object, Executable, Detect };
enum OptMode { Debug, Release };
} // namespace
@ -84,10 +91,11 @@ std::unique_ptr<codon::Compiler> processSource(const std::vector<const char *> &
bool standalone) {
llvm::cl::opt<std::string> input(llvm::cl::Positional, llvm::cl::desc("<input file>"),
llvm::cl::init("-"));
auto regs = llvm::cl::getRegisteredOptions();
llvm::cl::opt<OptMode> optMode(
llvm::cl::desc("optimization mode"),
llvm::cl::values(
clEnumValN(Debug, "debug",
clEnumValN(Debug, regs.find("debug") != regs.end() ? "default" : "debug",
"Turn off compiler optimizations and show backtraces"),
clEnumValN(Release, "release",
"Turn on compiler optimizations and disable debug info")),
@ -102,9 +110,7 @@ std::unique_ptr<codon::Compiler> processSource(const std::vector<const char *> &
llvm::cl::opt<std::string> log("log", llvm::cl::desc("Enable given log streams"));
llvm::cl::ParseCommandLineOptions(args.size(), args.data());
codon::getLogger().parse(log);
if (auto *d = getenv("CODON_DEBUG"))
codon::getLogger().parse(std::string(d));
initLogFlags(log);
auto &exts = supportedExtensions();
if (input != "-" && std::find_if(exts.begin(), exts.end(), [&](auto &ext) {
@ -206,7 +212,9 @@ std::string jitExec(codon::jit::JIT *jit, const std::string &code) {
int jitMode(const std::vector<const char *> &args) {
llvm::cl::list<std::string> plugins("plugin",
llvm::cl::desc("Load specified plugin"));
llvm::cl::opt<std::string> log("log", llvm::cl::desc("Enable given log streams"));
llvm::cl::ParseCommandLineOptions(args.size(), args.data());
initLogFlags(log);
codon::jit::JIT jit(args[0]);
// load plugins
@ -230,13 +238,13 @@ int jitMode(const std::vector<const char *> &args) {
if (line != "#%%") {
code += line + "\n";
} else {
fmt::print("{}\n\n[done]\n\n", jitExec(&jit, code));
fmt::print("{}[done]\n", jitExec(&jit, code));
code = "";
fflush(stdout);
}
}
if (!code.empty())
fmt::print("{}\n\n[done]\n\n", jitExec(&jit, code));
fmt::print("{}[done]\n", jitExec(&jit, code));
return EXIT_SUCCESS;
}

View File

@ -1,7 +1,5 @@
#include "compiler.h"
#include <filesystem>
#include "codon/parser/cache.h"
#include "codon/parser/peg/peg.h"
#include "codon/parser/visitors/doc/doc.h"
@ -11,13 +9,29 @@
#include "codon/parser/visitors/typecheck/typecheck.h"
namespace codon {
namespace {
ir::transform::PassManager::Init getPassManagerInit(Compiler::Mode mode, bool isTest) {
using ir::transform::PassManager;
switch (mode) {
case Compiler::Mode::DEBUG:
return isTest ? PassManager::Init::RELEASE : PassManager::Init::DEBUG;
case Compiler::Mode::RELEASE:
return PassManager::Init::RELEASE;
case Compiler::Mode::JIT:
return PassManager::Init::JIT;
default:
return PassManager::Init::EMPTY;
}
}
} // namespace
Compiler::Compiler(const std::string &argv0, bool debug,
Compiler::Compiler(const std::string &argv0, Compiler::Mode mode,
const std::vector<std::string> &disabledPasses, bool isTest)
: argv0(argv0), debug(debug), input(), plm(std::make_unique<PluginManager>()),
: argv0(argv0), debug(mode == Mode::DEBUG), input(),
plm(std::make_unique<PluginManager>()),
cache(std::make_unique<ast::Cache>(argv0)),
module(std::make_unique<ir::Module>()),
pm(std::make_unique<ir::transform::PassManager>(debug && !isTest,
pm(std::make_unique<ir::transform::PassManager>(getPassManagerInit(mode, isTest),
disabledPasses)),
llvisitor(std::make_unique<ir::LLVMVisitor>()) {
cache->module = module.get();
@ -50,9 +64,7 @@ Compiler::parse(bool isCode, const std::string &file, const std::string &code,
int startLine, int testFlags,
const std::unordered_map<std::string, std::string> &defines) {
input = file;
std::string abspath =
(file != "-") ? std::filesystem::absolute(std::filesystem::path(file)).string()
: file;
std::string abspath = (file != "-") ? ast::getAbsolutePath(file) : file;
try {
Timer t1("parse");
ast::StmtPtr codeStmt = isCode

View File

@ -15,6 +15,13 @@
namespace codon {
class Compiler {
public:
enum Mode {
DEBUG,
RELEASE,
JIT,
};
private:
std::string argv0;
bool debug;
@ -30,9 +37,14 @@ private:
const std::unordered_map<std::string, std::string> &defines);
public:
Compiler(const std::string &argv0, bool debug = false,
Compiler(const std::string &argv0, Mode mode,
const std::vector<std::string> &disabledPasses = {}, bool isTest = false);
explicit Compiler(const std::string &argv0, bool debug = false,
const std::vector<std::string> &disabledPasses = {},
bool isTest = false)
: Compiler(argv0, debug ? Mode::DEBUG : Mode::RELEASE, disabledPasses, isTest) {}
std::string getInput() const { return input; }
PluginManager *getPluginManager() const { return plm.get(); }
ast::Cache *getCache() const { return cache.get(); }

View File

@ -18,7 +18,7 @@ const std::string JIT_FILENAME = "<jit>";
} // namespace
JIT::JIT(const std::string &argv0, const std::string &mode)
: compiler(std::make_unique<Compiler>(argv0, /*debug=*/true)), mode(mode) {
: compiler(std::make_unique<Compiler>(argv0, Compiler::Mode::JIT)), mode(mode) {
if (auto e = Engine::create()) {
engine = std::move(e.get());
} else {
@ -44,7 +44,7 @@ llvm::Error JIT::init() {
pm->run(module);
module->accept(*llvisitor);
auto pair = llvisitor->takeModule();
auto pair = llvisitor->takeModule(module);
if (auto err = engine->addModule({std::move(pair.first), std::move(pair.second)}))
return err;
@ -58,25 +58,22 @@ llvm::Error JIT::init() {
return llvm::Error::success();
}
llvm::Expected<std::string> JIT::run(const ir::Func *input,
const std::vector<ir::Var *> &newGlobals) {
llvm::Expected<std::string> JIT::run(const ir::Func *input) {
auto *module = compiler->getModule();
auto *pm = compiler->getPassManager();
auto *llvisitor = compiler->getLLVMVisitor();
Timer t1("jit/ir");
pm->run(module);
t1.log();
const std::string name = ir::LLVMVisitor::getNameForFunction(input);
llvisitor->registerGlobal(input);
for (auto *var : newGlobals) {
llvisitor->registerGlobal(var);
}
for (auto *var : newGlobals) {
if (auto *func = ir::cast<ir::Func>(var))
func->accept(*llvisitor);
}
input->accept(*llvisitor);
auto pair = llvisitor->takeModule();
Timer t2("jit/llvm");
auto pair = llvisitor->takeModule(module);
t2.log();
Timer t3("jit/engine");
if (auto err = engine->addModule({std::move(pair.first), std::move(pair.second)}))
return std::move(err);
@ -85,6 +82,8 @@ llvm::Expected<std::string> JIT::run(const ir::Func *input,
return std::move(err);
auto *repl = (InputFunc *)func->getAddress();
t3.log();
try {
(*repl)();
} catch (const JITError &e) {
@ -138,11 +137,7 @@ llvm::Expected<std::string> JIT::exec(const std::string &code) {
auto *cache = compiler->getCache();
auto typechecked = ast::TypecheckVisitor::apply(cache, simplified);
std::vector<std::string> globalNames;
for (auto &g : cache->globals) {
if (!g.second)
globalNames.push_back(g.first);
}
// add newly realized functions
std::vector<ast::StmtPtr> v;
std::vector<ir::Func **> frs;
@ -155,16 +150,7 @@ llvm::Expected<std::string> JIT::exec(const std::string &code) {
ast::TranslateVisitor::apply(cache, std::make_shared<ast::SuiteStmt>(v, false));
cache->jitCell++;
std::vector<ir::Var *> globalVars;
for (auto &g : globalNames) {
seqassert(cache->globals[g], "JIT global {} not set", g);
globalVars.push_back(cache->globals[g]);
}
for (auto &i : frs) {
seqassert(*i, "JIT fn not set");
globalVars.push_back(*i);
}
return run(func, globalVars);
return run(func);
} catch (const exc::ParserException &e) {
*cache = bCache;
*(cache->imports[MAIN_IMPORT].ctx) = bSimplify;

View File

@ -28,8 +28,7 @@ public:
Engine *getEngine() const { return engine.get(); }
llvm::Error init();
llvm::Expected<std::string> run(const ir::Func *input,
const std::vector<ir::Var *> &newGlobals = {});
llvm::Expected<std::string> run(const ir::Func *input);
llvm::Expected<std::string> exec(const std::string &code);
};

View File

@ -1,12 +1,14 @@
#include "plugins.h"
#include <cstdlib>
#include <filesystem>
#include "codon/parser/common.h"
#include "codon/util/common.h"
#include "codon/util/semver/semver.h"
#include "codon/util/toml++/toml.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
namespace codon {
namespace {
@ -17,8 +19,6 @@ llvm::Expected<Plugin *> pluginError(const std::string &msg) {
typedef std::unique_ptr<DSL> LoadFunc();
} // namespace
namespace fs = std::filesystem;
llvm::Expected<Plugin *> PluginManager::load(const std::string &path) {
#if __APPLE__
const std::string libExt = "dylib";
@ -27,35 +27,42 @@ llvm::Expected<Plugin *> PluginManager::load(const std::string &path) {
#endif
const std::string config = "plugin.toml";
fs::path tomlPath = fs::path(path) / config;
if (!fs::exists(tomlPath)) {
llvm::SmallString<128> tomlPath(path);
llvm::sys::path::append(tomlPath, config);
if (!llvm::sys::fs::exists(tomlPath)) {
// try default install path
if (auto *homeDir = std::getenv("HOME"))
tomlPath = fs::path(homeDir) / ".codon/plugins" / path / config;
if (auto *homeDir = std::getenv("HOME")) {
tomlPath = homeDir;
llvm::sys::path::append(tomlPath, ".codon", "plugins", path, config);
}
}
toml::parse_result tml;
try {
tml = toml::parse_file(tomlPath.string());
tml = toml::parse_file(tomlPath.str());
} catch (const toml::parse_error &e) {
return pluginError(
fmt::format("[toml::parse_file(\"{}\")] {}", tomlPath.string(), e.what()));
fmt::format("[toml::parse_file(\"{}\")] {}", tomlPath.str(), e.what()));
}
auto about = tml["about"];
auto library = tml["library"];
std::string cppLib = library["cpp"].value_or("");
std::string dylibPath;
if (!cppLib.empty())
dylibPath = fs::path(tomlPath)
.replace_filename(library["cpp"].value_or("lib"))
.replace_extension(libExt)
.string();
llvm::SmallString<128> dylibPath;
if (!cppLib.empty()) {
dylibPath = llvm::sys::path::parent_path(tomlPath);
auto fn = std::string(library["cpp"].value_or("lib")) + "." + libExt;
llvm::sys::path::append(dylibPath, fn);
}
std::string codonLib = library["codon"].value_or("");
std::string stdlibPath;
if (!codonLib.empty())
stdlibPath = fs::path(tomlPath).replace_filename(codonLib).string();
if (!codonLib.empty()) {
llvm::SmallString<128> p = llvm::sys::path::parent_path(tomlPath.str());
llvm::sys::path::append(p, codonLib);
stdlibPath = p.str();
}
DSL::Info info = {about["name"].value_or(""), about["description"].value_or(""),
about["version"].value_or(""), about["url"].value_or(""),
@ -80,13 +87,13 @@ llvm::Expected<Plugin *> PluginManager::load(const std::string &path) {
&libLoadErrorMsg);
if (!handle.isValid())
return pluginError(fmt::format(
"[llvm::sys::DynamicLibrary::getPermanentLibrary(\"{}\", ...)] {}", dylibPath,
libLoadErrorMsg));
"[llvm::sys::DynamicLibrary::getPermanentLibrary(\"{}\", ...)] {}",
dylibPath.str(), libLoadErrorMsg));
auto *entry = (LoadFunc *)handle.getAddressOfSymbol("load");
if (!entry)
return pluginError(
fmt::format("could not find 'load' in plugin shared library: {}", dylibPath));
return pluginError(fmt::format(
"could not find 'load' in plugin shared library: {}", dylibPath.str()));
auto dsl = (*entry)();
plugins.push_back(std::make_unique<Plugin>(std::move(dsl), info, handle));

View File

@ -18,7 +18,7 @@ namespace ast {
Expr::Expr()
: type(nullptr), isTypeExpr(false), staticValue(StaticValue::NOT_STATIC),
done(false) {}
done(false), attributes(0) {}
types::TypePtr Expr::getType() const { return type; }
void Expr::setType(types::TypePtr t) { this->type = std::move(t); }
bool Expr::isType() const { return isTypeExpr; }
@ -31,6 +31,8 @@ std::string Expr::wrapType(const std::string &sexpr) const {
done ? "*" : "");
}
bool Expr::isStatic() const { return staticValue.type != StaticValue::NOT_STATIC; }
bool Expr::hasAttr(int attr) const { return (attributes & (1 << attr)); }
void Expr::setAttr(int attr) { attributes |= (1 << attr); }
StaticValue::StaticValue(StaticValue::Type t) : value(), type(t), evaluated(false) {}
StaticValue::StaticValue(int64_t i) : value(i), type(INT), evaluated(true) {}

View File

@ -78,6 +78,9 @@ struct Expr : public codon::SrcObject {
/// type-checking procedure was successful).
bool done;
/// Set of attributes.
int attributes;
public:
Expr();
Expr(const Expr &expr) = default;
@ -124,6 +127,10 @@ public:
virtual const TupleExpr *getTuple() const { return nullptr; }
virtual const UnaryExpr *getUnary() const { return nullptr; }
/// Attribute helpers
bool hasAttr(int attr) const;
void setAttr(int attr);
protected:
/// Add a type to S-expression string.
std::string wrapType(const std::string &sexpr) const;
@ -666,5 +673,7 @@ struct StackAllocExpr : Expr {
#undef ACCEPT
enum ExprAttr { SequenceItem, StarSequenceItem, List, Set, Dict, Partial, __LAST__ };
} // namespace ast
} // namespace codon

View File

@ -285,6 +285,8 @@ const std::string Attr::Atomic = "atomic";
const std::string Attr::Property = "property";
const std::string Attr::Internal = "__internal__";
const std::string Attr::ForceRealize = "__force__";
const std::string Attr::RealizeWithoutSelf =
"std.internal.attributes.realize_without_self";
const std::string Attr::C = "std.internal.attributes.C";
const std::string Attr::CVarArg = ".__vararg__";
const std::string Attr::Method = ".__method__";
@ -292,6 +294,7 @@ const std::string Attr::Capture = ".__capture__";
const std::string Attr::Extend = "extend";
const std::string Attr::Tuple = "tuple";
const std::string Attr::Test = "std.internal.attributes.test";
const std::string Attr::Overload = "std.internal.attributes.overload";
FunctionStmt::FunctionStmt(std::string name, ExprPtr ret, std::vector<Param> args,
StmtPtr suite, Attr attributes,

View File

@ -398,6 +398,7 @@ struct Attr {
// Internal attributes
const static std::string Internal;
const static std::string ForceRealize;
const static std::string RealizeWithoutSelf;
// Compiler-generated attributes
const static std::string C;
const static std::string CVarArg;
@ -408,6 +409,7 @@ struct Attr {
const static std::string Tuple;
// Standard library attributes
const static std::string Test;
const static std::string Overload;
// Function module
std::string module;
// Parent class (set for methods only)

View File

@ -185,7 +185,7 @@ std::string LinkType::debugString(bool debug) const {
// fmt::format("{}->{}", id, type->debugString(debug));
}
std::string LinkType::realizedName() const {
if (kind == Unbound)
if (kind == Unbound || kind == Generic)
return "?";
seqassert(kind == Link, "unexpected generic link");
return type->realizedName();
@ -476,12 +476,18 @@ std::vector<TypePtr> FuncType::getUnbounds() const {
}
bool FuncType::canRealize() const {
// Important: return type does not have to be realized.
for (int ai = 1; ai < args.size(); ai++)
bool force = ast->hasAttr(Attr::RealizeWithoutSelf);
int ai = 1 + force;
for (; ai < args.size(); ai++)
if (!args[ai]->getFunc() && !args[ai]->canRealize())
return false;
return std::all_of(funcGenerics.begin(), funcGenerics.end(),
[](auto &a) { return !a.type || a.type->canRealize(); }) &&
(!funcParent || funcParent->canRealize());
bool generics = std::all_of(funcGenerics.begin(), funcGenerics.end(),
[](auto &a) { return !a.type || a.type->canRealize(); });
if (!force)
generics &= (!funcParent || funcParent->canRealize());
return generics;
}
bool FuncType::isInstantiated() const {
TypePtr removed = nullptr;
@ -532,15 +538,7 @@ PartialType::PartialType(const std::shared_ptr<RecordType> &baseType,
std::shared_ptr<FuncType> func, std::vector<char> known)
: RecordType(*baseType), func(move(func)), known(move(known)) {}
int PartialType::unify(Type *typ, Unification *us) {
int s1 = 0, s;
if (auto tc = typ->getPartial()) {
// Check names.
if ((s = func->unify(tc->func.get(), us)) == -1)
return -1;
s1 += s;
}
s = this->RecordType::unify(typ, us);
return s == -1 ? s : s1 + s;
return this->RecordType::unify(typ, us);
}
TypePtr PartialType::generalize(int atLevel) {
return std::make_shared<PartialType>(
@ -549,10 +547,9 @@ TypePtr PartialType::generalize(int atLevel) {
}
TypePtr PartialType::instantiate(int atLevel, int *unboundCount,
std::unordered_map<int, TypePtr> *cache) {
return std::make_shared<PartialType>(
std::static_pointer_cast<RecordType>(
this->RecordType::instantiate(atLevel, unboundCount, cache)),
func, known);
auto rec = std::static_pointer_cast<RecordType>(
this->RecordType::instantiate(atLevel, unboundCount, cache));
return std::make_shared<PartialType>(rec, func, known);
}
std::string PartialType::debugString(bool debug) const {
std::vector<std::string> gs;
@ -573,7 +570,7 @@ std::string PartialType::debugString(bool debug) const {
}
std::string PartialType::realizedName() const {
std::vector<std::string> gs;
gs.push_back(func->realizedName());
gs.push_back(func->ast->name);
for (auto &a : generics)
if (!a.name.empty())
gs.push_back(a.type->realizedName());
@ -755,12 +752,24 @@ int CallableTrait::unify(Type *typ, Unification *us) {
zeros.emplace_back(pi - 9);
if (zeros.size() + 1 != args.size())
return -1;
if (args[0]->unify(pt->func->args[0].get(), us) == -1)
return -1;
int ic = 0;
std::unordered_map<int, TypePtr> c;
auto pf = pt->func->instantiate(0, &ic, &c)->getFunc();
// For partial functions, we just check can we unify without actually performing
// unification
for (int pi = 0, gi = 1; pi < pt->known.size(); pi++)
if (!pt->known[pi] && !pt->func->ast->args[pi].generic)
if (args[gi++]->unify(pt->func->args[pi + 1].get(), us) == -1)
if (!pt->known[pi] && !pf->ast->args[pi].generic)
if (args[gi++]->unify(pf->args[pi + 1].get(), us) == -1)
return -1;
if (us && us->realizator && pf->canRealize()) {
// Realize if possible to allow deduction of return type [and possible
// unification!]
auto rf = us->realizator->realize(pf);
pf->unify(rf.get(), us);
}
if (args[0]->unify(pf->args[0].get(), us) == -1)
return -1;
return 1;
}
} else if (auto tl = typ->getLink()) {

View File

@ -14,6 +14,7 @@ struct Expr;
struct StaticValue;
struct FunctionStmt;
struct TypeContext;
class TypecheckVisitor;
namespace types {
@ -43,6 +44,11 @@ struct Type : public codon::SrcObject, public std::enable_shared_from_this<Type>
std::vector<std::pair<LinkType *, int>> leveled;
/// List of assigned traits.
std::vector<LinkType *> traits;
/// Pointer to a TypecheckVisitor to support realization function types.
TypecheckVisitor *realizator = nullptr;
/// List of pointers that are owned by unification process
/// (to avoid memory issues with undoing).
std::vector<std::shared_ptr<Type>> ownedTypes;
public:
/// Undo the unification step.

View File

@ -111,14 +111,18 @@ ir::Func *Cache::realizeFunction(types::FuncTypePtr type,
}
}
}
int oldAge = typeCtx->age;
typeCtx->age = 99999;
auto tv = TypecheckVisitor(typeCtx);
ir::Func *f = nullptr;
if (auto rtv = tv.realize(type)) {
auto pr = pendingRealizations; // copy it as it might be modified
for (auto &fn : pr)
TranslateVisitor(codegenCtx).transform(functions[fn.first].ast->clone());
return functions[rtv->getFunc()->ast->name].realizations[rtv->realizedName()]->ir;
f = functions[rtv->getFunc()->ast->name].realizations[rtv->realizedName()]->ir;
}
return nullptr;
typeCtx->age = oldAge;
return f;
}
ir::types::Type *Cache::makeTuple(const std::vector<types::TypePtr> &types) {

View File

@ -188,6 +188,9 @@ struct Cache : public std::enable_shared_from_this<Cache> {
std::shared_ptr<TranslateContext> codegenCtx;
/// Set of function realizations that are to be translated to IR.
std::set<std::pair<std::string, std::string>> pendingRealizations;
/// Mapping of partial record names to function pointers and corresponding masks.
std::unordered_map<std::string, std::pair<types::FuncTypePtr, std::vector<char>>>
partials;
/// Custom operators
std::unordered_map<std::string,

View File

@ -1,11 +1,12 @@
#include "common.h"
#include <filesystem>
#include <string>
#include <vector>
#include "codon/parser/common.h"
#include "codon/util/fmt/format.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
namespace codon {
namespace ast {
@ -195,28 +196,29 @@ std::string executable_path(const char *argv0) {
std::string executable_path(const char *argv0) { return std::string(argv0); }
#endif
namespace fs = std::filesystem;
namespace {
void addPath(std::vector<fs::path> &paths, const fs::path &path) {
if (fs::exists(path))
paths.push_back(fs::canonical(path));
void addPath(std::vector<std::string> &paths, const std::string &path) {
if (llvm::sys::fs::exists(path))
paths.push_back(getAbsolutePath(path));
}
std::vector<fs::path> getStdLibPaths(const std::string &argv0,
const std::vector<std::string> &plugins) {
std::vector<fs::path> paths;
std::vector<std::string> getStdLibPaths(const std::string &argv0,
const std::vector<std::string> &plugins) {
std::vector<std::string> paths;
if (auto c = getenv("CODON_PATH")) {
addPath(paths, fs::path(std::string(c)));
addPath(paths, c);
}
if (!argv0.empty()) {
auto base = fs::path(executable_path(argv0.c_str()));
auto base = executable_path(argv0.c_str());
for (auto loci : {"../lib/codon/stdlib", "../stdlib", "stdlib"}) {
addPath(paths, base.parent_path() / loci);
auto path = llvm::SmallString<128>(llvm::sys::path::parent_path(base));
llvm::sys::path::append(path, loci);
addPath(paths, std::string(path));
}
}
for (auto &path : plugins) {
addPath(paths, fs::path(path));
addPath(paths, path);
}
return paths;
}
@ -244,28 +246,47 @@ ImportFile getRoot(const std::string argv0, const std::vector<std::string> &plug
}
} // namespace
std::string getAbsolutePath(const std::string &path) {
char *c = realpath(path.c_str(), nullptr);
if (!c)
return path;
std::string result(c);
free(c);
return result;
}
std::shared_ptr<ImportFile> getImportFile(const std::string &argv0,
const std::string &what,
const std::string &relativeTo,
bool forceStdlib, const std::string &module0,
const std::vector<std::string> &plugins) {
std::vector<fs::path> paths;
std::vector<std::string> paths;
if (what != "<jit>") {
auto parentRelativeTo = fs::path(relativeTo).parent_path();
auto parentRelativeTo = llvm::sys::path::parent_path(relativeTo);
if (!forceStdlib) {
addPath(paths, (parentRelativeTo / what).replace_extension("codon"));
addPath(paths, parentRelativeTo / what / "__init__.codon");
auto path = llvm::SmallString<128>(parentRelativeTo);
llvm::sys::path::append(path, what);
llvm::sys::path::replace_extension(path, "codon");
addPath(paths, std::string(path));
path = llvm::SmallString<128>(parentRelativeTo);
llvm::sys::path::append(path, what, "__init__.codon");
addPath(paths, std::string(path));
}
}
for (auto &p : getStdLibPaths(argv0, plugins)) {
addPath(paths, (p / what).replace_extension("codon"));
addPath(paths, p / what / "__init__.codon");
auto path = llvm::SmallString<128>(p);
llvm::sys::path::append(path, what);
llvm::sys::path::replace_extension(path, "codon");
addPath(paths, std::string(path));
path = llvm::SmallString<128>(p);
llvm::sys::path::append(path, what, "__init__.codon");
addPath(paths, std::string(path));
}
auto module0Root = fs::path(module0).parent_path().string();
auto module0Root = llvm::sys::path::parent_path(module0).str();
return paths.empty() ? nullptr
: std::make_shared<ImportFile>(
getRoot(argv0, plugins, module0Root, paths[0].string()));
getRoot(argv0, plugins, module0Root, paths[0]));
}
} // namespace ast

View File

@ -167,6 +167,9 @@ template <typename T> std::vector<T> clone_nop(const std::vector<T> &t) {
/// Path utilities
/// @return The absolute canonical path of a given path.
std::string getAbsolutePath(const std::string &path);
/// Detect a absolute path of the current executable (whose argv0 is known).
/// @return Absolute executable path or argv0 if one cannot be found.
std::string executable_path(const char *argv0);

View File

@ -109,9 +109,8 @@ StmtPtr parseFile(Cache *cache, const std::string &file) {
cache->imports[file].content = lines;
auto result = parseCode(cache, file, code);
// For debugging purposes:
// LOG("peg/{} := {}", file, result ? result->toString(0) : "<nullptr>");
// throw;
// LOG("fmt := {}", FormatVisitor::apply(result));
return result;
}

View File

@ -1,6 +1,5 @@
#include "doc.h"
#include <filesystem>
#include <memory>
#include <string>
#include <tuple>
@ -116,10 +115,9 @@ std::shared_ptr<json> DocVisitor::apply(const std::string &argv0,
auto ctx = std::make_shared<DocContext>(shared);
for (auto &f : files) {
auto path = std::filesystem::canonical(std::filesystem::path(f)).string();
auto path = getAbsolutePath(f);
ctx->setFilename(path);
ast = ast::parseFile(shared->cache, path);
// LOG("parsing {}", f);
DocVisitor(ctx).transformModule(std::move(ast));
}

View File

@ -406,15 +406,6 @@ void FormatVisitor::visit(FunctionStmt *fstmt) {
}
void FormatVisitor::visit(ClassStmt *stmt) {
// if (cache &&
// cache->realizationAsts.find(fstmt->name) != cache->realizationAsts.end()) {
// fstmt = (const FunctionStmt *)(cache->realizationAsts[fstmt->name].get());
// } else if (cache) {
// for (auto &real : cache->realizations[fstmt->name])
// result += simplify(cache->realizationAsts[real.first]);
// return;
// }
std::vector<std::string> attrs;
if (!stmt->attributes.has(Attr::Extend))

View File

@ -30,9 +30,6 @@ class FormatVisitor : public CallbackASTVisitor<std::string, std::string> {
private:
template <typename T, typename... Ts> std::string renderExpr(T &&t, Ts &&...args) {
std::string s;
// if (renderType)
// s += fmt::format("{}{}{}", typeStart,
// t->getType() ? t->getType()->toString() : "-", typeEnd);
return fmt::format("{}{}{}{}{}{}", exprStart, s, nodeStart, fmt::format(args...),
nodeEnd, exprEnd);
}

View File

@ -24,7 +24,8 @@ SimplifyContext::SimplifyContext(std::string filename, Cache *cache)
allowTypeOf(true), substitutions(nullptr) {}
SimplifyContext::Base::Base(std::string name, std::shared_ptr<Expr> ast, int attributes)
: name(move(name)), ast(move(ast)), attributes(attributes) {}
: name(move(name)), ast(move(ast)), attributes(attributes), deducedMembers(nullptr),
selfName() {}
std::shared_ptr<SimplifyItem> SimplifyContext::add(SimplifyItem::Kind kind,
const std::string &name,

View File

@ -67,6 +67,9 @@ struct SimplifyContext : public Context<SimplifyItem> {
/// Tracks function attributes (e.g. if it has @atomic or @test attributes).
int attributes;
std::shared_ptr<std::vector<std::string>> deducedMembers;
std::string selfName;
explicit Base(std::string name, ExprPtr ast = nullptr, int attributes = 0);
bool isType() const { return ast != nullptr; }
};

View File

@ -31,6 +31,8 @@ ExprPtr SimplifyVisitor::transform(const ExprPtr &expr, bool allowTypes,
ctx->canAssign = oldAssign;
if (!allowTypes && v.resultExpr && v.resultExpr->isType())
error("unexpected type expression");
if (v.resultExpr)
v.resultExpr->attributes |= expr->attributes;
return v.resultExpr;
}
@ -179,15 +181,21 @@ void SimplifyVisitor::visit(ListExpr *expr) {
for (const auto &it : expr->items) {
if (auto star = it->getStar()) {
ExprPtr forVar = N<IdExpr>(ctx->cache->getTemporaryVar("it"));
auto st = star->what->clone();
st->setAttr(ExprAttr::StarSequenceItem);
stmts.push_back(transform(N<ForStmt>(
clone(forVar), star->what->clone(),
clone(forVar), st,
N<ExprStmt>(N<CallExpr>(N<DotExpr>(clone(var), "append"), clone(forVar))))));
} else {
stmts.push_back(transform(
N<ExprStmt>(N<CallExpr>(N<DotExpr>(clone(var), "append"), clone(it)))));
auto st = clone(it);
st->setAttr(ExprAttr::SequenceItem);
stmts.push_back(
transform(N<ExprStmt>(N<CallExpr>(N<DotExpr>(clone(var), "append"), st))));
}
}
resultExpr = N<StmtExpr>(stmts, transform(var));
auto e = N<StmtExpr>(stmts, transform(var));
e->setAttr(ExprAttr::List);
resultExpr = e;
ctx->popBlock();
}
@ -200,14 +208,20 @@ void SimplifyVisitor::visit(SetExpr *expr) {
for (auto &it : expr->items)
if (auto star = it->getStar()) {
ExprPtr forVar = N<IdExpr>(ctx->cache->getTemporaryVar("it"));
auto st = star->what->clone();
st->setAttr(ExprAttr::StarSequenceItem);
stmts.push_back(transform(N<ForStmt>(
clone(forVar), star->what->clone(),
clone(forVar), st,
N<ExprStmt>(N<CallExpr>(N<DotExpr>(clone(var), "add"), clone(forVar))))));
} else {
stmts.push_back(transform(
N<ExprStmt>(N<CallExpr>(N<DotExpr>(clone(var), "add"), clone(it)))));
auto st = clone(it);
st->setAttr(ExprAttr::SequenceItem);
stmts.push_back(
transform(N<ExprStmt>(N<CallExpr>(N<DotExpr>(clone(var), "add"), st))));
}
resultExpr = N<StmtExpr>(stmts, transform(var));
auto e = N<StmtExpr>(stmts, transform(var));
e->setAttr(ExprAttr::Set);
resultExpr = e;
ctx->popBlock();
}
@ -220,16 +234,24 @@ void SimplifyVisitor::visit(DictExpr *expr) {
for (auto &it : expr->items)
if (auto star = CAST(it.value, KeywordStarExpr)) {
ExprPtr forVar = N<IdExpr>(ctx->cache->getTemporaryVar("it"));
auto st = star->what->clone();
st->setAttr(ExprAttr::StarSequenceItem);
stmts.push_back(transform(N<ForStmt>(
clone(forVar), N<CallExpr>(N<DotExpr>(star->what->clone(), "items")),
clone(forVar), N<CallExpr>(N<DotExpr>(st, "items")),
N<ExprStmt>(N<CallExpr>(N<DotExpr>(clone(var), "__setitem__"),
N<IndexExpr>(clone(forVar), N<IntExpr>(0)),
N<IndexExpr>(clone(forVar), N<IntExpr>(1)))))));
} else {
stmts.push_back(transform(N<ExprStmt>(N<CallExpr>(
N<DotExpr>(clone(var), "__setitem__"), clone(it.key), clone(it.value)))));
auto k = clone(it.key);
k->setAttr(ExprAttr::SequenceItem);
auto v = clone(it.value);
v->setAttr(ExprAttr::SequenceItem);
stmts.push_back(transform(
N<ExprStmt>(N<CallExpr>(N<DotExpr>(clone(var), "__setitem__"), k, v))));
}
resultExpr = N<StmtExpr>(stmts, transform(var));
auto e = N<StmtExpr>(stmts, transform(var));
e->setAttr(ExprAttr::Dict);
resultExpr = e;
ctx->popBlock();
}
@ -308,10 +330,10 @@ void SimplifyVisitor::visit(UnaryExpr *expr) {
void SimplifyVisitor::visit(BinaryExpr *expr) {
auto lhs = (startswith(expr->op, "is") && expr->lexpr->getNone())
? clone(expr->lexpr)
: transform(expr->lexpr);
: transform(expr->lexpr, startswith(expr->op, "is"));
auto rhs = (startswith(expr->op, "is") && expr->rexpr->getNone())
? clone(expr->rexpr)
: transform(expr->rexpr, false,
: transform(expr->rexpr, startswith(expr->op, "is"),
/*allowAssign*/ expr->op != "&&" && expr->op != "||");
resultExpr = N<BinaryExpr>(lhs, expr->op, rhs, expr->inPlace);
}
@ -493,9 +515,9 @@ void SimplifyVisitor::visit(CallExpr *expr) {
ctx->add(SimplifyItem::Var, varName, varName);
var = N<IdExpr>(varName);
ctx->addBlock(); // prevent tmp vars from being toplevel vars
ex = N<StmtExpr>(
transform(N<AssignStmt>(clone(g->loops[0].vars), clone(var), nullptr, true)),
transform(ex));
auto head =
transform(N<AssignStmt>(clone(g->loops[0].vars), clone(var), nullptr, true));
ex = N<StmtExpr>(head, transform(ex));
ctx->popBlock();
}
std::vector<GeneratorBody> body;
@ -688,7 +710,9 @@ void SimplifyVisitor::visit(StmtExpr *expr) {
for (auto &s : expr->stmts)
stmts.emplace_back(transform(s));
auto e = transform(expr->expr);
resultExpr = N<StmtExpr>(stmts, e);
auto s = N<StmtExpr>(stmts, e);
s->attributes = expr->attributes;
resultExpr = s;
}
/**************************************************************************************/

View File

@ -180,7 +180,9 @@ void SimplifyVisitor::visit(WhileStmt *stmt) {
transform(N<AssignStmt>(N<IdExpr>(breakVar), N<BoolExpr>(true), nullptr, true));
}
ctx->loops.push_back(breakVar); // needed for transforming break in loop..else blocks
StmtPtr whileStmt = N<WhileStmt>(transform(cond), transform(stmt->suite));
cond = transform(cond);
StmtPtr whileStmt = N<WhileStmt>(cond, transform(stmt->suite));
ctx->loops.pop_back();
if (stmt->elseSuite && stmt->elseSuite->firstInBlock()) {
resultStmt =
@ -232,8 +234,9 @@ void SimplifyVisitor::visit(ForStmt *stmt) {
ctx->addBlock();
if (auto i = stmt->var->getId()) {
ctx->add(SimplifyItem::Var, i->value, ctx->generateCanonicalName(i->value));
forStmt = N<ForStmt>(transform(stmt->var), clone(iter), transform(stmt->suite),
nullptr, decorator, ompArgs);
auto var = transform(stmt->var);
forStmt = N<ForStmt>(var, clone(iter), transform(stmt->suite), nullptr, decorator,
ompArgs);
} else {
std::string varName = ctx->cache->getTemporaryVar("for");
ctx->add(SimplifyItem::Var, varName, varName);
@ -259,8 +262,8 @@ void SimplifyVisitor::visit(ForStmt *stmt) {
void SimplifyVisitor::visit(IfStmt *stmt) {
seqassert(stmt->cond, "invalid if statement");
resultStmt = N<IfStmt>(transform(stmt->cond), transform(stmt->ifSuite),
transform(stmt->elseSuite));
auto cond = transform(stmt->cond);
resultStmt = N<IfStmt>(cond, transform(stmt->ifSuite), transform(stmt->elseSuite));
}
void SimplifyVisitor::visit(MatchStmt *stmt) {
@ -473,7 +476,7 @@ void SimplifyVisitor::visit(FunctionStmt *stmt) {
// TODO: error on decorators
return;
}
bool overload = attr.has(Attr::Overload);
bool isClassMember = ctx->inClass();
std::string rootName;
if (isClassMember) {
@ -481,10 +484,11 @@ void SimplifyVisitor::visit(FunctionStmt *stmt) {
auto i = m.find(stmt->name);
if (i != m.end())
rootName = i->second;
} else if (auto c = ctx->find(stmt->name)) {
if (c->isFunc() && c->getModule() == ctx->getModule() &&
c->getBase() == ctx->getBase())
rootName = c->canonicalName;
} else if (overload) {
if (auto c = ctx->find(stmt->name))
if (c->isFunc() && c->getModule() == ctx->getModule() &&
c->getBase() == ctx->getBase())
rootName = c->canonicalName;
}
if (rootName.empty())
rootName = ctx->generateCanonicalName(stmt->name, true);
@ -504,7 +508,9 @@ void SimplifyVisitor::visit(FunctionStmt *stmt) {
if (isClassMember)
ctx->bases.push_back(oldBases[0]);
ctx->bases.emplace_back(SimplifyContext::Base{canonicalName}); // Add new base...
ctx->addBlock(); // ... and a block!
if (isClassMember && ctx->bases[0].deducedMembers)
ctx->bases.back().deducedMembers = ctx->bases[0].deducedMembers;
ctx->addBlock(); // ... and a block!
// Set atomic flag if @atomic attribute is present.
if (attr.has(Attr::Atomic))
ctx->bases.back().attributes |= FLAG_ATOMIC;
@ -540,9 +546,12 @@ void SimplifyVisitor::visit(FunctionStmt *stmt) {
error("non-default argument '{}' after a default argument", varName);
defaultsStarted |= bool(a.deflt);
auto name = ctx->generateCanonicalName(varName);
auto typeAst = a.type;
if (!typeAst && isClassMember && ia == 0 && a.name == "self") {
typeAst = ctx->bases[ctx->bases.size() - 2].ast;
ctx->bases.back().selfName = name;
attr.set(".changedSelf");
attr.set(Attr::Method);
}
@ -557,9 +566,14 @@ void SimplifyVisitor::visit(FunctionStmt *stmt) {
}
// First add all generics!
auto name = ctx->generateCanonicalName(varName);
args.emplace_back(
Param{std::string(stars, '*') + name, typeAst, a.deflt, a.generic});
auto deflt = a.deflt;
if (typeAst && typeAst->getIndex() && typeAst->getIndex()->expr->isId("Callable") &&
deflt && deflt->getNone())
deflt = N<CallExpr>(N<IdExpr>("NoneType"));
if (typeAst && (typeAst->isId("type") || typeAst->isId("TypeVar")) && deflt &&
deflt->getNone())
deflt = N<IdExpr>("NoneType");
args.emplace_back(Param{std::string(stars, '*') + name, typeAst, deflt, a.generic});
if (a.generic) {
if (a.type->getIndex() && a.type->getIndex()->expr->isId("Static"))
ctx->add(SimplifyItem::Var, varName, name);
@ -677,12 +691,15 @@ void SimplifyVisitor::visit(ClassStmt *stmt) {
Attr attr = stmt->attributes;
std::vector<char> hasMagic(10, 2);
hasMagic[Init] = hasMagic[Pickle] = 1;
bool deduce = false;
// @tuple(init=, repr=, eq=, order=, hash=, pickle=, container=, python=, add=,
// internal=...)
// @dataclass(...)
// @extend
for (auto &d : stmt->decorators) {
if (auto c = d->getCall()) {
if (d->isId("deduce")) {
deduce = true;
} else if (auto c = d->getCall()) {
if (c->expr->isId(Attr::Tuple))
attr.set(Attr::Tuple);
else if (!c->expr->isId("dataclass"))
@ -861,6 +878,43 @@ void SimplifyVisitor::visit(ClassStmt *stmt) {
}
argSubstitutions.push_back(substitutions.size() - 1);
}
// Auto-detect fields
StmtPtr autoDeducedInit = nullptr;
Stmt *firstInit = nullptr;
if (deduce && args.empty() && !extension) {
for (auto sp : getClassMethods(stmt->suite))
if (sp && sp->getFunction()) {
firstInit = sp.get();
auto f = sp->getFunction();
if (f->name == "__init__" && f->args.size() >= 1 && f->args[0].name == "self") {
ctx->bases.back().deducedMembers =
std::make_shared<std::vector<std::string>>();
transform(sp);
autoDeducedInit = preamble->functions.back();
std::dynamic_pointer_cast<FunctionStmt>(autoDeducedInit)
->attributes.set(Attr::RealizeWithoutSelf);
ctx->cache->functions[autoDeducedInit->getFunction()->name]
.ast->attributes.set(Attr::RealizeWithoutSelf);
int i = 0;
for (auto &m : *(ctx->bases.back().deducedMembers)) {
auto varName = ctx->generateCanonicalName(format("T{}", ++i));
auto name = ctx->cache->reverseIdentifierLookup[varName];
ctx->add(SimplifyItem::Type, name, varName, true);
genAst.push_back(N<IdExpr>(varName));
args.emplace_back(Param{varName, N<IdExpr>("type"), nullptr, true});
argSubstitutions.push_back(substitutions.size() - 1);
ctx->cache->classes[canonicalName].fields.push_back({m, nullptr});
args.emplace_back(Param{m, N<IdExpr>(varName), nullptr});
argSubstitutions.push_back(substitutions.size() - 1);
}
ctx->bases.back().deducedMembers = nullptr;
break;
}
}
}
if (!genAst.empty())
ctx->bases.back().ast =
std::make_shared<IndexExpr>(N<IdExpr>(name), N<TupleExpr>(genAst));
@ -925,7 +979,7 @@ void SimplifyVisitor::visit(ClassStmt *stmt) {
magics = {"len", "hash"};
else
magics = {"new", "raw"};
if (hasMagic[Init])
if (hasMagic[Init] && !firstInit)
magics.emplace_back(isRecord ? "new" : "init");
if (hasMagic[Eq])
for (auto &i : {"eq", "ne"})
@ -959,7 +1013,6 @@ void SimplifyVisitor::visit(ClassStmt *stmt) {
}
}
for (int ai = 0; ai < baseASTs.size(); ai++) {
// FUNCS
for (auto &mm : ctx->cache->classes[baseASTs[ai]->name].methods)
for (auto &mf : ctx->cache->overloads[mm.second]) {
auto f = ctx->cache->functions[mf.name].ast;
@ -999,6 +1052,8 @@ void SimplifyVisitor::visit(ClassStmt *stmt) {
}
for (auto sp : getClassMethods(stmt->suite))
if (sp && !sp->getClass()) {
if (firstInit && firstInit == sp.get())
continue;
transform(sp);
suite->stmts.push_back(preamble->functions.back());
}
@ -1012,8 +1067,7 @@ void SimplifyVisitor::visit(ClassStmt *stmt) {
seqassert(c, "not a class AST for {}", canonicalName);
preamble->globals.push_back(c->clone());
c->suite = clone(suite);
// if (stmt->baseClasses.size())
// LOG("{} -> {}", stmt->name, c->toString(0));
}
stmts[0] = N<ClassStmt>(canonicalName, std::vector<Param>{}, N<SuiteStmt>(),
Attr({Attr::Extend}), std::vector<ExprPtr>{},
@ -1046,7 +1100,15 @@ StmtPtr SimplifyVisitor::transformAssignment(const ExprPtr &lhs, const ExprPtr &
clone(ei->index), rhs->clone())));
} else if (auto ed = lhs->getDot()) {
seqassert(!type, "unexpected type annotation");
return N<AssignMemberStmt>(transform(ed->expr), ed->member, transform(rhs, false));
auto l = transform(ed->expr);
if (ctx->bases.size() && ctx->bases.back().deducedMembers &&
l->isId(ctx->bases.back().selfName)) {
if (std::find(ctx->bases.back().deducedMembers->begin(),
ctx->bases.back().deducedMembers->end(),
ed->member) == ctx->bases.back().deducedMembers->end())
ctx->bases.back().deducedMembers->push_back(ed->member);
}
return N<AssignMemberStmt>(l, ed->member, transform(rhs, false));
} else if (auto e = lhs->getId()) {
ExprPtr t = transformType(type, false);
if (!shadow && !t) {

View File

@ -1,6 +1,5 @@
#include "translate.h"
#include <filesystem>
#include <memory>
#include <sstream>
#include <string>
@ -35,8 +34,7 @@ ir::Func *TranslateVisitor::apply(Cache *cache, StmtPtr stmts) {
main->setJIT();
} else {
main = cast<ir::BodiedFunc>(cache->module->getMainFunc());
auto path =
std::filesystem::canonical(std::filesystem::path(cache->module0)).string();
auto path = getAbsolutePath(cache->module0);
main->setSrcInfo({path, 0, 0, 0});
}
@ -57,8 +55,79 @@ ir::Func *TranslateVisitor::apply(Cache *cache, StmtPtr stmts) {
ir::Value *TranslateVisitor::transform(const ExprPtr &expr) {
TranslateVisitor v(ctx);
v.setSrcInfo(expr->getSrcInfo());
types::PartialType *p = nullptr;
if (expr->attributes) {
if (expr->hasAttr(ExprAttr::List) || expr->hasAttr(ExprAttr::Set) ||
expr->hasAttr(ExprAttr::Dict) || expr->hasAttr(ExprAttr::Partial)) {
ctx->seqItems.push_back(std::vector<std::pair<ExprAttr, ir::Value *>>());
}
if (expr->hasAttr(ExprAttr::Partial))
p = expr->type->getPartial().get();
}
expr->accept(v);
return v.result;
ir::Value *ir = v.result;
if (expr->attributes) {
if (expr->hasAttr(ExprAttr::List) || expr->hasAttr(ExprAttr::Set)) {
std::vector<ir::LiteralElement> v;
for (auto &p : ctx->seqItems.back()) {
seqassert(p.first <= ExprAttr::StarSequenceItem, "invalid list/set element");
v.push_back(
ir::LiteralElement{p.second, p.first == ExprAttr::StarSequenceItem});
}
if (expr->hasAttr(ExprAttr::List))
ir->setAttribute(std::make_unique<ir::ListLiteralAttribute>(v));
else
ir->setAttribute(std::make_unique<ir::SetLiteralAttribute>(v));
ctx->seqItems.pop_back();
}
if (expr->hasAttr(ExprAttr::Dict)) {
std::vector<ir::DictLiteralAttribute::KeyValuePair> v;
for (int pi = 0; pi < ctx->seqItems.back().size(); pi++) {
auto &p = ctx->seqItems.back()[pi];
if (p.first == ExprAttr::StarSequenceItem) {
v.push_back({p.second, nullptr});
} else {
seqassert(p.first == ExprAttr::SequenceItem &&
pi + 1 < ctx->seqItems.back().size() &&
ctx->seqItems.back()[pi + 1].first == ExprAttr::SequenceItem,
"invalid dict element");
v.push_back({p.second, ctx->seqItems.back()[pi + 1].second});
pi++;
}
}
ir->setAttribute(std::make_unique<ir::DictLiteralAttribute>(v));
ctx->seqItems.pop_back();
}
if (expr->hasAttr(ExprAttr::Partial)) {
std::vector<ir::Value *> v;
seqassert(p, "invalid partial element");
int j = 0;
for (int i = 0; i < p->known.size(); i++) {
if (p->known[i] && !p->func->ast->args[i].generic) {
seqassert(j < ctx->seqItems.back().size() &&
ctx->seqItems.back()[j].first == ExprAttr::SequenceItem,
"invalid partial element");
v.push_back(ctx->seqItems.back()[j++].second);
} else if (!p->func->ast->args[i].generic) {
v.push_back({nullptr});
}
}
ir->setAttribute(
std::make_unique<ir::PartialFunctionAttribute>(p->func->ast->name, v));
ctx->seqItems.pop_back();
}
if (expr->hasAttr(ExprAttr::SequenceItem)) {
ctx->seqItems.back().push_back({ExprAttr::SequenceItem, ir});
}
if (expr->hasAttr(ExprAttr::StarSequenceItem)) {
ctx->seqItems.back().push_back({ExprAttr::StarSequenceItem, ir});
}
}
return ir;
}
void TranslateVisitor::defaultVisit(Expr *n) {
@ -91,8 +160,10 @@ void TranslateVisitor::visit(IdExpr *expr) {
}
void TranslateVisitor::visit(IfExpr *expr) {
result = make<ir::TernaryInstr>(expr, transform(expr->cond), transform(expr->ifexpr),
transform(expr->elsexpr));
auto cond = transform(expr->cond);
auto ifexpr = transform(expr->ifexpr);
auto elsexpr = transform(expr->elsexpr);
result = make<ir::TernaryInstr>(expr, cond, ifexpr, elsexpr);
}
void TranslateVisitor::visit(CallExpr *expr) {
@ -428,13 +499,12 @@ void TranslateVisitor::transformFunction(types::FuncType *type, FunctionStmt *as
std::map<std::string, std::string> attr;
attr[".module"] = ast->attributes.module;
for (auto &a : ast->attributes.customAttr) {
// LOG("{} -> {}", ast->name, a);
attr[a] = "";
}
func->setAttribute(std::make_unique<ir::KeyValueAttribute>(attr));
for (int i = 0; i < names.size(); i++)
func->getArgVar(names[i])->setSrcInfo(ast->args[indices[i]].getSrcInfo());
func->setUnmangledName(ctx->cache->reverseIdentifierLookup[type->ast->name]);
// func->setUnmangledName(ctx->cache->reverseIdentifierLookup[type->ast->name]);
if (!ast->attributes.has(Attr::C) && !ast->attributes.has(Attr::Internal)) {
ctx->addBlock();
for (auto i = 0; i < names.size(); i++)
@ -511,7 +581,7 @@ void TranslateVisitor::transformLLVMFunction(types::FuncType *type, FunctionStmt
f->setLLVMBody(join(lines, "\n"));
f->setLLVMDeclarations(declare);
f->setLLVMLiterals(literals);
func->setUnmangledName(ctx->cache->reverseIdentifierLookup[type->ast->name]);
// func->setUnmangledName(ctx->cache->reverseIdentifierLookup[type->ast->name]);
}
} // namespace ast

View File

@ -21,14 +21,14 @@ std::shared_ptr<TranslateItem> TranslateContext::find(const std::string &name) c
return t;
std::shared_ptr<TranslateItem> ret = nullptr;
auto tt = cache->typeCtx->find(name);
if (tt->isType() && tt->type->canRealize()) {
if (tt && tt->isType() && tt->type->canRealize()) {
ret = std::make_shared<TranslateItem>(TranslateItem::Type, bases[0]);
seqassert(in(cache->classes, tt->type->getClass()->name) &&
in(cache->classes[tt->type->getClass()->name].realizations, name),
"cannot find type realization {}", name);
ret->handle.type =
cache->classes[tt->type->getClass()->name].realizations[name]->ir;
} else if (tt->type->getFunc() && tt->type->canRealize()) {
} else if (tt && tt->type->getFunc() && tt->type->canRealize()) {
ret = std::make_shared<TranslateItem>(TranslateItem::Func, bases[0]);
seqassert(
in(cache->functions, tt->type->getFunc()->ast->name) &&

View File

@ -50,6 +50,8 @@ struct TranslateContext : public Context<TranslateItem> {
std::vector<codon::ir::BodiedFunc *> bases;
/// Stack of IR series (blocks).
std::vector<codon::ir::SeriesFlow *> series;
/// Stack of sequence items for attribute initialization.
std::vector<std::vector<std::pair<ExprAttr, ir::Value *>>> seqItems;
public:
TranslateContext(Cache *cache);

View File

@ -38,6 +38,7 @@ TypePtr TypecheckVisitor::unify(TypePtr &a, const TypePtr &b, bool undoOnSuccess
return a = b;
seqassert(b, "rhs is nullptr");
types::Type::Unification undo;
undo.realizator = this;
if (a->unify(b.get(), &undo) >= 0) {
if (undoOnSuccess)
undo.undo();
@ -45,7 +46,6 @@ TypePtr TypecheckVisitor::unify(TypePtr &a, const TypePtr &b, bool undoOnSuccess
} else {
undo.undo();
}
// LOG("{} / {}", a->debugString(true), b->debugString(true));
if (!undoOnSuccess)
a->unify(b.get(), &undo);
error("cannot unify {} and {}", a->toString(), b->toString());

View File

@ -78,8 +78,8 @@ std::shared_ptr<types::LinkType>
TypeContext::addUnbound(const Expr *expr, int level, bool setActive, char staticType) {
auto t = std::make_shared<types::LinkType>(
types::LinkType::Unbound, cache->unboundCount++, level, nullptr, staticType);
// if (t->id == 7815)
// LOG("debug");
// Keep it for debugging purposes:
// if (t->id == 7815) LOG("debug");
t->setSrcInfo(expr->getSrcInfo());
LOG_TYPECHECK("[ub] new {}: {} ({})", t->debugString(true), expr->toString(),
setActive);
@ -202,17 +202,11 @@ int TypeContext::reorderNamedArgs(types::FuncType *func,
int starArgIndex = -1, kwstarArgIndex = -1;
for (int i = 0; i < func->ast->args.size(); i++) {
// if (!known.empty() && known[i] && !partial)
// continue;
if (startswith(func->ast->args[i].name, "**"))
kwstarArgIndex = i, score -= 2;
else if (startswith(func->ast->args[i].name, "*"))
starArgIndex = i, score -= 2;
}
// seqassert(known.empty() || starArgIndex == -1 || !known[starArgIndex],
// "partial *args");
// seqassert(known.empty() || kwstarArgIndex == -1 || !known[kwstarArgIndex],
// "partial **kwargs");
// 1. Assign positional arguments to slots
// Each slot contains a list of arg's indices

View File

@ -10,6 +10,7 @@
#include "codon/parser/common.h"
#include "codon/parser/visitors/simplify/simplify.h"
#include "codon/parser/visitors/typecheck/typecheck.h"
#include "codon/sir/attribute.h"
using fmt::format;
@ -35,8 +36,10 @@ ExprPtr TypecheckVisitor::transform(ExprPtr &expr, bool allowTypes, bool allowVo
ctx->allowActivation = false;
v.setSrcInfo(expr->getSrcInfo());
expr->accept(v);
if (v.resultExpr)
if (v.resultExpr) {
v.resultExpr->attributes |= expr->attributes;
expr = v.resultExpr;
}
seqassert(expr->type, "type not set for {}", expr->toString());
unify(typ, expr->type);
if (disableActivation)
@ -645,6 +648,8 @@ ExprPtr TypecheckVisitor::transformBinary(BinaryExpr *expr, bool isAtomic,
// Check if this is a "a is None" expression. If so, ...
if (expr->op == "is" && expr->rexpr->getNone()) {
if (expr->lexpr->getType()->getClass()->name == "NoneType")
return transform(N<BoolExpr>(true));
if (expr->lexpr->getType()->getClass()->name != TYPE_OPTIONAL)
// ... return False if lhs is not an Optional...
return transform(N<BoolExpr>(false));
@ -739,14 +744,7 @@ ExprPtr TypecheckVisitor::transformStaticTupleIndex(ClassType *tuple, ExprPtr &e
if (!tuple->getRecord())
return nullptr;
if (!startswith(tuple->name, TYPE_TUPLE) && !startswith(tuple->name, TYPE_PARTIAL))
// in(std::set<std::string>{"Ptr", "pyobj", "str", "Array"}, tuple->name))
// Ptr, pyobj and str are internal types and have only one overloaded __getitem__
return nullptr;
// if (in(ctx->cache->classes[tuple->name].methods, "__getitem__")) {
// ctx->cache->overloads[ctx->cache->classes[tuple->name].methods["__getitem__"]]
// .size() != 1)
// return nullptr;
// }
// Extract a static integer value from a compatible expression.
auto getInt = [&](int64_t *o, const ExprPtr &e) {
@ -870,8 +868,7 @@ ExprPtr TypecheckVisitor::transformDot(DotExpr *expr,
return transform(
N<CallExpr>(N<DotExpr>(expr->expr, "_getattr"), N<StringExpr>(expr->member)));
} else {
// For debugging purposes:
ctx->findMethod(typ->name, expr->member);
// For debugging purposes: ctx->findMethod(typ->name, expr->member);
error("cannot find '{}' in {}", expr->member, typ->toString());
}
}
@ -1021,7 +1018,6 @@ ExprPtr TypecheckVisitor::transformCall(CallExpr *expr, const types::TypePtr &in
ai--;
} else {
// Case 3: Normal argument
// LOG("-> {}", expr->args[ai].value->toString());
expr->args[ai].value = transform(expr->args[ai].value, true);
// Unbound inType might become a generator that will need to be extracted, so
// don't unify it yet.
@ -1047,8 +1043,6 @@ ExprPtr TypecheckVisitor::transformCall(CallExpr *expr, const types::TypePtr &in
ctx->bases.back().supers, expr->args);
if (m.empty())
error("no matching superf methods are available");
// LOG("found {} <- {}", ctx->bases.back().type->getFunc()->toString(),
// m[0]->toString());
ExprPtr e = N<CallExpr>(N<IdExpr>(m[0]->ast->name), expr->args);
return transform(e, false, true);
}
@ -1126,10 +1120,12 @@ ExprPtr TypecheckVisitor::transformCall(CallExpr *expr, const types::TypePtr &in
expr->expr = transform(N<StmtExpr>(N<AssignStmt>(clone(var), expr->expr),
N<IdExpr>(pc->func->ast->name)));
calleeFn = expr->expr->type->getFunc();
// Fill in generics
for (int i = 0, j = 0; i < pc->known.size(); i++)
if (pc->func->ast->args[i].generic) {
if (pc->known[i])
unify(calleeFn->funcGenerics[j].type, pc->func->funcGenerics[j].type);
unify(calleeFn->funcGenerics[j].type,
ctx->instantiate(expr, pc->func->funcGenerics[j].type));
j++;
}
known = pc->known;
@ -1144,7 +1140,6 @@ ExprPtr TypecheckVisitor::transformCall(CallExpr *expr, const types::TypePtr &in
std::vector<CallExpr::Arg> args;
std::vector<ExprPtr> typeArgs;
int typeArgCount = 0;
// bool isPartial = false;
int ellipsisStage = -1;
auto newMask = std::vector<char>(calleeFn->ast->args.size(), 1);
auto getPartialArg = [&](int pi) {
@ -1248,6 +1243,8 @@ ExprPtr TypecheckVisitor::transformCall(CallExpr *expr, const types::TypePtr &in
return -1;
},
known);
bool hasPartialArgs = partialStarArgs != nullptr,
hasPartialKwargs = partialKwstarArgs != nullptr;
if (isPartial) {
deactivateUnbounds(expr->args.back().value->getType().get());
expr->args.pop_back();
@ -1283,7 +1280,6 @@ ExprPtr TypecheckVisitor::transformCall(CallExpr *expr, const types::TypePtr &in
}
auto e = transform(expr->expr);
unify(expr->type, e->getType());
// LOG("-- {} / {}", e->toString(), e->type->debugString(true));
return e;
}
@ -1345,8 +1341,6 @@ ExprPtr TypecheckVisitor::transformCall(CallExpr *expr, const types::TypePtr &in
if (replacements[si]) {
if (replacements[si]->getFunc())
deactivateUnbounds(replacements[si].get());
if (auto pt = replacements[si]->getPartial())
deactivateUnbounds(pt->func.get());
calleeFn->generics[si + 1].type = calleeFn->args[si + 1] = replacements[si];
}
if (!isPartial) {
@ -1365,10 +1359,16 @@ ExprPtr TypecheckVisitor::transformCall(CallExpr *expr, const types::TypePtr &in
deactivateUnbounds(calleeFn.get());
std::vector<ExprPtr> newArgs;
for (auto &r : args)
if (!r.value->getEllipsis())
if (!r.value->getEllipsis()) {
newArgs.push_back(r.value);
newArgs.back()->setAttr(ExprAttr::SequenceItem);
}
newArgs.push_back(partialStarArgs);
if (hasPartialArgs)
newArgs.back()->setAttr(ExprAttr::SequenceItem);
newArgs.push_back(partialKwstarArgs);
if (hasPartialKwargs)
newArgs.back()->setAttr(ExprAttr::SequenceItem);
std::string var = ctx->cache->getTemporaryVar("partial");
ExprPtr call = nullptr;
@ -1383,12 +1383,9 @@ ExprPtr TypecheckVisitor::transformCall(CallExpr *expr, const types::TypePtr &in
N<CallExpr>(N<IdExpr>(partialTypeName), newArgs)),
N<IdExpr>(var));
}
call->setAttr(ExprAttr::Partial);
call = transform(call, false, allowVoidExpr);
seqassert(call->type->getRecord() &&
startswith(call->type->getRecord()->name, partialTypeName) &&
!call->type->getPartial(),
"bad partial transformation");
call->type = N<PartialType>(call->type->getRecord(), calleeFn, newMask);
seqassert(call->type->getPartial(), "expected partial type");
return call;
} else {
// Case 2. Normal function call.
@ -1629,16 +1626,19 @@ std::string TypecheckVisitor::generateFunctionStub(int n) {
std::string TypecheckVisitor::generatePartialStub(const std::vector<char> &mask,
types::FuncType *fn) {
std::string strMask(mask.size(), '1');
int tupleSize = 0;
int tupleSize = 0, genericSize = 0;
for (int i = 0; i < mask.size(); i++)
if (!mask[i])
strMask[i] = '0';
else if (!fn->ast->args[i].generic)
tupleSize++;
auto typeName = format(TYPE_PARTIAL "{}.{}", strMask, fn->ast->name);
if (!ctx->find(typeName))
// 2 for .starArgs and .kwstarArgs (empty tuples if fn does not have them)
else
genericSize++;
auto typeName = format(TYPE_PARTIAL "{}.{}", strMask, fn->toString());
if (!ctx->find(typeName)) {
ctx->cache->partials[typeName] = {fn->generalize(0)->getFunc(), mask};
generateTupleStub(tupleSize + 2, typeName, {}, false);
}
return typeName;
}
@ -1710,12 +1710,9 @@ ExprPtr TypecheckVisitor::partializeFunction(ExprPtr expr) {
N<CallExpr>(N<IdExpr>(partialTypeName), N<TupleExpr>(),
N<CallExpr>(N<IdExpr>(kwName)))),
N<IdExpr>(var));
call->setAttr(ExprAttr::Partial);
call = transform(call, false, allowVoidExpr);
seqassert(call->type->getRecord() &&
startswith(call->type->getRecord()->name, partialTypeName) &&
!call->type->getPartial(),
"bad partial transformation");
call->type = N<PartialType>(call->type->getRecord(), fn, mask);
seqassert(call->type->getPartial(), "expected partial type");
return call;
}
@ -1821,12 +1818,6 @@ TypecheckVisitor::findMatchingMethods(types::ClassType *typ,
}
}
if (score != -1) {
// std::vector<std::string> ar;
// for (auto &a: args) {
// if (a.first.empty()) ar.push_back(a.second->toString());
// else ar.push_back(format("{}: {}", a.first, a.second->toString()));
// }
// LOG("- {} vs {}", m->toString(), join(ar, "; "));
results.push_back(methods[mi]);
}
}
@ -1861,6 +1852,8 @@ bool TypecheckVisitor::wrapExpr(ExprPtr &expr, TypePtr expectedType,
// Case 7: wrap raw Seq functions into Partial(...) call for easy realization.
expr = partializeFunction(expr);
}
// Special case:
unify(expr->type, expectedType, undoOnSuccess);
return true;
}
@ -1951,7 +1944,6 @@ types::FuncTypePtr TypecheckVisitor::findDispatch(const std::string &fn) {
ctx->cache->functions[name].ast = ast;
ctx->cache->functions[name].type = typ;
prependStmts->push_back(ast);
// LOG("dispatch: {}", ast->toString(1));
return typ;
}

View File

@ -32,12 +32,11 @@ types::TypePtr TypecheckVisitor::realize(types::TypePtr typ) {
} else if (auto c = typ->getClass()) {
auto t = realizeType(c.get());
if (auto p = typ->getPartial()) {
if (auto rt = realize(p->func))
unify(rt, p->func);
// if (auto rt = realize(p->func))
// unify(rt, p->func);
return std::make_shared<PartialType>(t->getRecord(), p->func, p->known);
} else {
return t;
}
return t;
} else {
return nullptr;
}
@ -117,8 +116,9 @@ types::TypePtr TypecheckVisitor::realizeFunc(types::FuncType *type) {
try {
auto it =
ctx->cache->functions[type->ast->name].realizations.find(type->realizedName());
if (it != ctx->cache->functions[type->ast->name].realizations.end())
if (it != ctx->cache->functions[type->ast->name].realizations.end()) {
return it->second->type;
}
// Set up bases. Ensure that we have proper parent bases even during a realization
// of mutually recursive functions.
@ -150,6 +150,7 @@ types::TypePtr TypecheckVisitor::realizeFunc(types::FuncType *type) {
LOG_REALIZE("[realize] fn {} -> {} : base {} ; depth = {}", type->ast->name,
type->realizedName(), ctx->getBase(), depth);
{
// Timer trx(fmt::format("fn {}", type->realizedName()));
getLogger().level++;
ctx->realizationDepth++;
ctx->addBlock();
@ -161,11 +162,6 @@ types::TypePtr TypecheckVisitor::realizeFunc(types::FuncType *type) {
type->args[0],
{},
findSuperMethods(type->getFunc())});
// if (startswith(type->ast->name, "Foo")) {
// LOG(": {}", type->toString());
// for (auto &s: ctx->bases.back().supers)
// LOG(" - {}", s->toString());
// }
auto clonedAst = ctx->cache->functions[type->ast->name].ast->clone();
auto *ast = (FunctionStmt *)clonedAst.get();
addFunctionGenerics(type);
@ -177,13 +173,16 @@ types::TypePtr TypecheckVisitor::realizeFunc(types::FuncType *type) {
if (!isInternal)
for (int i = 0, j = 1; i < ast->args.size(); i++)
if (!ast->args[i].generic) {
seqassert(type->args[j] && type->args[j]->getUnbounds().empty(),
"unbound argument {}", type->args[j]->toString());
std::string varName = ast->args[i].name;
trimStars(varName);
ctx->add(TypecheckItem::Var, varName,
std::make_shared<LinkType>(
type->args[j++]->generalize(ctx->typecheckLevel)));
std::make_shared<LinkType>(type->args[j++]));
// N.B. this used to be:
// seqassert(type->args[j] && type->args[j]->getUnbounds().empty(),
// "unbound argument {}", type->args[j]->toString());
// type->args[j++]->generalize(ctx->typecheckLevel)
// no idea why... most likely an old artefact, BUT if seq or sequre
// fail with weird type errors try returning this and see if it works
}
// Need to populate realization table in advance to make recursive functions
@ -223,7 +222,9 @@ types::TypePtr TypecheckVisitor::realizeFunc(types::FuncType *type) {
// Realize the return type.
if (auto t = realize(type->args[0]))
unify(type->args[0], t);
LOG_REALIZE("done with {} / {}", type->realizedName(), oldKey);
LOG_REALIZE("[realize] done with {} / {} =>{}", type->realizedName(), oldKey,
time);
// trx.log();
// Create and store IR node and a realized AST to be used
// during the code generation.
@ -239,6 +240,7 @@ types::TypePtr TypecheckVisitor::realizeFunc(types::FuncType *type) {
} else {
r->ir = ctx->cache->module->Nr<ir::BodiedFunc>(type->realizedName());
}
r->ir->setUnmangledName(ctx->cache->reverseIdentifierLookup[type->ast->name]);
auto parent = type->funcParent;
if (!ast->attributes.parentClass.empty() &&
@ -408,6 +410,8 @@ std::pair<int, StmtPtr> TypecheckVisitor::inferTypes(StmtPtr result, bool keepLa
ir::types::Type *TypecheckVisitor::getLLVMType(const types::ClassType *t) {
auto realizedName = t->realizedTypeName();
if (!in(ctx->cache->classes[t->name].realizations, realizedName))
realizeType(const_cast<types::ClassType *>(t));
if (auto l = ctx->cache->classes[t->name].realizations[realizedName]->ir)
return l;
auto getLLVM = [&](const TypePtr &tt) {

View File

@ -508,6 +508,13 @@ void TypecheckVisitor::visit(ClassStmt *stmt) {
else
typ = std::make_shared<ClassType>(
stmt->name, ctx->cache->reverseIdentifierLookup[stmt->name]);
if (stmt->isRecord() && startswith(stmt->name, TYPE_PARTIAL)) {
seqassert(in(ctx->cache->partials, stmt->name),
"invalid partial initialization: {}", stmt->name);
typ = std::make_shared<PartialType>(typ->getRecord(),
ctx->cache->partials[stmt->name].first,
ctx->cache->partials[stmt->name].second);
}
typ->setSrcInfo(stmt->getSrcInfo());
ctx->add(TypecheckItem::Type, stmt->name, typ);
ctx->bases[0].visitedAsts[stmt->name] = {TypecheckItem::Type, typ};

View File

@ -481,6 +481,8 @@ public:
void visit(const dsl::CustomInstr *v) override;
template <typename NodeType> void process(const NodeType *v) {
if (!v)
return;
if (seenIds.find(v->getId()) != seenIds.end())
return;
seenIds.insert(v->getId());

View File

@ -1,5 +1,8 @@
#include "value.h"
#include "attribute.h"
#include "codon/sir/func.h"
#include "codon/sir/util/cloning.h"
#include "codon/sir/value.h"
#include "codon/util/fmt/ostream.h"
namespace codon {
@ -36,5 +39,141 @@ std::ostream &MemberAttribute::doFormat(std::ostream &os) const {
const std::string SrcInfoAttribute::AttributeName = "srcInfoAttribute";
const std::string TupleLiteralAttribute::AttributeName = "tupleLiteralAttribute";
std::unique_ptr<Attribute> TupleLiteralAttribute::clone(util::CloneVisitor &cv) const {
std::vector<Value *> elementsCloned;
for (auto *val : elements)
elementsCloned.push_back(cv.clone(val));
return std::make_unique<TupleLiteralAttribute>(elementsCloned);
}
std::unique_ptr<Attribute>
TupleLiteralAttribute::forceClone(util::CloneVisitor &cv) const {
std::vector<Value *> elementsCloned;
for (auto *val : elements)
elementsCloned.push_back(cv.forceClone(val));
return std::make_unique<TupleLiteralAttribute>(elementsCloned);
}
std::ostream &TupleLiteralAttribute::doFormat(std::ostream &os) const {
std::vector<std::string> strings;
for (auto *val : elements)
strings.push_back(fmt::format(FMT_STRING("{}"), *val));
fmt::print(os, FMT_STRING("({})"), fmt::join(strings.begin(), strings.end(), ","));
return os;
}
const std::string ListLiteralAttribute::AttributeName = "listLiteralAttribute";
std::unique_ptr<Attribute> ListLiteralAttribute::clone(util::CloneVisitor &cv) const {
std::vector<LiteralElement> elementsCloned;
for (auto &e : elements)
elementsCloned.push_back({cv.clone(e.value), e.star});
return std::make_unique<ListLiteralAttribute>(elementsCloned);
}
std::unique_ptr<Attribute>
ListLiteralAttribute::forceClone(util::CloneVisitor &cv) const {
std::vector<LiteralElement> elementsCloned;
for (auto &e : elements)
elementsCloned.push_back({cv.forceClone(e.value), e.star});
return std::make_unique<ListLiteralAttribute>(elementsCloned);
}
std::ostream &ListLiteralAttribute::doFormat(std::ostream &os) const {
std::vector<std::string> strings;
for (auto &e : elements)
strings.push_back(fmt::format(FMT_STRING("{}{}"), e.star ? "*" : "", *e.value));
fmt::print(os, FMT_STRING("[{}]"), fmt::join(strings.begin(), strings.end(), ","));
return os;
}
const std::string SetLiteralAttribute::AttributeName = "setLiteralAttribute";
std::unique_ptr<Attribute> SetLiteralAttribute::clone(util::CloneVisitor &cv) const {
std::vector<LiteralElement> elementsCloned;
for (auto &e : elements)
elementsCloned.push_back({cv.clone(e.value), e.star});
return std::make_unique<SetLiteralAttribute>(elementsCloned);
}
std::unique_ptr<Attribute>
SetLiteralAttribute::forceClone(util::CloneVisitor &cv) const {
std::vector<LiteralElement> elementsCloned;
for (auto &e : elements)
elementsCloned.push_back({cv.forceClone(e.value), e.star});
return std::make_unique<SetLiteralAttribute>(elementsCloned);
}
std::ostream &SetLiteralAttribute::doFormat(std::ostream &os) const {
std::vector<std::string> strings;
for (auto &e : elements)
strings.push_back(fmt::format(FMT_STRING("{}{}"), e.star ? "*" : "", *e.value));
fmt::print(os, FMT_STRING("set([{}])"),
fmt::join(strings.begin(), strings.end(), ","));
return os;
}
const std::string DictLiteralAttribute::AttributeName = "dictLiteralAttribute";
std::unique_ptr<Attribute> DictLiteralAttribute::clone(util::CloneVisitor &cv) const {
std::vector<DictLiteralAttribute::KeyValuePair> elementsCloned;
for (auto &val : elements)
elementsCloned.push_back(
{cv.clone(val.key), val.value ? cv.clone(val.value) : nullptr});
return std::make_unique<DictLiteralAttribute>(elementsCloned);
}
std::unique_ptr<Attribute>
DictLiteralAttribute::forceClone(util::CloneVisitor &cv) const {
std::vector<DictLiteralAttribute::KeyValuePair> elementsCloned;
for (auto &val : elements)
elementsCloned.push_back(
{cv.forceClone(val.key), val.value ? cv.forceClone(val.value) : nullptr});
return std::make_unique<DictLiteralAttribute>(elementsCloned);
}
std::ostream &DictLiteralAttribute::doFormat(std::ostream &os) const {
std::vector<std::string> strings;
for (auto &val : elements) {
if (val.value) {
strings.push_back(fmt::format(FMT_STRING("{}:{}"), *val.key, *val.value));
} else {
strings.push_back(fmt::format(FMT_STRING("**{}"), *val.key));
}
}
fmt::print(os, FMT_STRING("dict([{}])"),
fmt::join(strings.begin(), strings.end(), ","));
return os;
}
const std::string PartialFunctionAttribute::AttributeName = "partialFunctionAttribute";
std::unique_ptr<Attribute>
PartialFunctionAttribute::clone(util::CloneVisitor &cv) const {
std::vector<Value *> argsCloned;
for (auto *val : args)
argsCloned.push_back(cv.clone(val));
return std::make_unique<PartialFunctionAttribute>(name, argsCloned);
}
std::unique_ptr<Attribute>
PartialFunctionAttribute::forceClone(util::CloneVisitor &cv) const {
std::vector<Value *> argsCloned;
for (auto *val : args)
argsCloned.push_back(cv.forceClone(val));
return std::make_unique<PartialFunctionAttribute>(name, argsCloned);
}
std::ostream &PartialFunctionAttribute::doFormat(std::ostream &os) const {
std::vector<std::string> strings;
for (auto *val : args)
strings.push_back(val ? fmt::format(FMT_STRING("{}"), *val) : "...");
fmt::print(os, FMT_STRING("{}({})"), name,
fmt::join(strings.begin(), strings.end(), ","));
return os;
}
} // namespace ir
} // namespace codon

View File

@ -14,6 +14,13 @@
namespace codon {
namespace ir {
class Func;
class Value;
namespace util {
class CloneVisitor;
}
/// Base for SIR attributes.
struct Attribute {
virtual ~Attribute() noexcept = default;
@ -26,14 +33,15 @@ struct Attribute {
}
/// @return a clone of the attribute
std::unique_ptr<Attribute> clone() const {
return std::unique_ptr<Attribute>(doClone());
virtual std::unique_ptr<Attribute> clone(util::CloneVisitor &cv) const = 0;
/// @return a clone of the attribute
virtual std::unique_ptr<Attribute> forceClone(util::CloneVisitor &cv) const {
return clone(cv);
}
private:
virtual std::ostream &doFormat(std::ostream &os) const = 0;
virtual Attribute *doClone() const = 0;
};
/// Attribute containing SrcInfo
@ -48,10 +56,12 @@ struct SrcInfoAttribute : public Attribute {
/// @param info the source info
explicit SrcInfoAttribute(codon::SrcInfo info) : info(std::move(info)) {}
std::unique_ptr<Attribute> clone(util::CloneVisitor &cv) const override {
return std::make_unique<SrcInfoAttribute>(*this);
}
private:
std::ostream &doFormat(std::ostream &os) const override { return os << info; }
Attribute *doClone() const override { return new SrcInfoAttribute(*this); }
};
/// Attribute containing function information
@ -76,10 +86,12 @@ struct KeyValueAttribute : public Attribute {
/// string if none
std::string get(const std::string &key) const;
std::unique_ptr<Attribute> clone(util::CloneVisitor &cv) const override {
return std::make_unique<KeyValueAttribute>(*this);
}
private:
std::ostream &doFormat(std::ostream &os) const override;
Attribute *doClone() const override { return new KeyValueAttribute(*this); }
};
/// Attribute containing type member information
@ -95,10 +107,116 @@ struct MemberAttribute : public Attribute {
explicit MemberAttribute(std::map<std::string, SrcInfo> memberSrcInfo)
: memberSrcInfo(std::move(memberSrcInfo)) {}
std::unique_ptr<Attribute> clone(util::CloneVisitor &cv) const override {
return std::make_unique<MemberAttribute>(*this);
}
private:
std::ostream &doFormat(std::ostream &os) const override;
};
Attribute *doClone() const override { return new MemberAttribute(*this); }
/// Attribute attached to IR structures corresponding to tuple literals
struct TupleLiteralAttribute : public Attribute {
static const std::string AttributeName;
/// values contained in tuple literal
std::vector<Value *> elements;
explicit TupleLiteralAttribute(std::vector<Value *> elements)
: elements(std::move(elements)) {}
std::unique_ptr<Attribute> clone(util::CloneVisitor &cv) const override;
std::unique_ptr<Attribute> forceClone(util::CloneVisitor &cv) const override;
private:
std::ostream &doFormat(std::ostream &os) const override;
};
/// Information about an element in a collection literal
struct LiteralElement {
/// the element value
Value *value;
/// true if preceded by "*", as in "[*x]"
bool star;
};
/// Attribute attached to IR structures corresponding to list literals
struct ListLiteralAttribute : public Attribute {
static const std::string AttributeName;
/// elements contained in list literal
std::vector<LiteralElement> elements;
explicit ListLiteralAttribute(std::vector<LiteralElement> elements)
: elements(std::move(elements)) {}
std::unique_ptr<Attribute> clone(util::CloneVisitor &cv) const override;
std::unique_ptr<Attribute> forceClone(util::CloneVisitor &cv) const override;
private:
std::ostream &doFormat(std::ostream &os) const override;
};
/// Attribute attached to IR structures corresponding to set literals
struct SetLiteralAttribute : public Attribute {
static const std::string AttributeName;
/// elements contained in set literal
std::vector<LiteralElement> elements;
explicit SetLiteralAttribute(std::vector<LiteralElement> elements)
: elements(std::move(elements)) {}
std::unique_ptr<Attribute> clone(util::CloneVisitor &cv) const override;
std::unique_ptr<Attribute> forceClone(util::CloneVisitor &cv) const override;
private:
std::ostream &doFormat(std::ostream &os) const override;
};
/// Attribute attached to IR structures corresponding to dict literals
struct DictLiteralAttribute : public Attribute {
struct KeyValuePair {
/// the key in the literal
Value *key;
/// the value in the literal, or null if key is being star-unpacked
Value *value;
};
static const std::string AttributeName;
/// keys and values contained in dict literal
std::vector<KeyValuePair> elements;
explicit DictLiteralAttribute(std::vector<KeyValuePair> elements)
: elements(std::move(elements)) {}
std::unique_ptr<Attribute> clone(util::CloneVisitor &cv) const override;
std::unique_ptr<Attribute> forceClone(util::CloneVisitor &cv) const override;
private:
std::ostream &doFormat(std::ostream &os) const override;
};
/// Attribute attached to IR structures corresponding to partial functions
struct PartialFunctionAttribute : public Attribute {
static const std::string AttributeName;
/// base name of the function being used in the partial
std::string name;
/// partial arguments, or null if none
/// e.g. "f(a, ..., b)" has elements [a, null, b]
std::vector<Value *> args;
PartialFunctionAttribute(const std::string &name, std::vector<Value *> args)
: name(name), args(std::move(args)) {}
std::unique_ptr<Attribute> clone(util::CloneVisitor &cv) const override;
std::unique_ptr<Attribute> forceClone(util::CloneVisitor &cv) const override;
private:
std::ostream &doFormat(std::ostream &os) const override;
};
} // namespace ir

View File

@ -88,8 +88,7 @@ void LLVMVisitor::registerGlobal(const Var *var) {
return;
if (auto *f = cast<Func>(var)) {
makeLLVMFunction(f);
insertFunc(f, func);
insertFunc(f, makeLLVMFunction(f));
} else {
llvm::Type *llvmType = getLLVMType(var->getType());
if (llvmType->isVoidTy()) {
@ -145,6 +144,7 @@ llvm::Value *LLVMVisitor::getVar(const Var *var) {
}
} else {
registerGlobal(var);
it = vars.find(var->getId());
return it->second;
}
}
@ -177,6 +177,7 @@ llvm::Function *LLVMVisitor::getFunc(const Func *func) {
}
} else {
registerGlobal(func);
it = funcs.find(func->getId());
return it->second;
}
}
@ -210,7 +211,34 @@ std::unique_ptr<llvm::Module> LLVMVisitor::makeModule(llvm::LLVMContext &context
}
std::pair<std::unique_ptr<llvm::Module>, std::unique_ptr<llvm::LLVMContext>>
LLVMVisitor::takeModule(const SrcInfo *src) {
LLVMVisitor::takeModule(Module *module, const SrcInfo *src) {
// process any new functions or globals
if (module) {
std::unordered_set<id_t> funcsToProcess;
for (auto *var : *module) {
auto id = var->getId();
if (auto *func = cast<Func>(var)) {
if (funcs.find(id) != funcs.end())
continue;
else
funcsToProcess.insert(id);
} else {
if (vars.find(id) != vars.end())
continue;
}
registerGlobal(var);
}
for (auto *var : *module) {
if (auto *func = cast<Func>(var)) {
if (funcsToProcess.find(func->getId()) != funcsToProcess.end()) {
process(func);
}
}
}
}
db.builder->finalize();
auto currentContext = std::move(context);
auto currentModule = std::move(M);
@ -220,10 +248,25 @@ LLVMVisitor::takeModule(const SrcInfo *src) {
func = nullptr;
block = nullptr;
value = nullptr;
for (auto &it : vars)
it.second = nullptr;
for (auto &it : funcs)
it.second = nullptr;
for (auto it = funcs.begin(); it != funcs.end();) {
if (it->second && it->second->hasPrivateLinkage()) {
it = funcs.erase(it);
} else {
it->second = nullptr;
++it;
}
}
for (auto it = vars.begin(); it != vars.end();) {
if (it->second && !llvm::isa<llvm::GlobalValue>(it->second)) {
it = vars.erase(it);
} else {
it->second = nullptr;
++it;
}
}
coro.reset();
loops.clear();
trycatch.clear();
@ -575,8 +618,7 @@ void LLVMVisitor::visit(const Module *x) {
}
const Func *main = x->getMainFunc();
makeLLVMFunction(main);
llvm::FunctionCallee realMain = func;
llvm::FunctionCallee realMain = makeLLVMFunction(main);
process(main);
setDebugInfoForNode(nullptr);
@ -712,12 +754,15 @@ llvm::DISubprogram *LLVMVisitor::getDISubprogramForFunc(const Func *x) {
return subprogram;
}
void LLVMVisitor::makeLLVMFunction(const Func *x) {
llvm::Function *LLVMVisitor::makeLLVMFunction(const Func *x) {
// process LLVM functions in full immediately
if (auto *llvmFunc = cast<LLVMFunc>(x)) {
auto *oldFunc = func;
process(llvmFunc);
setDebugInfoForNode(nullptr);
return;
auto *newFunc = func;
func = oldFunc;
return newFunc;
}
auto *funcType = cast<types::FuncType>(x->getType());
@ -730,11 +775,12 @@ void LLVMVisitor::makeLLVMFunction(const Func *x) {
auto *llvmFuncType =
llvm::FunctionType::get(returnType, argTypes, funcType->isVariadic());
const std::string functionName = getNameForFunction(x);
func = llvm::cast<llvm::Function>(
auto *f = llvm::cast<llvm::Function>(
M->getOrInsertFunction(functionName, llvmFuncType).getCallee());
if (!cast<ExternalFunc>(x)) {
func->setSubprogram(getDISubprogramForFunc(x));
f->setSubprogram(getDISubprogramForFunc(x));
}
return f;
}
void LLVMVisitor::makeYield(llvm::Value *value, bool finalYield) {
@ -801,7 +847,7 @@ void LLVMVisitor::visit(const InternalFunc *x) {
auto *funcType = cast<FuncType>(x->getType());
std::vector<Type *> argTypes(funcType->begin(), funcType->end());
func->setLinkage(getDefaultLinkage());
func->setLinkage(llvm::GlobalValue::PrivateLinkage);
func->addFnAttr(llvm::Attribute::AttrKind::AlwaysInline);
std::vector<llvm::Value *> args;
for (auto it = func->arg_begin(); it != func->arg_end(); ++it) {
@ -964,7 +1010,7 @@ void LLVMVisitor::visit(const LLVMFunc *x) {
seqassert(!fail, "linking failed");
func = M->getFunction(getNameForFunction(x));
seqassert(func, "function not linked in");
func->setLinkage(getDefaultLinkage());
func->setLinkage(llvm::GlobalValue::PrivateLinkage);
func->addFnAttr(llvm::Attribute::AttrKind::AlwaysInline);
func->setSubprogram(getDISubprogramForFunc(x));
@ -988,10 +1034,11 @@ void LLVMVisitor::visit(const BodiedFunc *x) {
setDebugInfoForNode(x);
auto *fnAttributes = x->getAttribute<KeyValueAttribute>();
if (fnAttributes && fnAttributes->has("std.internal.attributes.export")) {
if (x->isJIT() ||
(fnAttributes && fnAttributes->has("std.internal.attributes.export"))) {
func->setLinkage(llvm::GlobalValue::ExternalLinkage);
} else {
func->setLinkage(getDefaultLinkage());
func->setLinkage(llvm::GlobalValue::PrivateLinkage);
}
if (fnAttributes && fnAttributes->has("std.internal.attributes.inline")) {
func->addFnAttr(llvm::Attribute::AttrKind::AlwaysInline);

View File

@ -167,7 +167,7 @@ private:
// General function helpers
llvm::Value *call(llvm::FunctionCallee callee, llvm::ArrayRef<llvm::Value *> args);
void makeLLVMFunction(const Func *);
llvm::Function *makeLLVMFunction(const Func *);
void makeYield(llvm::Value *value = nullptr, bool finalYield = false);
std::string buildLLVMCodeString(const LLVMFunc *);
void callStage(const PipelineFlow::Stage *stage);
@ -290,10 +290,11 @@ public:
/// Returns the current module/LLVM context and replaces them
/// with new, fresh ones. References to variables or functions
/// from the old module will be included as "external".
/// @param module the IR module
/// @param src source information for the new module
/// @return the current module/context, replaced internally
std::pair<std::unique_ptr<llvm::Module>, std::unique_ptr<llvm::LLVMContext>>
takeModule(const SrcInfo *src = nullptr);
takeModule(Module *module, const SrcInfo *src = nullptr);
/// Sets current debug info based on a given node.
/// @param node the node whose debug info to use

View File

@ -142,7 +142,8 @@ Func *Module::getOrRealizeFunc(const std::string &funcName,
try {
return cache->realizeFunction(func, arg, gens);
} catch (const exc::ParserException &e) {
LOG_IR("getOrRealizeFunc parser error: {}", e.what());
for (int i = 0; i < e.messages.size(); i++)
LOG_IR("getOrRealizeFunc parser error at {}: {}", e.locations[i], e.messages[i]);
return nullptr;
}
}

View File

@ -280,7 +280,7 @@ struct CanonConstSub : public RewriteRule {
Value *newCall = nullptr;
if (util::isConst<int64_t>(rhs)) {
auto c = util::getConst<int64_t>(rhs);
if (c != -(static_cast<int64_t>(1) << 63)) // ensure no overflow
if (c != -(1ull << 63)) // ensure no overflow
newCall = *lhs + *(M->getInt(-c));
} else if (util::isConst<double>(rhs)) {
auto c = util::getConst<double>(rhs);

View File

@ -139,12 +139,18 @@ void PassManager::invalidate(const std::string &key) {
}
}
void PassManager::registerStandardPasses(bool debug) {
if (debug) {
void PassManager::registerStandardPasses(PassManager::Init init) {
switch (init) {
case Init::EMPTY:
break;
case Init::DEBUG: {
registerPass(std::make_unique<lowering::PipelineLowering>());
registerPass(std::make_unique<lowering::ImperativeForFlowLowering>());
registerPass(std::make_unique<parallel::OpenMPPass>());
} else {
break;
}
case Init::RELEASE:
case Init::JIT: {
// Pythonic
registerPass(std::make_unique<pythonic::DictArithmeticOptimization>());
registerPass(std::make_unique<pythonic::StrAdditionOptimization>());
@ -174,10 +180,19 @@ void PassManager::registerStandardPasses(bool debug) {
// parallel
registerPass(std::make_unique<parallel::OpenMPPass>());
registerPass(std::make_unique<folding::FoldingPassGroup>(seKey2, rdKey, globalKey,
/*runGlobalDemoton=*/true),
/*insertBefore=*/"", {seKey2, rdKey, globalKey},
{seKey2, rdKey, cfgKey, globalKey});
if (init != Init::JIT) {
// Don't demote globals in JIT mode, since they might be used later
// by another user input.
registerPass(
std::make_unique<folding::FoldingPassGroup>(seKey2, rdKey, globalKey,
/*runGlobalDemoton=*/true),
/*insertBefore=*/"", {seKey2, rdKey, globalKey},
{seKey2, rdKey, cfgKey, globalKey});
}
break;
}
default:
seqassert(false, "unknown PassManager init value");
}
}

View File

@ -95,6 +95,7 @@ public:
EMPTY,
DEBUG,
RELEASE,
JIT,
};
static const int PASS_IT_MAX;
@ -102,16 +103,7 @@ public:
explicit PassManager(Init init, std::vector<std::string> disabled = {})
: km(), passes(), analyses(), executionOrder(), results(),
disabled(std::move(disabled)) {
switch (init) {
case Init::EMPTY:
break;
case Init::DEBUG:
registerStandardPasses(true);
break;
case Init::RELEASE:
registerStandardPasses(false);
break;
}
registerStandardPasses(init);
}
explicit PassManager(bool debug = false, std::vector<std::string> disabled = {})
@ -156,7 +148,7 @@ public:
private:
void runPass(Module *module, const std::string &name);
void registerStandardPasses(bool debug = false);
void registerStandardPasses(Init init);
void runAnalysis(Module *module, const std::string &name);
void invalidate(const std::string &key);
};

View File

@ -82,7 +82,7 @@ public:
for (auto it = other->attributes_begin(); it != other->attributes_end(); ++it) {
const auto *attr = other->getAttribute(*it);
if (attr->needsClone()) {
ctx[id]->setAttribute(attr->clone(), *it);
ctx[id]->setAttribute(attr->clone(*this), *it);
}
}
}
@ -125,7 +125,7 @@ public:
for (auto it = other->attributes_begin(); it != other->attributes_end(); ++it) {
const auto *attr = other->getAttribute(*it);
if (attr->needsClone()) {
ctx[id]->setAttribute(attr->clone(), *it);
ctx[id]->setAttribute(attr->forceClone(*this), *it);
}
}
}

View File

@ -68,8 +68,10 @@ public:
}
void visit(BodiedFunc *f) override {
seen.insert(f->getBody()->getId());
process(f->getBody());
if (f->getBody()) {
seen.insert(f->getBody()->getId());
process(f->getBody());
}
}
LAMBDA_VISIT(VarValue);

View File

@ -1,7 +1,7 @@
#pragma once
#include "llvm/Support/Path.h"
#include <chrono>
#include <filesystem>
#include <iostream>
#include <ostream>
@ -123,7 +123,7 @@ struct SrcInfo {
SrcInfo() : SrcInfo("", 0, 0, 0) {}
friend std::ostream &operator<<(std::ostream &out, const codon::SrcInfo &src) {
out << std::filesystem::path(src.file).filename() << ":" << src.line << ":"
out << llvm::sys::path::filename(src.file).str() << ":" << src.line << ":"
<< src.col;
return out;
}

View File

@ -1,9 +1,11 @@
#include "codon.h"
#include "jupyter.h"
#ifdef CODON_JUPYTER
#include <codecvt>
#include <dirent.h>
#include <fcntl.h>
#include <iostream>
#include <locale>
#include <nlohmann/json.hpp>
#include <unistd.h>
#include <xeus/xhelper.hpp>
@ -50,8 +52,24 @@ nl::json CodonJupyter::execute_request_impl(int execution_counter, const string
ast::join(backtrace, " \n"));
});
if (failed.empty()) {
std::string out = *result;
nl::json pub_data;
pub_data["text/plain"] = *result;
if (ast::startswith(out, "\x00\x00__codon/mime__\x00")) {
std::string mime = "";
int i = 17;
for (; i < out.size() && out[i]; i++)
mime += out[i];
if (i < out.size() && !out[i]) {
i += 1;
} else {
mime = "text/plain";
i = 0;
}
pub_data[mime] = out.substr(i);
LOG("> {}: {}", mime, out.substr(i));
} else {
pub_data["text/plain"] = out;
}
publish_execution_result(execution_counter, move(pub_data), nl::json::object());
return nl::json{{"status", "ok"},
{"payload", nl::json::array()},

View File

@ -339,6 +339,9 @@ class Counter[T](Dict[T,int]):
result |= other
return result
def __dict_do_op_throws__[F, Z](self, key: T, other: Z, op: F):
self.__dict_do_op__(key, other, 0, op)
@extend
class Dict:

View File

@ -38,3 +38,10 @@ def distributive():
def C():
pass
@__attribute__
def realize_without_self():
pass
@__attribute__
def overload():
pass

View File

@ -331,10 +331,13 @@ class int:
return result
def _jit_display(x, s: Static[str]):
if hasattr(x, "__repr_pretty__") and s == "jupyter":
print x.__repr_pretty__()
def _jit_display(x, s: Static[str], bundle: Set[str] = Set[str]()):
if hasattr(x, "_repr_mimebundle_") and s == "jupyter":
d = x._repr_mimebundle_(bundle)
# TODO: pick appropriate mime
mime = next(d.keys()) # just pick first
print(f"\x00\x00__codon/mime__\x00{mime}\x00{d[mime]}", end='')
elif hasattr(x, "__repr__"):
print x.__repr__()
print(x.__repr__(), end='')
elif hasattr(x, "__str__"):
print x.__str__()
print(x.__str__(), end='')

View File

@ -35,9 +35,43 @@ PyDict_SetItem = Function[[cobj, cobj, cobj], cobj](cobj())
PyDict_Next = Function[[cobj, Ptr[int], Ptr[cobj], Ptr[cobj]], int](cobj())
PyObject_GetIter = Function[[cobj], cobj](cobj())
PyIter_Next = Function[[cobj], cobj](cobj())
PyObject_HasAttrString = Function[[cobj, cobj], int](cobj())
PyImport_AddModule = Function[[cobj], cobj](cobj())
_PY_MODULE_CACHE = Dict[str, pyobj]()
_PY_INIT = """
import io
clsf = None
clsa = None
plt = None
try:
import matplotlib.figure
import matplotlib.pyplot
plt = matplotlib.pyplot
clsf = matplotlib.figure.Figure
clsa = matplotlib.artist.Artist
except ModuleNotFoundError:
pass
def __codon_repr__(fig):
if clsf and isinstance(fig, clsf):
stream = io.StringIO()
fig.savefig(stream, format="svg")
return 'image/svg+xml', stream.getvalue()
elif clsa and isinstance(fig, list) and all(
isinstance(i, clsa) for i in fig
):
stream = io.StringIO()
plt.gcf().savefig(stream, format="svg")
return 'image/svg+xml', stream.getvalue()
elif hasattr(fig, "_repr_html_"):
return 'text/html', fig._repr_html_()
else:
return 'text/plain', fig.__repr__()
"""
_PY_INITIALIZED = False
def init():
global _PY_INITIALIZED
@ -115,8 +149,14 @@ def init():
PyObject_GetIter = dlsym(hnd, "PyObject_GetIter")
global PyIter_Next
PyIter_Next = dlsym(hnd, "PyIter_Next")
global PyObject_HasAttrString
PyObject_HasAttrString = dlsym(hnd, "PyObject_HasAttrString")
global PyImport_AddModule
PyImport_AddModule = dlsym(hnd, "PyImport_AddModule")
Py_Initialize()
PyRun_SimpleString(_PY_INIT.c_str())
_PY_INITIALIZED = True
def ensure_initialized():
@ -229,10 +269,19 @@ class pyobj:
def get(self, T: type) -> T:
return T.__from_py__(self)
def _main_module():
m = PyImport_AddModule("__main__".c_str())
return pyobj(m)
def _repr_mimebundle_(self, bundle = Set[str]()):
fn = pyobj._main_module()._getattr("__codon_repr__")
assert fn.p != cobj(), "cannot find python.__codon_repr__"
mime, txt = fn.__call__(self).get(Tuple[str, str])
return {mime: txt}
def none():
raise NotImplementedError()
# Type conversions
def py(x) -> pyobj:

View File

@ -381,6 +381,8 @@ print log(5.5) #: 1.70475
#%% import_c_dylib,barebones
from internal.dlopen import dlext
RT = "./libcodonrt." + dlext()
if RT[-3:] == ".so":
RT = "build/" + RT[2:]
from C import RT.seq_str_int(int) -> str as sp
print sp(65) #: 65
@ -994,4 +996,27 @@ def foo(return_, pass_, yield_, break_, continue_, print_, assert_):
assert_.append(7)
return return_, pass_, yield_, break_, continue_, print_, assert_
print foo([1], [1], [1], [1], [1], [1], [1])
#: ([1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [1, 7])
#: ([1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [1, 7])
#%% class_deduce,barebones
@deduce
class Foo:
def __init__(self, x):
self.x = [x]
self.y = 1, x
f = Foo(1)
print(f.x, f.y, f.__class__) #: [1] (1, 1) Foo[List[int],Tuple[int,int]]
f: Foo = Foo('s')
print(f.x, f.y, f.__class__) #: ['s'] (1, 's') Foo[List[str],Tuple[int,str]]
@deduce
class Bar:
def __init__(self, y):
self.y = Foo(y)
b = Bar(3.1)
print(b.y.x, b.__class__) #: [3.1] Bar[Foo[List[float],Tuple[int,float]]]

View File

@ -1113,11 +1113,13 @@ print methodcaller('index')(v, 42) #: 1
def foo(x):
return 1, x
@overload
def foo(x, y):
def foo(x, y):
return f'{x}_{y}'
return 2, foo(x, y)
@overload
def foo(x):
if x == '':
return 3, 0
@ -1126,9 +1128,19 @@ def foo(x):
print foo('hi') #: (3, 2)
print foo('hi', 1) #: (2, 'hi_1')
#%% fn_shadow,barebones
def foo(x):
return 1, x
print foo('hi') #: (1, 'hi')
def foo(x):
return 2, x
print foo('hi') #: (2, 'hi')
#%% fn_overloads_error,barebones
def foo(x):
return 1, x
@overload
def foo(x, y):
return 2, x, y
foo('hooooooooy!', 1, 2) #! cannot find an overload 'foo' with arguments = str, = int, = int