diff --git a/codon/cir/module.cpp b/codon/cir/module.cpp index 2287edcc..af160a4c 100644 --- a/codon/cir/module.cpp +++ b/codon/cir/module.cpp @@ -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__"; diff --git a/codon/cir/module.h b/codon/cir/module.h index 647c8670..3fdd6d60 100644 --- a/codon/cir/module.h +++ b/codon/cir/module.h @@ -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; diff --git a/codon/cir/types/types.cpp b/codon/cir/types/types.cpp index b2f4f6d0..445b7a84 100644 --- a/codon/cir/types/types.cpp +++ b/codon/cir/types/types.cpp @@ -39,9 +39,17 @@ std::vector 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()); + } } } diff --git a/codon/parser/cache.h b/codon/parser/cache.h index f6f47e59..2f75744e 100644 --- a/codon/parser/cache.h +++ b/codon/parser/cache.h @@ -80,6 +80,8 @@ struct Cache : public std::enable_shared_from_this { std::vector 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). diff --git a/codon/parser/visitors/simplify/import.cpp b/codon/parser/visitors/simplify/import.cpp index 0c2cedd9..a0736403 100644 --- a/codon/parser/visitors/simplify/import.cpp +++ b/codon/parser/visitors/simplify/import.cpp @@ -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(N(importDoneVar), N(true)); - u->setUpdate(); - resultStmt = - N(N(N(importDoneVar, "__invert__")), - N(N(N(N(importVar))), u)); + if (!handled) { + resultStmt = N(N(N(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( - resultStmt, transform(N(N(var), - N(N("Import"), - N(file->module), - N(file->path)), - N("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(N("__name__"), N(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(N("__name__"), N(ictx->moduleName.module)); + preamble->push_back(N( + N(importVar), + N(N("Import.__new__"), N(file.module), + N(file.path), N(false)), + N("Import"))); + auto var = ctx->addAlwaysVisible( + std::make_shared(SimplifyItem::Var, ctx->getBaseName(), importVar, + ctx->getModule(), std::vector{0})); + ctx->cache->addGlobal(importVar); } n = N(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(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(N(importDoneVar = importVar + "_done"), - N(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 stmts; + stmts.push_back( + N(N(N(importVar), "loaded"), N())); + stmts.push_back(N( + N(N("Import._set_loaded"), + N(N("__ptr__"), N(importVar))))); auto processToplevelStmt = [&](const StmtPtr &s) { // Process toplevel statement if (auto a = s->getAssign()) { diff --git a/codon/parser/visitors/typecheck/infer.cpp b/codon/parser/visitors/typecheck/infer.cpp index 6410f0e0..bd54dd5a 100644 --- a/codon/parser/visitors/typecheck/infer.cpp +++ b/codon/parser/visitors/typecheck/infer.cpp @@ -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 diff --git a/codon/parser/visitors/typecheck/typecheck.cpp b/codon/parser/visitors/typecheck/typecheck.cpp index 637f3b76..953ba748 100644 --- a/codon/parser/visitors/typecheck/typecheck.cpp +++ b/codon/parser/visitors/typecheck/typecheck.cpp @@ -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()) diff --git a/scripts/deps.sh b/scripts/deps.sh index 25c212b3..b6c4ab56 100755 --- a/scripts/deps.sh +++ b/scripts/deps.sh @@ -41,4 +41,6 @@ if [ ! -f "${INSTALLDIR}/bin/llvm-config" ]; then fi "${INSTALLDIR}/bin/llvm-config" --cmakedir + cd ${INSTALLDIR} + rm -rf ${SRCDIR} fi diff --git a/stdlib/internal/core.codon b/stdlib/internal/core.codon index 71c6b0d0..ff1a8ebb 100644 --- a/stdlib/internal/core.codon +++ b/stdlib/internal/core.codon @@ -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"" diff --git a/stdlib/internal/internal.codon b/stdlib/internal/internal.codon index 1a9f7573..eb054524 100644 --- a/stdlib/internal/internal.codon +++ b/stdlib/internal/internal.codon @@ -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"" - @extend class Function: @pure