Update import handling (#580)

pull/581/head
A. R. Shajii 2024-08-23 10:18:13 -04:00 committed by GitHub
parent 3c4272d92a
commit c214e2c65d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 76 additions and 46 deletions

View File

@ -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__";

View File

@ -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;

View File

@ -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());
}
}
}

View File

@ -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).

View File

@ -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()) {

View File

@ -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

View File

@ -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())

View File

@ -41,4 +41,6 @@ if [ ! -f "${INSTALLDIR}/bin/llvm-config" ]; then
fi
"${INSTALLDIR}/bin/llvm-config" --cmakedir
cd ${INSTALLDIR}
rm -rf ${SRCDIR}
fi

View File

@ -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}'>"

View 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