From 92f9a274e7b2f4c7bef2630d9dbe15b71eba904a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ibrahim=20Numanagic=CC=81?= Date: Fri, 10 Feb 2023 18:21:48 -0800 Subject: [PATCH] Add support for @pycapture --- codon/parser/visitors/simplify/access.cpp | 21 +++++++++++++++++---- codon/parser/visitors/simplify/ctx.cpp | 2 +- codon/parser/visitors/simplify/ctx.h | 4 ++++ codon/parser/visitors/simplify/function.cpp | 3 +++ codon/parser/visitors/typecheck/access.cpp | 1 - stdlib/internal/attributes.codon | 4 ++++ stdlib/internal/python.codon | 4 ++++ 7 files changed, 33 insertions(+), 6 deletions(-) diff --git a/codon/parser/visitors/simplify/access.cpp b/codon/parser/visitors/simplify/access.cpp index 5013c4a8..0bd93884 100644 --- a/codon/parser/visitors/simplify/access.cpp +++ b/codon/parser/visitors/simplify/access.cpp @@ -19,8 +19,14 @@ void SimplifyVisitor::visit(IdExpr *expr) { return; } auto val = ctx->findDominatingBinding(expr->value); - if (!val) + + if (!val && ctx->getBase()->pyCaptures) { + ctx->getBase()->pyCaptures->insert(expr->value); + resultExpr = N(N("__pyenv__"), N(expr->value)); + return; + } else if (!val) { E(Error::ID_NOT_FOUND, expr, expr->value); + } // If we are accessing an outside variable, capture it or raise an error auto captured = checkCapture(val); @@ -107,7 +113,11 @@ void SimplifyVisitor::visit(DotExpr *expr) { std::reverse(chain.begin(), chain.end()); auto p = getImport(chain); - if (p.second->getModule() == "std.python") { + if (!p.second) { + seqassert(ctx->getBase()->pyCaptures, "unexpected py capture"); + ctx->getBase()->pyCaptures->insert(chain[0]); + resultExpr = N(N("__pyenv__"), N(chain[0])); + } else if (p.second->getModule() == "std.python") { resultExpr = transform(N( N(N(N("internal"), "python"), "_get_identifier"), N(chain[p.first++]))); @@ -238,7 +248,7 @@ SimplifyVisitor::getImport(const std::vector &chain) { for (auto i = chain.size(); i-- > importEnd;) { if (fctx->getModule() == "std.python" && importEnd < chain.size()) { // Special case: importing from Python. - // Fake SimplifyItem that inidcates std.python access + // Fake SimplifyItem that indicates std.python access val = std::make_shared(SimplifyItem::Var, "", "", fctx->getModule(), std::vector{}); return {importEnd, val}; @@ -250,8 +260,11 @@ SimplifyVisitor::getImport(const std::vector &chain) { } } } - if (itemName.empty() && importName.empty()) + if (itemName.empty() && importName.empty()) { + if (ctx->getBase()->pyCaptures) + return {1, nullptr}; E(Error::IMPORT_NO_MODULE, getSrcInfo(), chain[importEnd]); + } if (itemName.empty()) E(Error::IMPORT_NO_NAME, getSrcInfo(), chain[importEnd], ctx->cache->imports[importName].moduleName); diff --git a/codon/parser/visitors/simplify/ctx.cpp b/codon/parser/visitors/simplify/ctx.cpp index c5a95493..e77c9407 100644 --- a/codon/parser/visitors/simplify/ctx.cpp +++ b/codon/parser/visitors/simplify/ctx.cpp @@ -25,7 +25,7 @@ SimplifyContext::SimplifyContext(std::string filename, Cache *cache) SimplifyContext::Base::Base(std::string name, Attr *attributes) : name(move(name)), attributes(attributes), deducedMembers(nullptr), selfName(), - captures(nullptr) {} + captures(nullptr), pyCaptures(nullptr) {} void SimplifyContext::add(const std::string &name, const SimplifyContext::Item &var) { auto v = find(name); diff --git a/codon/parser/visitors/simplify/ctx.h b/codon/parser/visitors/simplify/ctx.h index 1f959170..31c11bf7 100644 --- a/codon/parser/visitors/simplify/ctx.h +++ b/codon/parser/visitors/simplify/ctx.h @@ -112,6 +112,10 @@ struct SimplifyContext : public Context { /// function after processing) and their types (indicating if they are a type, a /// static or a variable). std::unordered_map> *captures; + + /// Map of identifiers that are to be fetched from Python. + std::unordered_set *pyCaptures; + /// Scope that defines the base. std::vector scope; diff --git a/codon/parser/visitors/simplify/function.cpp b/codon/parser/visitors/simplify/function.cpp index 92e1fc5c..d33e5a8e 100644 --- a/codon/parser/visitors/simplify/function.cpp +++ b/codon/parser/visitors/simplify/function.cpp @@ -161,6 +161,7 @@ void SimplifyVisitor::visit(FunctionStmt *stmt) { StmtPtr suite = nullptr; ExprPtr ret = nullptr; std::unordered_map> captures; + std::unordered_set pyCaptures; { // Set up the base SimplifyContext::BaseGuard br(ctx.get(), canonicalName); @@ -239,6 +240,8 @@ void SimplifyVisitor::visit(FunctionStmt *stmt) { } else { if ((isEnclosedFunc || stmt->attributes.has(Attr::Capture)) && !isClassMember) ctx->getBase()->captures = &captures; + if (stmt->attributes.has("std.internal.attributes.pycapture")) + ctx->getBase()->pyCaptures = &pyCaptures; suite = SimplifyVisitor(ctx, preamble).transformConditionalScope(stmt->suite); } } diff --git a/codon/parser/visitors/typecheck/access.cpp b/codon/parser/visitors/typecheck/access.cpp index ce91cd24..9caa87d0 100644 --- a/codon/parser/visitors/typecheck/access.cpp +++ b/codon/parser/visitors/typecheck/access.cpp @@ -318,7 +318,6 @@ ExprPtr TypecheckVisitor::getClassMember(DotExpr *expr, // Case: transform `pyobj.member` to `pyobj._getattr("member")` if (typ->is("pyobj")) { - LOG("-> /p {}", expr->toString()); return transform( N(N(expr->expr, "_getattr"), N(expr->member))); } diff --git a/stdlib/internal/attributes.codon b/stdlib/internal/attributes.codon index cdc50612..54578033 100644 --- a/stdlib/internal/attributes.codon +++ b/stdlib/internal/attributes.codon @@ -32,6 +32,10 @@ def no_side_effect(): def nocapture(): pass +@__attribute__ +def pycapture(): + pass + @__attribute__ def derives(): pass diff --git a/stdlib/internal/python.codon b/stdlib/internal/python.codon index f2b72aec..8f9dd6d6 100644 --- a/stdlib/internal/python.codon +++ b/stdlib/internal/python.codon @@ -978,3 +978,7 @@ class Optional: return Optional[T]() else: return Optional[T](T.__from_py__(o)) + + +__pyenv__: Optional[pyobj] = None +def _____(): __pyenv__ # make it global!