mirror of
https://github.com/exaloop/codon.git
synced 2025-06-03 15:03:52 +08:00
Support for overloaded functions [wip; base logic done]
This commit is contained in:
parent
58664374c7
commit
fa7278e616
@ -50,6 +50,9 @@ types::ClassTypePtr Cache::findClass(const std::string &name) const {
|
|||||||
|
|
||||||
types::FuncTypePtr Cache::findFunction(const std::string &name) const {
|
types::FuncTypePtr Cache::findFunction(const std::string &name) const {
|
||||||
auto f = typeCtx->find(name);
|
auto f = typeCtx->find(name);
|
||||||
|
if (f && f->type && f->kind == TypecheckItem::Func)
|
||||||
|
return f->type->getFunc();
|
||||||
|
f = typeCtx->find(name + ":0");
|
||||||
if (f && f->type && f->kind == TypecheckItem::Func)
|
if (f && f->type && f->kind == TypecheckItem::Func)
|
||||||
return f->type->getFunc();
|
return f->type->getFunc();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -106,19 +106,9 @@ struct Cache : public std::enable_shared_from_this<Cache> {
|
|||||||
/// Non-simplified AST. Used for base class instantiation.
|
/// Non-simplified AST. Used for base class instantiation.
|
||||||
std::shared_ptr<ClassStmt> originalAst;
|
std::shared_ptr<ClassStmt> originalAst;
|
||||||
|
|
||||||
/// A class function method.
|
/// Class method lookup table. Each non-canonical name points
|
||||||
struct ClassMethod {
|
/// to a root function name of a corresponding method.
|
||||||
/// Canonical name of a method (e.g. __init__.1).
|
std::unordered_map<std::string, std::string> methods;
|
||||||
std::string name;
|
|
||||||
/// A corresponding generic function type.
|
|
||||||
types::FuncTypePtr type;
|
|
||||||
/// Method age (how many class extension were seen before a method definition).
|
|
||||||
/// Used to prevent the usage of a method before it was defined in the code.
|
|
||||||
int age;
|
|
||||||
};
|
|
||||||
/// Class method lookup table. Each name points to a list of ClassMethod instances
|
|
||||||
/// that share the same method name (a list because methods can be overloaded).
|
|
||||||
std::unordered_map<std::string, std::vector<ClassMethod>> methods;
|
|
||||||
|
|
||||||
/// A class field (member).
|
/// A class field (member).
|
||||||
struct ClassField {
|
struct ClassField {
|
||||||
@ -177,6 +167,20 @@ struct Cache : public std::enable_shared_from_this<Cache> {
|
|||||||
/// corresponding Function instance.
|
/// corresponding Function instance.
|
||||||
std::unordered_map<std::string, Function> functions;
|
std::unordered_map<std::string, Function> functions;
|
||||||
|
|
||||||
|
|
||||||
|
struct Overload {
|
||||||
|
/// Canonical name of an overload (e.g. Foo.__init__.1).
|
||||||
|
std::string name;
|
||||||
|
/// Overload age (how many class extension were seen before a method definition).
|
||||||
|
/// Used to prevent the usage of an overload before it was defined in the code.
|
||||||
|
/// TODO: I have no recollection of how this was supposed to work. Most likely
|
||||||
|
/// it does not work at all...
|
||||||
|
int age;
|
||||||
|
};
|
||||||
|
/// Maps a "root" name of each function to the list of names of the function
|
||||||
|
/// overloads.
|
||||||
|
std::unordered_map<std::string, std::vector<Overload>> overloads;
|
||||||
|
|
||||||
/// Pointer to the later contexts needed for IR API access.
|
/// Pointer to the later contexts needed for IR API access.
|
||||||
std::shared_ptr<TypeContext> typeCtx;
|
std::shared_ptr<TypeContext> typeCtx;
|
||||||
std::shared_ptr<TranslateContext> codegenCtx;
|
std::shared_ptr<TranslateContext> codegenCtx;
|
||||||
|
@ -52,8 +52,6 @@ std::shared_ptr<peg::Grammar> initParser() {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
T parseCode(Cache *cache, const std::string &file, std::string code, int line_offset,
|
T parseCode(Cache *cache, const std::string &file, std::string code, int line_offset,
|
||||||
int col_offset, const std::string &rule) {
|
int col_offset, const std::string &rule) {
|
||||||
TIME("peg");
|
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
if (!grammar)
|
if (!grammar)
|
||||||
grammar = initParser();
|
grammar = initParser();
|
||||||
|
@ -14,8 +14,9 @@ namespace codon {
|
|||||||
namespace ast {
|
namespace ast {
|
||||||
|
|
||||||
SimplifyItem::SimplifyItem(Kind k, std::string base, std::string canonicalName,
|
SimplifyItem::SimplifyItem(Kind k, std::string base, std::string canonicalName,
|
||||||
bool global)
|
bool global, std::string moduleName)
|
||||||
: kind(k), base(move(base)), canonicalName(move(canonicalName)), global(global) {}
|
: kind(k), base(move(base)), canonicalName(move(canonicalName)), global(global),
|
||||||
|
moduleName(move(moduleName)) {}
|
||||||
|
|
||||||
SimplifyContext::SimplifyContext(std::string filename, Cache *cache)
|
SimplifyContext::SimplifyContext(std::string filename, Cache *cache)
|
||||||
: Context<SimplifyItem>(move(filename)), cache(move(cache)),
|
: Context<SimplifyItem>(move(filename)), cache(move(cache)),
|
||||||
@ -31,6 +32,7 @@ std::shared_ptr<SimplifyItem> SimplifyContext::add(SimplifyItem::Kind kind,
|
|||||||
bool global) {
|
bool global) {
|
||||||
seqassert(!canonicalName.empty(), "empty canonical name for '{}'", name);
|
seqassert(!canonicalName.empty(), "empty canonical name for '{}'", name);
|
||||||
auto t = std::make_shared<SimplifyItem>(kind, getBase(), canonicalName, global);
|
auto t = std::make_shared<SimplifyItem>(kind, getBase(), canonicalName, global);
|
||||||
|
t->moduleName = getModule();
|
||||||
Context<SimplifyItem>::add(name, t);
|
Context<SimplifyItem>::add(name, t);
|
||||||
Context<SimplifyItem>::add(canonicalName, t);
|
Context<SimplifyItem>::add(canonicalName, t);
|
||||||
return t;
|
return t;
|
||||||
@ -60,6 +62,14 @@ std::string SimplifyContext::getBase() const {
|
|||||||
return bases.back().name;
|
return bases.back().name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string SimplifyContext::getModule() const {
|
||||||
|
std::string base = moduleName.status == ImportFile::STDLIB ? "std." : "";
|
||||||
|
base += moduleName.module;
|
||||||
|
if (startswith(base, "__main__"))
|
||||||
|
base = base.substr(8);
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
std::string SimplifyContext::generateCanonicalName(const std::string &name,
|
std::string SimplifyContext::generateCanonicalName(const std::string &name,
|
||||||
bool includeBase,
|
bool includeBase,
|
||||||
bool zeroId) const {
|
bool zeroId) const {
|
||||||
@ -67,12 +77,8 @@ std::string SimplifyContext::generateCanonicalName(const std::string &name,
|
|||||||
bool alreadyGenerated = name.find('.') != std::string::npos;
|
bool alreadyGenerated = name.find('.') != std::string::npos;
|
||||||
if (includeBase && !alreadyGenerated) {
|
if (includeBase && !alreadyGenerated) {
|
||||||
std::string base = getBase();
|
std::string base = getBase();
|
||||||
if (base.empty()) {
|
if (base.empty())
|
||||||
base = moduleName.status == ImportFile::STDLIB ? "std." : "";
|
base = getModule();
|
||||||
base += moduleName.module;
|
|
||||||
if (startswith(base, "__main__"))
|
|
||||||
base = base.substr(8);
|
|
||||||
}
|
|
||||||
newName = (base.empty() ? "" : (base + ".")) + newName;
|
newName = (base.empty() ? "" : (base + ".")) + newName;
|
||||||
}
|
}
|
||||||
auto num = cache->identifierCount[newName]++;
|
auto num = cache->identifierCount[newName]++;
|
||||||
|
@ -32,13 +32,16 @@ struct SimplifyItem {
|
|||||||
bool global;
|
bool global;
|
||||||
/// Non-empty string if a variable is import variable
|
/// Non-empty string if a variable is import variable
|
||||||
std::string importPath;
|
std::string importPath;
|
||||||
|
/// Full module name
|
||||||
|
std::string moduleName;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SimplifyItem(Kind k, std::string base, std::string canonicalName,
|
SimplifyItem(Kind k, std::string base, std::string canonicalName, bool global = false,
|
||||||
bool global = false);
|
std::string moduleName = "");
|
||||||
|
|
||||||
/// Convenience getters.
|
/// Convenience getters.
|
||||||
std::string getBase() const { return base; }
|
std::string getBase() const { return base; }
|
||||||
|
std::string getModule() const { return moduleName; }
|
||||||
bool isGlobal() const { return global; }
|
bool isGlobal() const { return global; }
|
||||||
bool isVar() const { return kind == Var; }
|
bool isVar() const { return kind == Var; }
|
||||||
bool isFunc() const { return kind == Func; }
|
bool isFunc() const { return kind == Func; }
|
||||||
@ -107,6 +110,8 @@ public:
|
|||||||
/// Return a canonical name of the top-most base, or an empty string if this is a
|
/// Return a canonical name of the top-most base, or an empty string if this is a
|
||||||
/// top-level base.
|
/// top-level base.
|
||||||
std::string getBase() const;
|
std::string getBase() const;
|
||||||
|
/// Return the current module.
|
||||||
|
std::string getModule() const;
|
||||||
/// Return the current base nesting level (note: bases, not blocks).
|
/// Return the current base nesting level (note: bases, not blocks).
|
||||||
int getLevel() const { return bases.size(); }
|
int getLevel() const { return bases.size(); }
|
||||||
/// Pretty-print the current context state.
|
/// Pretty-print the current context state.
|
||||||
|
@ -437,25 +437,27 @@ void SimplifyVisitor::visit(FunctionStmt *stmt) {
|
|||||||
if (stmt->decorators.size() != 1)
|
if (stmt->decorators.size() != 1)
|
||||||
error("__attribute__ cannot be mixed with other decorators");
|
error("__attribute__ cannot be mixed with other decorators");
|
||||||
attr.isAttribute = true;
|
attr.isAttribute = true;
|
||||||
} else if (d->isId(Attr::LLVM))
|
} else if (d->isId(Attr::LLVM)) {
|
||||||
attr.set(Attr::LLVM);
|
attr.set(Attr::LLVM);
|
||||||
else if (d->isId(Attr::Python))
|
} else if (d->isId(Attr::Python)) {
|
||||||
attr.set(Attr::Python);
|
attr.set(Attr::Python);
|
||||||
else if (d->isId(Attr::Internal))
|
} else if (d->isId(Attr::Internal)) {
|
||||||
attr.set(Attr::Internal);
|
attr.set(Attr::Internal);
|
||||||
else if (d->isId(Attr::Atomic))
|
} else if (d->isId(Attr::Atomic)) {
|
||||||
attr.set(Attr::Atomic);
|
attr.set(Attr::Atomic);
|
||||||
else if (d->isId(Attr::Property))
|
} else if (d->isId(Attr::Property)) {
|
||||||
attr.set(Attr::Property);
|
attr.set(Attr::Property);
|
||||||
else if (d->isId(Attr::ForceRealize))
|
} else if (d->isId(Attr::ForceRealize)) {
|
||||||
attr.set(Attr::ForceRealize);
|
attr.set(Attr::ForceRealize);
|
||||||
else {
|
} else {
|
||||||
// Let's check if this is a attribute
|
// Let's check if this is a attribute
|
||||||
auto dt = transform(clone(d));
|
auto dt = transform(clone(d));
|
||||||
if (dt && dt->getId()) {
|
if (dt && dt->getId()) {
|
||||||
auto ci = ctx->find(dt->getId()->value);
|
auto ci = ctx->find(dt->getId()->value);
|
||||||
if (ci && ci->kind == SimplifyItem::Func) {
|
if (ci && ci->kind == SimplifyItem::Func) {
|
||||||
if (ctx->cache->functions[ci->canonicalName].ast->attributes.isAttribute) {
|
if (ctx->cache->overloads[ci->canonicalName].size() == 1)
|
||||||
|
if (ctx->cache->functions[ctx->cache->overloads[ci->canonicalName][0].name]
|
||||||
|
.ast->attributes.isAttribute) {
|
||||||
attr.set(ci->canonicalName);
|
attr.set(ci->canonicalName);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -473,19 +475,22 @@ void SimplifyVisitor::visit(FunctionStmt *stmt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isClassMember = ctx->inClass();
|
bool isClassMember = ctx->inClass();
|
||||||
if (isClassMember && !endswith(stmt->name, ".dispatch") &&
|
std::string rootName;
|
||||||
ctx->cache->classes[ctx->bases.back().name].methods[stmt->name].empty()) {
|
if (isClassMember) {
|
||||||
generateDispatch(stmt->name);
|
auto &m = ctx->cache->classes[ctx->bases.back().name].methods;
|
||||||
}
|
auto i = m.find(stmt->name);
|
||||||
auto func_name = stmt->name;
|
if (i != m.end())
|
||||||
if (endswith(stmt->name, ".dispatch"))
|
rootName = i->second;
|
||||||
func_name = func_name.substr(0, func_name.size() - 9);
|
} else if (auto c = ctx->find(stmt->name)) {
|
||||||
auto canonicalName = ctx->generateCanonicalName(
|
if (c->isFunc() && c->getModule() == ctx->getModule() &&
|
||||||
func_name, true, isClassMember && !endswith(stmt->name, ".dispatch"));
|
c->getBase() == ctx->getBase())
|
||||||
if (endswith(stmt->name, ".dispatch")) {
|
rootName = c->canonicalName;
|
||||||
canonicalName += ".dispatch";
|
|
||||||
ctx->cache->reverseIdentifierLookup[canonicalName] = func_name;
|
|
||||||
}
|
}
|
||||||
|
if (rootName.empty())
|
||||||
|
rootName = ctx->generateCanonicalName(stmt->name, true);
|
||||||
|
auto canonicalName =
|
||||||
|
format("{}:{}", rootName, ctx->cache->overloads[rootName].size());
|
||||||
|
ctx->cache->reverseIdentifierLookup[canonicalName] = stmt->name;
|
||||||
bool isEnclosedFunc = ctx->inFunction();
|
bool isEnclosedFunc = ctx->inFunction();
|
||||||
|
|
||||||
if (attr.has(Attr::ForceRealize) && (ctx->getLevel() || isClassMember))
|
if (attr.has(Attr::ForceRealize) && (ctx->getLevel() || isClassMember))
|
||||||
@ -495,7 +500,7 @@ void SimplifyVisitor::visit(FunctionStmt *stmt) {
|
|||||||
ctx->bases = std::vector<SimplifyContext::Base>();
|
ctx->bases = std::vector<SimplifyContext::Base>();
|
||||||
if (!isClassMember)
|
if (!isClassMember)
|
||||||
// Class members are added to class' method table
|
// Class members are added to class' method table
|
||||||
ctx->add(SimplifyItem::Func, func_name, canonicalName, ctx->isToplevel());
|
ctx->add(SimplifyItem::Func, stmt->name, rootName, ctx->isToplevel());
|
||||||
if (isClassMember)
|
if (isClassMember)
|
||||||
ctx->bases.push_back(oldBases[0]);
|
ctx->bases.push_back(oldBases[0]);
|
||||||
ctx->bases.emplace_back(SimplifyContext::Base{canonicalName}); // Add new base...
|
ctx->bases.emplace_back(SimplifyContext::Base{canonicalName}); // Add new base...
|
||||||
@ -614,8 +619,7 @@ void SimplifyVisitor::visit(FunctionStmt *stmt) {
|
|||||||
// ... set the enclosing class name...
|
// ... set the enclosing class name...
|
||||||
attr.parentClass = ctx->bases.back().name;
|
attr.parentClass = ctx->bases.back().name;
|
||||||
// ... add the method to class' method list ...
|
// ... add the method to class' method list ...
|
||||||
ctx->cache->classes[ctx->bases.back().name].methods[func_name].push_back(
|
ctx->cache->classes[ctx->bases.back().name].methods[stmt->name] = rootName;
|
||||||
{canonicalName, nullptr, ctx->cache->age});
|
|
||||||
// ... and if the function references outer class variable (by definition a
|
// ... and if the function references outer class variable (by definition a
|
||||||
// generic), mark it as not static as it needs fully instantiated class to be
|
// generic), mark it as not static as it needs fully instantiated class to be
|
||||||
// realized. For example, in class A[T]: def foo(): pass, A.foo() can be realized
|
// realized. For example, in class A[T]: def foo(): pass, A.foo() can be realized
|
||||||
@ -624,6 +628,7 @@ void SimplifyVisitor::visit(FunctionStmt *stmt) {
|
|||||||
if (isMethod)
|
if (isMethod)
|
||||||
attr.set(Attr::Method);
|
attr.set(Attr::Method);
|
||||||
}
|
}
|
||||||
|
ctx->cache->overloads[rootName].push_back({canonicalName, ctx->cache->age});
|
||||||
|
|
||||||
std::vector<CallExpr::Arg> partialArgs;
|
std::vector<CallExpr::Arg> partialArgs;
|
||||||
if (!captures.empty()) {
|
if (!captures.empty()) {
|
||||||
@ -649,21 +654,21 @@ void SimplifyVisitor::visit(FunctionStmt *stmt) {
|
|||||||
|
|
||||||
ExprPtr finalExpr;
|
ExprPtr finalExpr;
|
||||||
if (!captures.empty())
|
if (!captures.empty())
|
||||||
finalExpr = N<CallExpr>(N<IdExpr>(func_name), partialArgs);
|
finalExpr = N<CallExpr>(N<IdExpr>(stmt->name), partialArgs);
|
||||||
if (isClassMember && decorators.size())
|
if (isClassMember && decorators.size())
|
||||||
error("decorators cannot be applied to class methods");
|
error("decorators cannot be applied to class methods");
|
||||||
for (int j = int(decorators.size()) - 1; j >= 0; j--) {
|
for (int j = int(decorators.size()) - 1; j >= 0; j--) {
|
||||||
if (auto c = const_cast<CallExpr *>(decorators[j]->getCall())) {
|
if (auto c = const_cast<CallExpr *>(decorators[j]->getCall())) {
|
||||||
c->args.emplace(c->args.begin(),
|
c->args.emplace(c->args.begin(),
|
||||||
CallExpr::Arg{"", finalExpr ? finalExpr : N<IdExpr>(func_name)});
|
CallExpr::Arg{"", finalExpr ? finalExpr : N<IdExpr>(stmt->name)});
|
||||||
finalExpr = N<CallExpr>(c->expr, c->args);
|
finalExpr = N<CallExpr>(c->expr, c->args);
|
||||||
} else {
|
} else {
|
||||||
finalExpr =
|
finalExpr =
|
||||||
N<CallExpr>(decorators[j], finalExpr ? finalExpr : N<IdExpr>(func_name));
|
N<CallExpr>(decorators[j], finalExpr ? finalExpr : N<IdExpr>(stmt->name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (finalExpr)
|
if (finalExpr)
|
||||||
resultStmt = transform(N<AssignStmt>(N<IdExpr>(func_name), finalExpr));
|
resultStmt = transform(N<AssignStmt>(N<IdExpr>(stmt->name), finalExpr));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimplifyVisitor::visit(ClassStmt *stmt) {
|
void SimplifyVisitor::visit(ClassStmt *stmt) {
|
||||||
@ -744,6 +749,7 @@ void SimplifyVisitor::visit(ClassStmt *stmt) {
|
|||||||
ClassStmt *originalAST = nullptr;
|
ClassStmt *originalAST = nullptr;
|
||||||
auto classItem =
|
auto classItem =
|
||||||
std::make_shared<SimplifyItem>(SimplifyItem::Type, "", "", ctx->isToplevel());
|
std::make_shared<SimplifyItem>(SimplifyItem::Type, "", "", ctx->isToplevel());
|
||||||
|
classItem->moduleName = ctx->getModule();
|
||||||
if (!extension) {
|
if (!extension) {
|
||||||
classItem->canonicalName = canonicalName =
|
classItem->canonicalName = canonicalName =
|
||||||
ctx->generateCanonicalName(name, !attr.has(Attr::Internal));
|
ctx->generateCanonicalName(name, !attr.has(Attr::Internal));
|
||||||
@ -949,22 +955,29 @@ void SimplifyVisitor::visit(ClassStmt *stmt) {
|
|||||||
for (int ai = 0; ai < baseASTs.size(); ai++) {
|
for (int ai = 0; ai < baseASTs.size(); ai++) {
|
||||||
// FUNCS
|
// FUNCS
|
||||||
for (auto &mm : ctx->cache->classes[baseASTs[ai]->name].methods)
|
for (auto &mm : ctx->cache->classes[baseASTs[ai]->name].methods)
|
||||||
for (auto &mf : mm.second) {
|
for (auto &mf : ctx->cache->overloads[mm.second]) {
|
||||||
auto f = ctx->cache->functions[mf.name].ast;
|
auto f = ctx->cache->functions[mf.name].ast;
|
||||||
if (f->attributes.has("autogenerated"))
|
if (f->attributes.has("autogenerated"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto subs = substitutions[ai];
|
auto subs = substitutions[ai];
|
||||||
if (ctx->cache->classes[ctx->bases.back().name]
|
|
||||||
.methods[ctx->cache->reverseIdentifierLookup[f->name]]
|
std::string rootName;
|
||||||
.empty())
|
auto &mts = ctx->cache->classes[ctx->bases.back().name].methods;
|
||||||
generateDispatch(ctx->cache->reverseIdentifierLookup[f->name]);
|
auto it = mts.find(ctx->cache->reverseIdentifierLookup[f->name]);
|
||||||
auto newName = ctx->generateCanonicalName(
|
if (it != mts.end())
|
||||||
|
rootName = it->second;
|
||||||
|
else
|
||||||
|
rootName = ctx->generateCanonicalName(
|
||||||
ctx->cache->reverseIdentifierLookup[f->name], true);
|
ctx->cache->reverseIdentifierLookup[f->name], true);
|
||||||
|
auto newCanonicalName =
|
||||||
|
format("{}:{}", rootName, ctx->cache->overloads[rootName].size());
|
||||||
|
ctx->cache->reverseIdentifierLookup[newCanonicalName] =
|
||||||
|
ctx->cache->reverseIdentifierLookup[f->name];
|
||||||
auto nf = std::dynamic_pointer_cast<FunctionStmt>(
|
auto nf = std::dynamic_pointer_cast<FunctionStmt>(
|
||||||
replace(std::static_pointer_cast<Stmt>(f), subs));
|
replace(std::static_pointer_cast<Stmt>(f), subs));
|
||||||
subs[nf->name] = N<IdExpr>(newName);
|
subs[nf->name] = N<IdExpr>(newCanonicalName);
|
||||||
nf->name = newName;
|
nf->name = newCanonicalName;
|
||||||
suite->stmts.push_back(nf);
|
suite->stmts.push_back(nf);
|
||||||
nf->attributes.parentClass = ctx->bases.back().name;
|
nf->attributes.parentClass = ctx->bases.back().name;
|
||||||
|
|
||||||
@ -972,10 +985,10 @@ void SimplifyVisitor::visit(ClassStmt *stmt) {
|
|||||||
if (nf->attributes.has(".changedSelf")) // replace self type with new class
|
if (nf->attributes.has(".changedSelf")) // replace self type with new class
|
||||||
nf->args[0].type = transformType(ctx->bases.back().ast);
|
nf->args[0].type = transformType(ctx->bases.back().ast);
|
||||||
preamble->functions.push_back(clone(nf));
|
preamble->functions.push_back(clone(nf));
|
||||||
ctx->cache->functions[newName].ast = nf;
|
ctx->cache->overloads[rootName].push_back({newCanonicalName, ctx->cache->age});
|
||||||
|
ctx->cache->functions[newCanonicalName].ast = nf;
|
||||||
ctx->cache->classes[ctx->bases.back().name]
|
ctx->cache->classes[ctx->bases.back().name]
|
||||||
.methods[ctx->cache->reverseIdentifierLookup[f->name]]
|
.methods[ctx->cache->reverseIdentifierLookup[f->name]] = rootName;
|
||||||
.push_back({newName, nullptr, ctx->cache->age});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto sp : getClassMethods(stmt->suite))
|
for (auto sp : getClassMethods(stmt->suite))
|
||||||
@ -1248,8 +1261,10 @@ StmtPtr SimplifyVisitor::transformCImport(const std::string &name,
|
|||||||
auto f = N<FunctionStmt>(name, ret ? ret->clone() : N<IdExpr>("void"), fnArgs,
|
auto f = N<FunctionStmt>(name, ret ? ret->clone() : N<IdExpr>("void"), fnArgs,
|
||||||
nullptr, attr);
|
nullptr, attr);
|
||||||
StmtPtr tf = transform(f); // Already in the preamble
|
StmtPtr tf = transform(f); // Already in the preamble
|
||||||
if (!altName.empty())
|
if (!altName.empty()) {
|
||||||
ctx->add(altName, ctx->find(name));
|
ctx->add(altName, ctx->find(name));
|
||||||
|
ctx->remove(name);
|
||||||
|
}
|
||||||
return tf;
|
return tf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1392,10 +1407,11 @@ void SimplifyVisitor::transformNewImport(const ImportFile &file) {
|
|||||||
stmts[0] = N<SuiteStmt>();
|
stmts[0] = N<SuiteStmt>();
|
||||||
// Add a def import(): ... manually to the cache and to the preamble (it won't be
|
// Add a def import(): ... manually to the cache and to the preamble (it won't be
|
||||||
// transformed here!).
|
// transformed here!).
|
||||||
ctx->cache->functions[importVar].ast =
|
ctx->cache->overloads[importVar].push_back({importVar, ctx->cache->age});
|
||||||
N<FunctionStmt>(importVar, nullptr, std::vector<Param>{}, N<SuiteStmt>(stmts),
|
ctx->cache->functions[importVar + ":0"].ast =
|
||||||
Attr({Attr::ForceRealize}));
|
N<FunctionStmt>(importVar + ":0", nullptr, std::vector<Param>{},
|
||||||
preamble->functions.push_back(ctx->cache->functions[importVar].ast->clone());
|
N<SuiteStmt>(stmts), Attr({Attr::ForceRealize}));
|
||||||
|
preamble->functions.push_back(ctx->cache->functions[importVar + ":0"].ast->clone());
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1768,15 +1784,5 @@ std::vector<StmtPtr> SimplifyVisitor::getClassMethods(const StmtPtr &s) {
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimplifyVisitor::generateDispatch(const std::string &name) {
|
|
||||||
transform(N<FunctionStmt>(
|
|
||||||
name + ".dispatch", nullptr,
|
|
||||||
std::vector<Param>{Param("*args"), Param("**kwargs")},
|
|
||||||
N<SuiteStmt>(N<ReturnStmt>(N<CallExpr>(
|
|
||||||
N<DotExpr>(N<IdExpr>(ctx->bases.back().name), name),
|
|
||||||
N<StarExpr>(N<IdExpr>("args")), N<KeywordStarExpr>(N<IdExpr>("kwargs"))))),
|
|
||||||
Attr({"autogenerated"})));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
} // namespace codon
|
} // namespace codon
|
||||||
|
@ -296,7 +296,8 @@ void TranslateVisitor::visit(ForStmt *stmt) {
|
|||||||
auto c = stmt->decorator->getCall();
|
auto c = stmt->decorator->getCall();
|
||||||
seqassert(c, "for par is not a call: {}", stmt->decorator->toString());
|
seqassert(c, "for par is not a call: {}", stmt->decorator->toString());
|
||||||
auto fc = c->expr->getType()->getFunc();
|
auto fc = c->expr->getType()->getFunc();
|
||||||
seqassert(fc && fc->ast->name == "std.openmp.for_par", "for par is not a function");
|
seqassert(fc && fc->ast->name == "std.openmp.for_par:0",
|
||||||
|
"for par is not a function");
|
||||||
auto schedule =
|
auto schedule =
|
||||||
fc->funcGenerics[0].type->getStatic()->expr->staticValue.getString();
|
fc->funcGenerics[0].type->getStatic()->expr->staticValue.getString();
|
||||||
bool ordered = fc->funcGenerics[1].type->getStatic()->expr->staticValue.getInt();
|
bool ordered = fc->funcGenerics[1].type->getStatic()->expr->staticValue.getInt();
|
||||||
|
@ -313,6 +313,8 @@ private:
|
|||||||
int64_t translateIndex(int64_t idx, int64_t len, bool clamp = false);
|
int64_t translateIndex(int64_t idx, int64_t len, bool clamp = false);
|
||||||
int64_t sliceAdjustIndices(int64_t length, int64_t *start, int64_t *stop,
|
int64_t sliceAdjustIndices(int64_t length, int64_t *start, int64_t *stop,
|
||||||
int64_t step);
|
int64_t step);
|
||||||
|
types::FuncTypePtr findDispatch(const std::string &fn);
|
||||||
|
std::string getRootName(const std::string &name);
|
||||||
|
|
||||||
friend struct Cache;
|
friend struct Cache;
|
||||||
};
|
};
|
||||||
|
@ -142,22 +142,23 @@ std::vector<types::FuncTypePtr> TypeContext::findMethod(const std::string &typeN
|
|||||||
auto m = cache->classes.find(typeName);
|
auto m = cache->classes.find(typeName);
|
||||||
if (m != cache->classes.end()) {
|
if (m != cache->classes.end()) {
|
||||||
auto t = m->second.methods.find(method);
|
auto t = m->second.methods.find(method);
|
||||||
if (t != m->second.methods.end() && !t->second.empty()) {
|
if (t != m->second.methods.end()) {
|
||||||
seqassert(!t->second.empty() && endswith(t->second[0].name, ".dispatch"),
|
auto mt = cache->overloads[t->second];
|
||||||
"first method '{}' is not dispatch", t->second[0].name);
|
|
||||||
std::unordered_set<std::string> signatureLoci;
|
std::unordered_set<std::string> signatureLoci;
|
||||||
std::vector<types::FuncTypePtr> vv;
|
std::vector<types::FuncTypePtr> vv;
|
||||||
for (int mti = int(t->second.size()) - 1; mti > 0; mti--) {
|
for (int mti = int(mt.size()) - 1; mti >= 0; mti--) {
|
||||||
auto &mt = t->second[mti];
|
auto &m = mt[mti];
|
||||||
if (mt.age <= age) {
|
if (endswith(m.name, ":dispatch"))
|
||||||
|
continue;
|
||||||
|
if (m.age <= age) {
|
||||||
if (hideShadowed) {
|
if (hideShadowed) {
|
||||||
auto sig = cache->functions[mt.name].ast->signature();
|
auto sig = cache->functions[m.name].ast->signature();
|
||||||
if (!in(signatureLoci, sig)) {
|
if (!in(signatureLoci, sig)) {
|
||||||
signatureLoci.insert(sig);
|
signatureLoci.insert(sig);
|
||||||
vv.emplace_back(mt.type);
|
vv.emplace_back(cache->functions[m.name].type);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
vv.emplace_back(mt.type);
|
vv.emplace_back(cache->functions[m.name].type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,6 +105,9 @@ void TypecheckVisitor::visit(IdExpr *expr) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto val = ctx->find(expr->value);
|
auto val = ctx->find(expr->value);
|
||||||
|
if (!val) {
|
||||||
|
val = ctx->find(expr->value + ":0"); // is it function?!
|
||||||
|
}
|
||||||
seqassert(val, "cannot find IdExpr '{}' ({})", expr->value, expr->getSrcInfo());
|
seqassert(val, "cannot find IdExpr '{}' ({})", expr->value, expr->getSrcInfo());
|
||||||
|
|
||||||
auto t = ctx->instantiate(expr, val->type);
|
auto t = ctx->instantiate(expr, val->type);
|
||||||
@ -725,14 +728,17 @@ ExprPtr TypecheckVisitor::transformBinary(BinaryExpr *expr, bool isAtomic,
|
|||||||
|
|
||||||
ExprPtr TypecheckVisitor::transformStaticTupleIndex(ClassType *tuple, ExprPtr &expr,
|
ExprPtr TypecheckVisitor::transformStaticTupleIndex(ClassType *tuple, ExprPtr &expr,
|
||||||
ExprPtr &index) {
|
ExprPtr &index) {
|
||||||
if (!tuple->getRecord() ||
|
if (!tuple->getRecord())
|
||||||
in(std::set<std::string>{"Ptr", "pyobj", "str", "Array"}, tuple->name))
|
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__
|
// Ptr, pyobj and str are internal types and have only one overloaded __getitem__
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (ctx->cache->classes[tuple->name].methods["__getitem__"].size() != 2)
|
// if (in(ctx->cache->classes[tuple->name].methods, "__getitem__")) {
|
||||||
// n.b.: there is dispatch as well
|
// ctx->cache->overloads[ctx->cache->classes[tuple->name].methods["__getitem__"]]
|
||||||
// TODO: be smarter! there might be a compatible getitem?
|
// .size() != 1)
|
||||||
return nullptr;
|
// return nullptr;
|
||||||
|
// }
|
||||||
|
|
||||||
// Extract a static integer value from a compatible expression.
|
// Extract a static integer value from a compatible expression.
|
||||||
auto getInt = [&](int64_t *o, const ExprPtr &e) {
|
auto getInt = [&](int64_t *o, const ExprPtr &e) {
|
||||||
@ -919,9 +925,7 @@ ExprPtr TypecheckVisitor::transformDot(DotExpr *expr,
|
|||||||
} else if (methods.size() > 1) {
|
} else if (methods.size() > 1) {
|
||||||
auto m = ctx->cache->classes.find(typ->name);
|
auto m = ctx->cache->classes.find(typ->name);
|
||||||
auto t = m->second.methods.find(expr->member);
|
auto t = m->second.methods.find(expr->member);
|
||||||
seqassert(!t->second.empty() && endswith(t->second[0].name, ".dispatch"),
|
bestMethod = findDispatch(t->second);
|
||||||
"first method is not dispatch");
|
|
||||||
bestMethod = t->second[0].type;
|
|
||||||
} else {
|
} else {
|
||||||
bestMethod = methods[0];
|
bestMethod = methods[0];
|
||||||
}
|
}
|
||||||
@ -1036,7 +1040,8 @@ ExprPtr TypecheckVisitor::transformCall(CallExpr *expr, const types::TypePtr &in
|
|||||||
ctx->bases.back().supers, expr->args);
|
ctx->bases.back().supers, expr->args);
|
||||||
if (m.empty())
|
if (m.empty())
|
||||||
error("no matching super methods are available");
|
error("no matching super methods are available");
|
||||||
// LOG("found {} <- {}", ctx->bases.back().type->getFunc()->toString(), m[0]->toString());
|
// LOG("found {} <- {}", ctx->bases.back().type->getFunc()->toString(),
|
||||||
|
// m[0]->toString());
|
||||||
ExprPtr e = N<CallExpr>(N<IdExpr>(m[0]->ast->name), expr->args);
|
ExprPtr e = N<CallExpr>(N<IdExpr>(m[0]->ast->name), expr->args);
|
||||||
return transform(e, false, true);
|
return transform(e, false, true);
|
||||||
}
|
}
|
||||||
@ -1700,7 +1705,7 @@ TypecheckVisitor::findBestMethod(const Expr *expr, const std::string &member,
|
|||||||
std::vector<types::FuncTypePtr>
|
std::vector<types::FuncTypePtr>
|
||||||
TypecheckVisitor::findSuperMethods(const types::FuncTypePtr &func) {
|
TypecheckVisitor::findSuperMethods(const types::FuncTypePtr &func) {
|
||||||
if (func->ast->attributes.parentClass.empty() ||
|
if (func->ast->attributes.parentClass.empty() ||
|
||||||
endswith(func->ast->name, ".dispatch"))
|
endswith(func->ast->name, ":dispatch"))
|
||||||
return {};
|
return {};
|
||||||
auto p = ctx->find(func->ast->attributes.parentClass)->type;
|
auto p = ctx->find(func->ast->attributes.parentClass)->type;
|
||||||
if (!p || !p->getClass())
|
if (!p || !p->getClass())
|
||||||
@ -1711,14 +1716,13 @@ TypecheckVisitor::findSuperMethods(const types::FuncTypePtr &func) {
|
|||||||
std::vector<types::FuncTypePtr> result;
|
std::vector<types::FuncTypePtr> result;
|
||||||
if (m != ctx->cache->classes.end()) {
|
if (m != ctx->cache->classes.end()) {
|
||||||
auto t = m->second.methods.find(methodName);
|
auto t = m->second.methods.find(methodName);
|
||||||
if (t != m->second.methods.end() && !t->second.empty()) {
|
if (t != m->second.methods.end()) {
|
||||||
seqassert(!t->second.empty() && endswith(t->second[0].name, ".dispatch"),
|
for (auto &m : ctx->cache->overloads[t->second]) {
|
||||||
"first method '{}' is not dispatch", t->second[0].name);
|
if (endswith(m.name, ":dispatch"))
|
||||||
for (int mti = 1; mti < t->second.size(); mti++) {
|
continue;
|
||||||
auto &mt = t->second[mti];
|
if (m.name == func->ast->name)
|
||||||
if (mt.type->ast->name == func->ast->name)
|
|
||||||
break;
|
break;
|
||||||
result.emplace_back(mt.type);
|
result.emplace_back(ctx->cache->functions[m.name].type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1860,5 +1864,45 @@ int64_t TypecheckVisitor::sliceAdjustIndices(int64_t length, int64_t *start,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
types::FuncTypePtr TypecheckVisitor::findDispatch(const std::string &fn) {
|
||||||
|
for (auto &m : ctx->cache->overloads[fn])
|
||||||
|
if (endswith(ctx->cache->functions[m.name].ast->name, ":dispatch"))
|
||||||
|
return ctx->cache->functions[m.name].type;
|
||||||
|
|
||||||
|
// Generate dispatch and return it!
|
||||||
|
auto name = fn + ":dispatch";
|
||||||
|
|
||||||
|
ExprPtr root;
|
||||||
|
auto a = ctx->cache->functions[ctx->cache->overloads[fn][0].name].ast;
|
||||||
|
if (!a->attributes.parentClass.empty())
|
||||||
|
root = N<DotExpr>(N<IdExpr>(a->attributes.parentClass),
|
||||||
|
ctx->cache->reverseIdentifierLookup[fn]);
|
||||||
|
else
|
||||||
|
root = N<IdExpr>(fn);
|
||||||
|
root = N<CallExpr>(root, N<StarExpr>(N<IdExpr>("args")),
|
||||||
|
N<KeywordStarExpr>(N<IdExpr>("kwargs")));
|
||||||
|
auto ast = N<FunctionStmt>(
|
||||||
|
name, nullptr, std::vector<Param>{Param("*args"), Param("**kwargs")},
|
||||||
|
N<SuiteStmt>(N<IfStmt>(
|
||||||
|
N<CallExpr>(N<IdExpr>("isinstance"), root->clone(), N<IdExpr>("void")),
|
||||||
|
N<ExprStmt>(root->clone()), N<ReturnStmt>(root))),
|
||||||
|
Attr({"autogenerated"}));
|
||||||
|
ctx->cache->reverseIdentifierLookup[name] = ctx->cache->reverseIdentifierLookup[fn];
|
||||||
|
|
||||||
|
auto baseType =
|
||||||
|
ctx->instantiate(N<IdExpr>(name).get(), ctx->find(generateFunctionStub(2))->type,
|
||||||
|
nullptr, false)
|
||||||
|
->getRecord();
|
||||||
|
auto typ = std::make_shared<FuncType>(baseType, ast.get());
|
||||||
|
typ = std::static_pointer_cast<FuncType>(typ->generalize(ctx->typecheckLevel));
|
||||||
|
ctx->add(TypecheckItem::Func, name, typ);
|
||||||
|
|
||||||
|
ctx->cache->overloads[fn].insert(ctx->cache->overloads[fn].begin(), {name, 0});
|
||||||
|
ctx->cache->functions[name].ast = ast;
|
||||||
|
ctx->cache->functions[name].type = typ;
|
||||||
|
prependStmts->push_back(ast);
|
||||||
|
return typ;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
} // namespace codon
|
} // namespace codon
|
||||||
|
@ -474,12 +474,12 @@ void TypecheckVisitor::visit(FunctionStmt *stmt) {
|
|||||||
typ = std::static_pointer_cast<FuncType>(typ->generalize(ctx->typecheckLevel));
|
typ = std::static_pointer_cast<FuncType>(typ->generalize(ctx->typecheckLevel));
|
||||||
// Check if this is a class method; if so, update the class method lookup table.
|
// Check if this is a class method; if so, update the class method lookup table.
|
||||||
if (isClassMember) {
|
if (isClassMember) {
|
||||||
auto &methods = ctx->cache->classes[attr.parentClass]
|
auto m = ctx->cache->classes[attr.parentClass]
|
||||||
.methods[ctx->cache->reverseIdentifierLookup[stmt->name]];
|
.methods[ctx->cache->reverseIdentifierLookup[stmt->name]];
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (auto &i : methods)
|
for (auto &i : ctx->cache->overloads[m])
|
||||||
if (i.name == stmt->name) {
|
if (i.name == stmt->name) {
|
||||||
i.type = typ;
|
ctx->cache->functions[i.name].type = typ;
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -570,5 +570,11 @@ void TypecheckVisitor::visit(ClassStmt *stmt) {
|
|||||||
stmt->done = true;
|
stmt->done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string TypecheckVisitor::getRootName(const std::string &name) {
|
||||||
|
auto p = name.rfind(':');
|
||||||
|
seqassert(p != std::string::npos, ": not found in {}", name);
|
||||||
|
return name.substr(0, p);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
} // namespace codon
|
} // namespace codon
|
||||||
|
@ -44,6 +44,7 @@ class str:
|
|||||||
if c == '\n': d = "\\n"
|
if c == '\n': d = "\\n"
|
||||||
elif c == '\r': d = "\\r"
|
elif c == '\r': d = "\\r"
|
||||||
elif c == '\t': d = "\\t"
|
elif c == '\t': d = "\\t"
|
||||||
|
elif c == '\a': d = "\\a"
|
||||||
elif c == '\\': d = "\\\\"
|
elif c == '\\': d = "\\\\"
|
||||||
elif c == q: d = qe
|
elif c == q: d = qe
|
||||||
else:
|
else:
|
||||||
|
@ -538,7 +538,7 @@ def foo() -> int:
|
|||||||
a{=a}
|
a{=a}
|
||||||
foo()
|
foo()
|
||||||
#! not a type or static expression
|
#! not a type or static expression
|
||||||
#! while realizing foo (arguments foo)
|
#! while realizing foo:0 (arguments foo:0)
|
||||||
|
|
||||||
#%% function_llvm_err_4,barebones
|
#%% function_llvm_err_4,barebones
|
||||||
a = 5
|
a = 5
|
||||||
|
@ -374,7 +374,7 @@ def foo(i, j, k):
|
|||||||
return i + j + k
|
return i + j + k
|
||||||
print foo(1.1, 2.2, 3.3) #: 6.6
|
print foo(1.1, 2.2, 3.3) #: 6.6
|
||||||
p = foo(6, ...)
|
p = foo(6, ...)
|
||||||
print p.__class__ #: foo[int,...,...]
|
print p.__class__ #: foo:0[int,...,...]
|
||||||
print p(2, 1) #: 9
|
print p(2, 1) #: 9
|
||||||
print p(k=3, j=6) #: 15
|
print p(k=3, j=6) #: 15
|
||||||
q = p(k=1, ...)
|
q = p(k=1, ...)
|
||||||
@ -390,11 +390,11 @@ print 42 |> add_two #: 44
|
|||||||
def moo(a, b, c=3):
|
def moo(a, b, c=3):
|
||||||
print a, b, c
|
print a, b, c
|
||||||
m = moo(b=2, ...)
|
m = moo(b=2, ...)
|
||||||
print m.__class__ #: moo[...,int,...]
|
print m.__class__ #: moo:0[...,int,...]
|
||||||
m('s', 1.1) #: s 2 1.1
|
m('s', 1.1) #: s 2 1.1
|
||||||
# #
|
# #
|
||||||
n = m(c=2.2, ...)
|
n = m(c=2.2, ...)
|
||||||
print n.__class__ #: moo[...,int,float]
|
print n.__class__ #: moo:0[...,int,float]
|
||||||
n('x') #: x 2 2.2
|
n('x') #: x 2 2.2
|
||||||
print n('y').__class__ #: void
|
print n('y').__class__ #: void
|
||||||
|
|
||||||
@ -403,11 +403,11 @@ def ff(a, b, c):
|
|||||||
print ff(1.1, 2, True).__class__ #: Tuple[float,int,bool]
|
print ff(1.1, 2, True).__class__ #: Tuple[float,int,bool]
|
||||||
print ff(1.1, ...)(2, True).__class__ #: Tuple[float,int,bool]
|
print ff(1.1, ...)(2, True).__class__ #: Tuple[float,int,bool]
|
||||||
y = ff(1.1, ...)(c=True, ...)
|
y = ff(1.1, ...)(c=True, ...)
|
||||||
print y.__class__ #: ff[float,...,bool]
|
print y.__class__ #: ff:0[float,...,bool]
|
||||||
print ff(1.1, ...)(2, ...)(True).__class__ #: Tuple[float,int,bool]
|
print ff(1.1, ...)(2, ...)(True).__class__ #: Tuple[float,int,bool]
|
||||||
print y('hei').__class__ #: Tuple[float,str,bool]
|
print y('hei').__class__ #: Tuple[float,str,bool]
|
||||||
z = ff(1.1, ...)(c='s', ...)
|
z = ff(1.1, ...)(c='s', ...)
|
||||||
print z.__class__ #: ff[float,...,str]
|
print z.__class__ #: ff:0[float,...,str]
|
||||||
|
|
||||||
#%% call_arguments_partial,barebones
|
#%% call_arguments_partial,barebones
|
||||||
def doo[R, T](a: Callable[[T], R], b: Generator[T], c: Optional[T], d: T):
|
def doo[R, T](a: Callable[[T], R], b: Generator[T], c: Optional[T], d: T):
|
||||||
@ -432,7 +432,7 @@ l = [1]
|
|||||||
def adder(a, b): return a+b
|
def adder(a, b): return a+b
|
||||||
doo(b=l, d=Optional(5), c=l[0], a=adder(b=4, ...))
|
doo(b=l, d=Optional(5), c=l[0], a=adder(b=4, ...))
|
||||||
#: int int
|
#: int int
|
||||||
#: adder[.. Generator[int]
|
#: adder:0[ Generator[int]
|
||||||
#: 5
|
#: 5
|
||||||
#: 1 Optional[int]
|
#: 1 Optional[int]
|
||||||
#: 5 int
|
#: 5 int
|
||||||
|
@ -252,7 +252,7 @@ try:
|
|||||||
except MyError:
|
except MyError:
|
||||||
print "my"
|
print "my"
|
||||||
except OSError as o:
|
except OSError as o:
|
||||||
print "os", o._hdr[0], len(o._hdr[1]), o._hdr[3][-20:], o._hdr[4]
|
print "os", o._hdr.typename, len(o._hdr.msg), o._hdr.file[-20:], o._hdr.line
|
||||||
#: os std.internal.types.error.OSError 9 typecheck_stmt.codon 249
|
#: os std.internal.types.error.OSError 9 typecheck_stmt.codon 249
|
||||||
finally:
|
finally:
|
||||||
print "whoa" #: whoa
|
print "whoa" #: whoa
|
||||||
@ -263,7 +263,7 @@ def foo():
|
|||||||
try:
|
try:
|
||||||
foo()
|
foo()
|
||||||
except MyError as e:
|
except MyError as e:
|
||||||
print e._hdr[0], e._hdr[1] #: MyError foo!
|
print e._hdr.typename, e._hdr.msg #: MyError foo!
|
||||||
|
|
||||||
#%% throw_error,barebones
|
#%% throw_error,barebones
|
||||||
raise 'hello' #! cannot throw non-exception (first object member must be of type ExcHeader)
|
raise 'hello' #! cannot throw non-exception (first object member must be of type ExcHeader)
|
||||||
@ -291,13 +291,13 @@ def foo(x):
|
|||||||
print len(x)
|
print len(x)
|
||||||
foo(5) #: 4
|
foo(5) #: 4
|
||||||
|
|
||||||
def foo(x):
|
def foo2(x):
|
||||||
if isinstance(x, int):
|
if isinstance(x, int):
|
||||||
print x+1
|
print x+1
|
||||||
return
|
return
|
||||||
print len(x)
|
print len(x)
|
||||||
foo(1) #: 2
|
foo2(1) #: 2
|
||||||
foo('s') #: 1
|
foo2('s') #: 1
|
||||||
|
|
||||||
#%% super,barebones
|
#%% super,barebones
|
||||||
class Foo:
|
class Foo:
|
||||||
@ -341,4 +341,4 @@ class Foo:
|
|||||||
print 'foo-1', a
|
print 'foo-1', a
|
||||||
Foo.foo(1)
|
Foo.foo(1)
|
||||||
#! no matching super methods are available
|
#! no matching super methods are available
|
||||||
#! while realizing Foo.foo.2
|
#! while realizing Foo.foo:0
|
||||||
|
@ -199,10 +199,10 @@ def f[T](x: T) -> T:
|
|||||||
print f(1.2).__class__ #: float
|
print f(1.2).__class__ #: float
|
||||||
print f('s').__class__ #: str
|
print f('s').__class__ #: str
|
||||||
|
|
||||||
def f[T](x: T):
|
def f2[T](x: T):
|
||||||
return f(x - 1, T) if x else 1
|
return f2(x - 1, T) if x else 1
|
||||||
print f(1) #: 1
|
print f2(1) #: 1
|
||||||
print f(1.1).__class__ #: int
|
print f2(1.1).__class__ #: int
|
||||||
|
|
||||||
|
|
||||||
#%% recursive_error,barebones
|
#%% recursive_error,barebones
|
||||||
@ -215,7 +215,7 @@ def rec3(x, y): #- ('a, 'b) -> 'b
|
|||||||
return y
|
return y
|
||||||
rec3(1, 's')
|
rec3(1, 's')
|
||||||
#! cannot unify str and int
|
#! cannot unify str and int
|
||||||
#! while realizing rec3 (arguments rec3[int,str])
|
#! while realizing rec3:0 (arguments rec3:0[int,str])
|
||||||
|
|
||||||
#%% instantiate_function_2,barebones
|
#%% instantiate_function_2,barebones
|
||||||
def fx[T](x: T) -> T:
|
def fx[T](x: T) -> T:
|
||||||
@ -447,13 +447,13 @@ def f(x):
|
|||||||
return g(x)
|
return g(x)
|
||||||
print f(5), f('s') #: 5 s
|
print f(5), f('s') #: 5 s
|
||||||
|
|
||||||
def f[U](x: U, y):
|
def f2[U](x: U, y):
|
||||||
def g[T, U](x: T, y: U):
|
def g[T, U](x: T, y: U):
|
||||||
return (x, y)
|
return (x, y)
|
||||||
return g(y, x)
|
return g(y, x)
|
||||||
x, y = 1, 'haha'
|
x, y = 1, 'haha'
|
||||||
print f(x, y).__class__ #: Tuple[str,int]
|
print f2(x, y).__class__ #: Tuple[str,int]
|
||||||
print f('aa', 1.1, U=str).__class__ #: Tuple[float,str]
|
print f2('aa', 1.1, U=str).__class__ #: Tuple[float,str]
|
||||||
|
|
||||||
#%% nested_fn_generic_error,barebones
|
#%% nested_fn_generic_error,barebones
|
||||||
def f[U](x: U, y): # ('u, 'a) -> tuple['a, 'u]
|
def f[U](x: U, y): # ('u, 'a) -> tuple['a, 'u]
|
||||||
@ -464,7 +464,7 @@ print f(1.1, 1, int).__class__ #! cannot unify float and int
|
|||||||
|
|
||||||
#%% fn_realization,barebones
|
#%% fn_realization,barebones
|
||||||
def ff[T](x: T, y: tuple[T]):
|
def ff[T](x: T, y: tuple[T]):
|
||||||
print ff(T=str,...).__class__ #: ff[str,Tuple[str],str]
|
print ff(T=str,...).__class__ #: ff:0[str,Tuple[str],str]
|
||||||
return x
|
return x
|
||||||
x = ff(1, (1,))
|
x = ff(1, (1,))
|
||||||
print x, x.__class__ #: 1 int
|
print x, x.__class__ #: 1 int
|
||||||
@ -474,7 +474,7 @@ def fg[T](x:T):
|
|||||||
def g[T](y):
|
def g[T](y):
|
||||||
z = T()
|
z = T()
|
||||||
return z
|
return z
|
||||||
print fg(T=str,...).__class__ #: fg[str,str]
|
print fg(T=str,...).__class__ #: fg:0[str,str]
|
||||||
print g(1, T).__class__ #: int
|
print g(1, T).__class__ #: int
|
||||||
fg(1)
|
fg(1)
|
||||||
print fg(1).__class__ #: void
|
print fg(1).__class__ #: void
|
||||||
@ -515,7 +515,7 @@ class A[T]:
|
|||||||
def foo[W](t: V, u: V, v: V, w: W):
|
def foo[W](t: V, u: V, v: V, w: W):
|
||||||
return (t, u, v, w)
|
return (t, u, v, w)
|
||||||
|
|
||||||
print A.B.C[bool].foo(W=str, ...).__class__ #: A.B.C.foo.2[bool,bool,bool,str,str]
|
print A.B.C[bool].foo(W=str, ...).__class__ #: A.B.C.foo:0[bool,bool,bool,str,str]
|
||||||
print A.B.C.foo(1,1,1,True) #: (1, 1, 1, True)
|
print A.B.C.foo(1,1,1,True) #: (1, 1, 1, True)
|
||||||
print A.B.C.foo('x', 'x', 'x', 'x') #: ('x', 'x', 'x', 'x')
|
print A.B.C.foo('x', 'x', 'x', 'x') #: ('x', 'x', 'x', 'x')
|
||||||
print A.B.C.foo('x', 'x', 'x', 'x') #: ('x', 'x', 'x', 'x')
|
print A.B.C.foo('x', 'x', 'x', 'x') #: ('x', 'x', 'x', 'x')
|
||||||
@ -734,10 +734,10 @@ def test(name, sort, key):
|
|||||||
def foo(l, f):
|
def foo(l, f):
|
||||||
return [f(i) for i in l]
|
return [f(i) for i in l]
|
||||||
test('hi', foo, lambda x: x+1) #: hi [2, 3, 4, 5]
|
test('hi', foo, lambda x: x+1) #: hi [2, 3, 4, 5]
|
||||||
# TODO
|
|
||||||
# def foof(l: List[int], x, f: Callable[[int], int]):
|
def foof(l: List[int], x, f: Callable[[int], int]):
|
||||||
# return [f(i)+x for i in l]
|
return [f(i)+x for i in l]
|
||||||
# test('qsort', foof(..., 3, ...))
|
test('qsort', foof(x=3, ...), lambda x: x+1) #: qsort [5, 6, 7, 8]
|
||||||
|
|
||||||
#%% class_fn_access,barebones
|
#%% class_fn_access,barebones
|
||||||
class X[T]:
|
class X[T]:
|
||||||
@ -745,8 +745,7 @@ class X[T]:
|
|||||||
return (x+x, y+y)
|
return (x+x, y+y)
|
||||||
y = X[X[int]]()
|
y = X[X[int]]()
|
||||||
print y.__class__ #: X[X[int]]
|
print y.__class__ #: X[X[int]]
|
||||||
print X[float].foo(U=int, ...).__class__ #: X.foo.2[X[float],float,int,int]
|
print X[float].foo(U=int, ...).__class__ #: X.foo:0[X[float],float,int,int]
|
||||||
# print y.foo.1[float].__class__
|
|
||||||
print X[int]().foo(1, 's') #: (2, 'ss')
|
print X[int]().foo(1, 's') #: (2, 'ss')
|
||||||
|
|
||||||
#%% class_partial_access,barebones
|
#%% class_partial_access,barebones
|
||||||
@ -754,7 +753,7 @@ class X[T]:
|
|||||||
def foo[U](self, x, y: U):
|
def foo[U](self, x, y: U):
|
||||||
return (x+x, y+y)
|
return (x+x, y+y)
|
||||||
y = X[X[int]]()
|
y = X[X[int]]()
|
||||||
print y.foo(U=float,...).__class__ #: X.foo.2[X[X[int]],...,...]
|
print y.foo(U=float,...).__class__ #: X.foo:0[X[X[int]],...,...]
|
||||||
print y.foo(1, 2.2, float) #: (2, 4.4)
|
print y.foo(1, 2.2, float) #: (2, 4.4)
|
||||||
|
|
||||||
#%% forward,barebones
|
#%% forward,barebones
|
||||||
@ -765,10 +764,10 @@ def bar[T](x):
|
|||||||
print x, T.__class__
|
print x, T.__class__
|
||||||
foo(bar, 1)
|
foo(bar, 1)
|
||||||
#: 1 int
|
#: 1 int
|
||||||
#: bar[...]
|
#: bar:0[...]
|
||||||
foo(bar(...), 's')
|
foo(bar(...), 's')
|
||||||
#: s str
|
#: s str
|
||||||
#: bar[...]
|
#: bar:0[...]
|
||||||
z = bar
|
z = bar
|
||||||
z('s', int)
|
z('s', int)
|
||||||
#: s int
|
#: s int
|
||||||
@ -786,8 +785,8 @@ def foo(f, x):
|
|||||||
def bar[T](x):
|
def bar[T](x):
|
||||||
print x, T.__class__
|
print x, T.__class__
|
||||||
foo(bar(T=int,...), 1)
|
foo(bar(T=int,...), 1)
|
||||||
#! too many arguments for bar[T1,int] (expected maximum 2, got 2)
|
#! too many arguments for bar:0[T1,int] (expected maximum 2, got 2)
|
||||||
#! while realizing foo (arguments foo[bar[...],int])
|
#! while realizing foo:0 (arguments foo:0[bar:0[...],int])
|
||||||
|
|
||||||
#%% sort_partial
|
#%% sort_partial
|
||||||
def foo(x, y):
|
def foo(x, y):
|
||||||
@ -806,16 +805,16 @@ def frec(x, y):
|
|||||||
return grec(x, y) if bl(y) else 2
|
return grec(x, y) if bl(y) else 2
|
||||||
print frec(1, 2).__class__, frec('s', 1).__class__
|
print frec(1, 2).__class__, frec('s', 1).__class__
|
||||||
#! expression with void type
|
#! expression with void type
|
||||||
#! while realizing frec (arguments frec[int,int])
|
#! while realizing frec:0 (arguments frec:0[int,int])
|
||||||
|
|
||||||
#%% return_fn,barebones
|
#%% return_fn,barebones
|
||||||
def retfn(a):
|
def retfn(a):
|
||||||
def inner(b, *args, **kwargs):
|
def inner(b, *args, **kwargs):
|
||||||
print a, b, args, kwargs
|
print a, b, args, kwargs
|
||||||
print inner.__class__ #: retfn.inner[...,...,int,...]
|
print inner.__class__ #: retfn:0.inner:0[...,...,int,...]
|
||||||
return inner(15, ...)
|
return inner(15, ...)
|
||||||
f = retfn(1)
|
f = retfn(1)
|
||||||
print f.__class__ #: retfn.inner[int,...,int,...]
|
print f.__class__ #: retfn:0.inner:0[int,...,int,...]
|
||||||
f(2,3,foo='bar') #: 1 15 (2, 3) (foo: 'bar')
|
f(2,3,foo='bar') #: 1 15 (2, 3) (foo: 'bar')
|
||||||
|
|
||||||
#%% decorator_manual,barebones
|
#%% decorator_manual,barebones
|
||||||
@ -823,7 +822,7 @@ def foo(x, *args, **kwargs):
|
|||||||
print x, args, kwargs
|
print x, args, kwargs
|
||||||
return 1
|
return 1
|
||||||
def dec(fn, a):
|
def dec(fn, a):
|
||||||
print 'decorating', fn.__class__ #: decorating foo[...,...,...]
|
print 'decorating', fn.__class__ #: decorating foo:0[...,...,...]
|
||||||
def inner(*args, **kwargs):
|
def inner(*args, **kwargs):
|
||||||
print 'decorator', args, kwargs #: decorator (5.5, 's') (z: True)
|
print 'decorator', args, kwargs #: decorator (5.5, 's') (z: True)
|
||||||
return fn(a, *args, **kwargs)
|
return fn(a, *args, **kwargs)
|
||||||
@ -846,7 +845,7 @@ def dec(fn, a):
|
|||||||
return inner
|
return inner
|
||||||
ff = dec(foo, 10)
|
ff = dec(foo, 10)
|
||||||
print ff(5.5, 's', z=True)
|
print ff(5.5, 's', z=True)
|
||||||
#: decorating foo[...,...,...]
|
#: decorating foo:0[...,...,...]
|
||||||
#: decorator (5.5, 's') (z: True)
|
#: decorator (5.5, 's') (z: True)
|
||||||
#: 10 (5.5, 's') (z: True)
|
#: 10 (5.5, 's') (z: True)
|
||||||
#: 1
|
#: 1
|
||||||
@ -856,7 +855,7 @@ def zoo(e, b, *args):
|
|||||||
return f'zoo: {e}, {b}, {args}'
|
return f'zoo: {e}, {b}, {args}'
|
||||||
print zoo(2, 3)
|
print zoo(2, 3)
|
||||||
print zoo('s', 3)
|
print zoo('s', 3)
|
||||||
#: decorating zoo[...,...,...]
|
#: decorating zoo:0[...,...,...]
|
||||||
#: decorator (2, 3) ()
|
#: decorator (2, 3) ()
|
||||||
#: zoo: 5, 2, (3)
|
#: zoo: 5, 2, (3)
|
||||||
#: decorator ('s', 3) ()
|
#: decorator ('s', 3) ()
|
||||||
@ -869,9 +868,9 @@ def mydecorator(func):
|
|||||||
print("after")
|
print("after")
|
||||||
return inner
|
return inner
|
||||||
@mydecorator
|
@mydecorator
|
||||||
def foo():
|
def foo2():
|
||||||
print("foo")
|
print("foo")
|
||||||
foo()
|
foo2()
|
||||||
#: before
|
#: before
|
||||||
#: foo
|
#: foo
|
||||||
#: after
|
#: after
|
||||||
@ -891,7 +890,7 @@ def factorial(num):
|
|||||||
return n
|
return n
|
||||||
factorial(10)
|
factorial(10)
|
||||||
#: 3628800
|
#: 3628800
|
||||||
#: time needed for factorial[...] is 3628799
|
#: time needed for factorial:0[...] is 3628799
|
||||||
|
|
||||||
def dx1(func):
|
def dx1(func):
|
||||||
def inner():
|
def inner():
|
||||||
@ -921,9 +920,9 @@ def dy2(func):
|
|||||||
return inner
|
return inner
|
||||||
@dy1
|
@dy1
|
||||||
@dy2
|
@dy2
|
||||||
def num(a, b):
|
def num2(a, b):
|
||||||
return a+b
|
return a+b
|
||||||
print(num(10, 20)) #: 3600
|
print(num2(10, 20)) #: 3600
|
||||||
|
|
||||||
#%% hetero_iter,barebones
|
#%% hetero_iter,barebones
|
||||||
e = (1, 2, 3, 'foo', 5, 'bar', 6)
|
e = (1, 2, 3, 'foo', 5, 'bar', 6)
|
||||||
@ -970,14 +969,14 @@ def tee(iterable, n=2):
|
|||||||
return list(gen(d) for d in deques)
|
return list(gen(d) for d in deques)
|
||||||
it = [1,2,3,4]
|
it = [1,2,3,4]
|
||||||
a, b = tee(it) #! cannot typecheck the program
|
a, b = tee(it) #! cannot typecheck the program
|
||||||
#! while realizing tee (arguments tee[List[int],int])
|
#! while realizing tee:0 (arguments tee:0[List[int],int])
|
||||||
|
|
||||||
#%% new_syntax,barebones
|
#%% new_syntax,barebones
|
||||||
def foo[T,U](x: type, y, z: Static[int] = 10):
|
def foo[T,U](x: type, y, z: Static[int] = 10):
|
||||||
print T.__class__, U.__class__, x.__class__, y.__class__, Int[z+1].__class__
|
print T.__class__, U.__class__, x.__class__, y.__class__, Int[z+1].__class__
|
||||||
return List[x]()
|
return List[x]()
|
||||||
print foo(T=int,U=str,...).__class__ #: foo[T1,x,z,int,str]
|
print foo(T=int,U=str,...).__class__ #: foo:0[T1,x,z,int,str]
|
||||||
print foo(T=int,U=str,z=5,x=bool,...).__class__ #: foo[T1,bool,5,int,str]
|
print foo(T=int,U=str,z=5,x=bool,...).__class__ #: foo:0[T1,bool,5,int,str]
|
||||||
print foo(float,3,T=int,U=str,z=5).__class__ #: List[float]
|
print foo(float,3,T=int,U=str,z=5).__class__ #: List[float]
|
||||||
foo(float,1,10,str,int) #: str int float int Int[11]
|
foo(float,1,10,str,int) #: str int float int Int[11]
|
||||||
|
|
||||||
@ -993,11 +992,11 @@ print Foo[5,int,float,6].__class__ #: Foo[5,int,float,6]
|
|||||||
print Foo(1.1, 10i32, [False], 10u66).__class__ #: Foo[66,bool,float,32]
|
print Foo(1.1, 10i32, [False], 10u66).__class__ #: Foo[66,bool,float,32]
|
||||||
|
|
||||||
|
|
||||||
def foo[N: Static[int]]():
|
def foo2[N: Static[int]]():
|
||||||
print Int[N].__class__, N
|
print Int[N].__class__, N
|
||||||
x: Static[int] = 5
|
x: Static[int] = 5
|
||||||
y: Static[int] = 105 - x * 2
|
y: Static[int] = 105 - x * 2
|
||||||
foo(y-x) #: Int[90] 90
|
foo2(y-x) #: Int[90] 90
|
||||||
|
|
||||||
if 1.1+2.2 > 0:
|
if 1.1+2.2 > 0:
|
||||||
x: Static[int] = 88
|
x: Static[int] = 88
|
||||||
|
Loading…
x
Reference in New Issue
Block a user