mirror of https://github.com/exaloop/codon
Update import handling (#580)
parent
3c4272d92a
commit
c214e2c65d
|
@ -77,6 +77,7 @@ const std::string Module::GE_MAGIC_NAME = "__ge__";
|
|||
const std::string Module::POS_MAGIC_NAME = "__pos__";
|
||||
const std::string Module::NEG_MAGIC_NAME = "__neg__";
|
||||
const std::string Module::INVERT_MAGIC_NAME = "__invert__";
|
||||
const std::string Module::ABS_MAGIC_NAME = "__abs__";
|
||||
|
||||
const std::string Module::ADD_MAGIC_NAME = "__add__";
|
||||
const std::string Module::SUB_MAGIC_NAME = "__sub__";
|
||||
|
@ -125,6 +126,7 @@ const std::string Module::FLOAT_MAGIC_NAME = "__float__";
|
|||
const std::string Module::BOOL_MAGIC_NAME = "__bool__";
|
||||
const std::string Module::STR_MAGIC_NAME = "__str__";
|
||||
const std::string Module::REPR_MAGIC_NAME = "__repr__";
|
||||
const std::string Module::CALL_MAGIC_NAME = "__call__";
|
||||
|
||||
const std::string Module::GETITEM_MAGIC_NAME = "__getitem__";
|
||||
const std::string Module::SETITEM_MAGIC_NAME = "__setitem__";
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
static const std::string POS_MAGIC_NAME;
|
||||
static const std::string NEG_MAGIC_NAME;
|
||||
static const std::string INVERT_MAGIC_NAME;
|
||||
static const std::string ABS_MAGIC_NAME;
|
||||
|
||||
static const std::string ADD_MAGIC_NAME;
|
||||
static const std::string SUB_MAGIC_NAME;
|
||||
|
@ -97,6 +98,7 @@ public:
|
|||
static const std::string BOOL_MAGIC_NAME;
|
||||
static const std::string STR_MAGIC_NAME;
|
||||
static const std::string REPR_MAGIC_NAME;
|
||||
static const std::string CALL_MAGIC_NAME;
|
||||
|
||||
static const std::string GETITEM_MAGIC_NAME;
|
||||
static const std::string SETITEM_MAGIC_NAME;
|
||||
|
|
|
@ -39,9 +39,17 @@ std::vector<Generic> Type::doGetGenerics() const {
|
|||
ret.emplace_back(
|
||||
getModule()->getCache()->realizeType(cls, extractTypes(cls->generics)));
|
||||
else {
|
||||
seqassertn(g.type->getStatic()->expr->staticValue.type == ast::StaticValue::INT,
|
||||
"IR only supports int statics [{}]", g.type->getSrcInfo());
|
||||
ret.emplace_back(g.type->getStatic()->expr->staticValue.getInt());
|
||||
switch (g.type->getStatic()->expr->staticValue.type) {
|
||||
case ast::StaticValue::INT:
|
||||
ret.emplace_back(g.type->getStatic()->expr->staticValue.getInt());
|
||||
break;
|
||||
case ast::StaticValue::STRING:
|
||||
ret.emplace_back(g.type->getStatic()->expr->staticValue.getString());
|
||||
break;
|
||||
default:
|
||||
seqassertn(false, "IR only supports int or str statics [{}]",
|
||||
g.type->getSrcInfo());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,6 +80,8 @@ struct Cache : public std::enable_shared_from_this<Cache> {
|
|||
std::vector<std::string> content;
|
||||
/// Relative module name (e.g., `foo.bar`)
|
||||
std::string moduleName;
|
||||
/// Set if loaded at toplevel
|
||||
bool loadedAtToplevel = true;
|
||||
};
|
||||
|
||||
/// Absolute path of seqc executable (if available).
|
||||
|
|
|
@ -47,38 +47,32 @@ void SimplifyVisitor::visit(ImportStmt *stmt) {
|
|||
}
|
||||
|
||||
// If the file has not been seen before, load it into cache
|
||||
if (ctx->cache->imports.find(file->path) == ctx->cache->imports.end())
|
||||
bool handled = true;
|
||||
if (ctx->cache->imports.find(file->path) == ctx->cache->imports.end()) {
|
||||
resultStmt = transformNewImport(*file);
|
||||
if (!resultStmt)
|
||||
handled = false; // we need an import
|
||||
}
|
||||
|
||||
const auto &import = ctx->cache->imports[file->path];
|
||||
std::string importVar = import.importVar;
|
||||
std::string importDoneVar = importVar + "_done";
|
||||
if (!import.loadedAtToplevel)
|
||||
handled = false;
|
||||
|
||||
// Construct `if _import_done.__invert__(): (_import(); _import_done = True)`.
|
||||
// Do not do this during the standard library loading (we assume that standard library
|
||||
// imports are "clean" and do not need guards). Note that the importVar is empty if
|
||||
// the import has been loaded during the standard library loading.
|
||||
if (!ctx->isStdlibLoading && !importVar.empty()) {
|
||||
auto u = N<AssignStmt>(N<IdExpr>(importDoneVar), N<BoolExpr>(true));
|
||||
u->setUpdate();
|
||||
resultStmt =
|
||||
N<IfStmt>(N<CallExpr>(N<DotExpr>(importDoneVar, "__invert__")),
|
||||
N<SuiteStmt>(N<ExprStmt>(N<CallExpr>(N<IdExpr>(importVar))), u));
|
||||
if (!handled) {
|
||||
resultStmt = N<ExprStmt>(N<CallExpr>(N<IdExpr>(importVar + ":0")));
|
||||
LOG_TYPECHECK("[import] loading {}", importVar);
|
||||
}
|
||||
|
||||
// Import requested identifiers from the import's scope to the current scope
|
||||
if (!stmt->what) {
|
||||
// Case: import foo
|
||||
auto name = stmt->as.empty() ? path : stmt->as;
|
||||
auto var = importVar + "_var";
|
||||
// Construct `import_var = Import([module], [path])` (for printing imports etc.)
|
||||
resultStmt = N<SuiteStmt>(
|
||||
resultStmt, transform(N<AssignStmt>(N<IdExpr>(var),
|
||||
N<CallExpr>(N<IdExpr>("Import"),
|
||||
N<StringExpr>(file->module),
|
||||
N<StringExpr>(file->path)),
|
||||
N<IdExpr>("Import"))));
|
||||
ctx->addVar(name, var, stmt->getSrcInfo())->importPath = file->path;
|
||||
ctx->addVar(name, importVar, stmt->getSrcInfo())->importPath = file->path;
|
||||
} else if (stmt->what->isId("*")) {
|
||||
// Case: from foo import *
|
||||
seqassert(stmt->as.empty(), "renamed star-import");
|
||||
|
@ -314,14 +308,29 @@ StmtPtr SimplifyVisitor::transformNewImport(const ImportFile &file) {
|
|||
ictx->isStdlibLoading = ctx->isStdlibLoading;
|
||||
ictx->moduleName = file;
|
||||
auto import = ctx->cache->imports.insert({file.path, {file.path, ictx}}).first;
|
||||
import->second.loadedAtToplevel =
|
||||
ctx->cache->imports[ctx->moduleName.path].loadedAtToplevel &&
|
||||
(ctx->isStdlibLoading || (ctx->isGlobal() && ctx->scope.blocks.size() == 1));
|
||||
auto importVar = import->second.importVar =
|
||||
ctx->cache->getTemporaryVar(format("import_{}", file.module));
|
||||
import->second.moduleName = file.module;
|
||||
LOG_TYPECHECK("[import] initializing {} ({})", importVar,
|
||||
import->second.loadedAtToplevel);
|
||||
|
||||
// __name__ = [import name]
|
||||
StmtPtr n =
|
||||
N<AssignStmt>(N<IdExpr>("__name__"), N<StringExpr>(ictx->moduleName.module));
|
||||
if (ictx->moduleName.module == "internal.core") {
|
||||
StmtPtr n = nullptr;
|
||||
if (ictx->moduleName.module != "internal.core") {
|
||||
// str is not defined when loading internal.core; __name__ is not needed anyway
|
||||
n = nullptr;
|
||||
n = N<AssignStmt>(N<IdExpr>("__name__"), N<StringExpr>(ictx->moduleName.module));
|
||||
preamble->push_back(N<AssignStmt>(
|
||||
N<IdExpr>(importVar),
|
||||
N<CallExpr>(N<IdExpr>("Import.__new__"), N<StringExpr>(file.module),
|
||||
N<StringExpr>(file.path), N<BoolExpr>(false)),
|
||||
N<IdExpr>("Import")));
|
||||
auto var = ctx->addAlwaysVisible(
|
||||
std::make_shared<SimplifyItem>(SimplifyItem::Var, ctx->getBaseName(), importVar,
|
||||
ctx->getModule(), std::vector<int>{0}));
|
||||
ctx->cache->addGlobal(importVar);
|
||||
}
|
||||
n = N<SuiteStmt>(n, parseFile(ctx->cache, file.path));
|
||||
n = SimplifyVisitor(ictx, preamble).transform(n);
|
||||
|
@ -335,20 +344,15 @@ StmtPtr SimplifyVisitor::transformNewImport(const ImportFile &file) {
|
|||
// statements are executed before the user-provided code.
|
||||
return N<SuiteStmt>(comment, n);
|
||||
} else {
|
||||
// Generate import identifier
|
||||
std::string importVar = import->second.importVar =
|
||||
ctx->cache->getTemporaryVar(format("import_{}", file.module));
|
||||
std::string importDoneVar;
|
||||
|
||||
// `import_[I]_done = False` (set to True upon successful import)
|
||||
preamble->push_back(N<AssignStmt>(N<IdExpr>(importDoneVar = importVar + "_done"),
|
||||
N<BoolExpr>(false)));
|
||||
ctx->cache->addGlobal(importDoneVar);
|
||||
|
||||
// Wrap all imported top-level statements into a function.
|
||||
// Make sure to register the global variables and set their assignments as updates.
|
||||
// Note: signatures/classes/functions are not wrapped
|
||||
// Make sure to register the global variables and set their assignments as
|
||||
// updates. Note: signatures/classes/functions are not wrapped
|
||||
std::vector<StmtPtr> stmts;
|
||||
stmts.push_back(
|
||||
N<IfStmt>(N<DotExpr>(N<IdExpr>(importVar), "loaded"), N<ReturnStmt>()));
|
||||
stmts.push_back(N<ExprStmt>(
|
||||
N<CallExpr>(N<IdExpr>("Import._set_loaded"),
|
||||
N<CallExpr>(N<IdExpr>("__ptr__"), N<IdExpr>(importVar)))));
|
||||
auto processToplevelStmt = [&](const StmtPtr &s) {
|
||||
// Process toplevel statement
|
||||
if (auto a = s->getAssign()) {
|
||||
|
|
|
@ -373,7 +373,7 @@ types::TypePtr TypecheckVisitor::realizeFunc(types::FuncType *type, bool force)
|
|||
// Lambda typecheck failures are "ignored" as they are treated as statements,
|
||||
// not functions.
|
||||
// TODO: generalize this further.
|
||||
// LOG("{}", ast->suite->toString(2));
|
||||
LOG_REALIZE("[error] {}", ast->suite->toString(2));
|
||||
error("cannot typecheck the program");
|
||||
}
|
||||
return nullptr; // inference must be delayed
|
||||
|
|
|
@ -26,6 +26,7 @@ StmtPtr TypecheckVisitor::apply(Cache *cache, const StmtPtr &stmts) {
|
|||
auto so = clone(stmts);
|
||||
auto s = v.inferTypes(so, true);
|
||||
if (!s) {
|
||||
LOG_REALIZE("[error] {}", so->toString(2));
|
||||
v.error("cannot typecheck the program");
|
||||
}
|
||||
if (s->getSuite())
|
||||
|
|
|
@ -41,4 +41,6 @@ if [ ! -f "${INSTALLDIR}/bin/llvm-config" ]; then
|
|||
fi
|
||||
|
||||
"${INSTALLDIR}/bin/llvm-config" --cmakedir
|
||||
cd ${INSTALLDIR}
|
||||
rm -rf ${SRCDIR}
|
||||
fi
|
||||
|
|
|
@ -274,3 +274,21 @@ def statictuple(*args):
|
|||
|
||||
def __has_rtti__(T: type):
|
||||
pass
|
||||
|
||||
@dataclass(init=False)
|
||||
@tuple
|
||||
class Import:
|
||||
loaded: bool
|
||||
name: Static[str]
|
||||
file: Static[str]
|
||||
|
||||
def __new__(name: Static[str],
|
||||
file: Static[str],
|
||||
loaded: bool) -> Import[name, file]:
|
||||
return (loaded,)
|
||||
|
||||
def _set_loaded(i: Ptr[Import]):
|
||||
Ptr[bool](i.as_byte())[0] = True
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<module '{self.name}' from '{self.file}'>"
|
||||
|
|
|
@ -693,15 +693,6 @@ class __magic__:
|
|||
def str(slf) -> str:
|
||||
return slf.__repr__()
|
||||
|
||||
@dataclass(init=True)
|
||||
@tuple
|
||||
class Import:
|
||||
name: str
|
||||
file: str
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<module '{self.name}' from '{self.file}'>"
|
||||
|
||||
@extend
|
||||
class Function:
|
||||
@pure
|
||||
|
|
Loading…
Reference in New Issue