mirror of
https://github.com/exaloop/codon.git
synced 2025-06-03 15:03:52 +08:00
Fix various bugs and update tests
This commit is contained in:
parent
a68e95fb2b
commit
3d6090322d
@ -55,9 +55,8 @@ types::FuncTypePtr Cache::findFunction(const std::string &name) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
types::FuncTypePtr
|
||||
Cache::findMethod(types::ClassType *typ, const std::string &member,
|
||||
const std::vector<std::pair<std::string, types::TypePtr>> &args) {
|
||||
types::FuncTypePtr Cache::findMethod(types::ClassType *typ, const std::string &member,
|
||||
const std::vector<types::TypePtr> &args) {
|
||||
auto e = std::make_shared<IdExpr>(typ->name);
|
||||
e->type = typ->getClass();
|
||||
seqassert(e->type, "not a class");
|
||||
|
@ -223,9 +223,8 @@ public:
|
||||
types::FuncTypePtr findFunction(const std::string &name) const;
|
||||
/// Find the class method in a given class type that best matches the given arguments.
|
||||
/// Returns an _uninstantiated_ type.
|
||||
types::FuncTypePtr
|
||||
findMethod(types::ClassType *typ, const std::string &member,
|
||||
const std::vector<std::pair<std::string, types::TypePtr>> &args);
|
||||
types::FuncTypePtr findMethod(types::ClassType *typ, const std::string &member,
|
||||
const std::vector<types::TypePtr> &args);
|
||||
|
||||
/// Given a class type and the matching generic vector, instantiate the type and
|
||||
/// realize it.
|
||||
|
@ -64,7 +64,8 @@ std::string SimplifyContext::generateCanonicalName(const std::string &name,
|
||||
bool includeBase,
|
||||
bool zeroId) const {
|
||||
std::string newName = name;
|
||||
if (includeBase && name.find('.') == std::string::npos) {
|
||||
bool alreadyGenerated = name.find('.') != std::string::npos;
|
||||
if (includeBase && !alreadyGenerated) {
|
||||
std::string base = getBase();
|
||||
if (base.empty()) {
|
||||
base = moduleName.status == ImportFile::STDLIB ? "std." : "";
|
||||
@ -75,9 +76,10 @@ std::string SimplifyContext::generateCanonicalName(const std::string &name,
|
||||
newName = (base.empty() ? "" : (base + ".")) + newName;
|
||||
}
|
||||
auto num = cache->identifierCount[newName]++;
|
||||
newName = num || zeroId ? format("{}.{}", newName, num) : newName;
|
||||
// if (newName != name)
|
||||
// cache->identifierCount[newName]++;
|
||||
if (num)
|
||||
newName = format("{}.{}", newName, num);
|
||||
if (name != newName && !zeroId)
|
||||
cache->identifierCount[newName]++;
|
||||
cache->reverseIdentifierLookup[newName] = name;
|
||||
return newName;
|
||||
}
|
||||
|
@ -617,7 +617,7 @@ void SimplifyVisitor::visit(DotExpr *expr) {
|
||||
auto s = join(chain, ".", importEnd, i + 1);
|
||||
val = fctx->find(s);
|
||||
// Make sure that we access only global imported variables.
|
||||
if (val && (importName.empty() || val->isGlobal())) {
|
||||
if (val && (importName.empty() || val->isType() || val->isGlobal())) {
|
||||
itemName = val->canonicalName;
|
||||
itemEnd = i + 1;
|
||||
if (!importName.empty())
|
||||
|
@ -289,9 +289,10 @@ private:
|
||||
/// Also takes care of the Optional arguments.
|
||||
/// If multiple equally good methods are found, return the first one.
|
||||
/// Return nullptr if no methods were found.
|
||||
types::FuncTypePtr
|
||||
findBestMethod(const Expr *expr, const std::string &member,
|
||||
const std::vector<std::pair<std::string, types::TypePtr>> &args);
|
||||
types::FuncTypePtr findBestMethod(const Expr *expr, const std::string &member,
|
||||
const std::vector<types::TypePtr> &args);
|
||||
types::FuncTypePtr findBestMethod(const Expr *expr, const std::string &member,
|
||||
const std::vector<CallExpr::Arg> &args);
|
||||
|
||||
private:
|
||||
types::TypePtr unify(types::TypePtr &a, const types::TypePtr &b,
|
||||
|
@ -140,7 +140,7 @@ TypeContext::findMethod(const std::string &typeName, const std::string &method)
|
||||
auto m = cache->classes.find(typeName);
|
||||
if (m != cache->classes.end()) {
|
||||
auto t = m->second.methods.find(method);
|
||||
if (t != m->second.methods.end()) {
|
||||
if (t != m->second.methods.end() && !t->second.empty()) {
|
||||
seqassert(!t->second.empty() && endswith(t->second[0].name, ".dispatch"),
|
||||
"first method '{}' is not dispatch", t->second[0].name);
|
||||
std::unordered_set<std::string> signatureLoci;
|
||||
|
@ -683,8 +683,8 @@ ExprPtr TypecheckVisitor::transformBinary(BinaryExpr *expr, bool isAtomic,
|
||||
if (isAtomic) {
|
||||
auto ptrlt =
|
||||
ctx->instantiateGeneric(expr->lexpr.get(), ctx->findInternal("Ptr"), {lt});
|
||||
method = findBestMethod(expr->lexpr.get(), format("__atomic_{}__", magic),
|
||||
{{"", ptrlt}, {"", rt}});
|
||||
method =
|
||||
findBestMethod(expr->lexpr.get(), format("__atomic_{}__", magic), {ptrlt, rt});
|
||||
if (method) {
|
||||
expr->lexpr = N<PtrExpr>(expr->lexpr);
|
||||
if (noReturn)
|
||||
@ -693,19 +693,16 @@ ExprPtr TypecheckVisitor::transformBinary(BinaryExpr *expr, bool isAtomic,
|
||||
}
|
||||
// Check if lt.__iop__(lt, rt) exists.
|
||||
if (!method && expr->inPlace) {
|
||||
method = findBestMethod(expr->lexpr.get(), format("__i{}__", magic),
|
||||
{{"", lt}, {"", rt}});
|
||||
method = findBestMethod(expr->lexpr.get(), format("__i{}__", magic), {lt, rt});
|
||||
if (method && noReturn)
|
||||
*noReturn = true;
|
||||
}
|
||||
// Check if lt.__op__(lt, rt) exists.
|
||||
if (!method)
|
||||
method = findBestMethod(expr->lexpr.get(), format("__{}__", magic),
|
||||
{{"", lt}, {"", rt}});
|
||||
method = findBestMethod(expr->lexpr.get(), format("__{}__", magic), {lt, rt});
|
||||
// Check if rt.__rop__(rt, lt) exists.
|
||||
if (!method) {
|
||||
method = findBestMethod(expr->rexpr.get(), format("__r{}__", magic),
|
||||
{{"", rt}, {"", lt}});
|
||||
method = findBestMethod(expr->rexpr.get(), format("__r{}__", magic), {rt, lt});
|
||||
if (method)
|
||||
swap(expr->lexpr, expr->rexpr);
|
||||
}
|
||||
@ -868,12 +865,15 @@ ExprPtr TypecheckVisitor::transformDot(DotExpr *expr,
|
||||
// If it exists, return a simple IdExpr with that method's name.
|
||||
// Append a "self" variable to the front if needed.
|
||||
if (args) {
|
||||
std::vector<std::pair<std::string, TypePtr>> argTypes;
|
||||
std::vector<CallExpr::Arg> argTypes;
|
||||
bool isType = expr->expr->isType();
|
||||
if (!isType)
|
||||
argTypes.emplace_back(make_pair("", typ)); // self variable
|
||||
if (!isType) {
|
||||
ExprPtr expr = N<IdExpr>("self");
|
||||
expr->setType(typ);
|
||||
argTypes.emplace_back(CallExpr::Arg{"", expr});
|
||||
}
|
||||
for (const auto &a : *args)
|
||||
argTypes.emplace_back(make_pair(a.name, a.value->getType()));
|
||||
argTypes.emplace_back(a);
|
||||
if (auto bestMethod = findBestMethod(expr->expr.get(), expr->member, argTypes)) {
|
||||
ExprPtr e = N<IdExpr>(bestMethod->ast->name);
|
||||
auto t = ctx->instantiate(expr, bestMethod, typ.get());
|
||||
@ -891,7 +891,7 @@ ExprPtr TypecheckVisitor::transformDot(DotExpr *expr,
|
||||
// No method was found, print a nice error message.
|
||||
std::vector<std::string> nice;
|
||||
for (auto &t : argTypes)
|
||||
nice.emplace_back(format("{} = {}", t.first, t.second->toString()));
|
||||
nice.emplace_back(format("{} = {}", t.name, t.value->type->toString()));
|
||||
error("cannot find a method '{}' in {} with arguments {}", expr->member,
|
||||
typ->toString(), join(nice, ", "));
|
||||
}
|
||||
@ -901,17 +901,17 @@ ExprPtr TypecheckVisitor::transformDot(DotExpr *expr,
|
||||
auto oldType = expr->getType() ? expr->getType()->getClass() : nullptr;
|
||||
if (methods.size() > 1 && oldType && oldType->getFunc()) {
|
||||
// If old type is already a function, use its arguments to pick the best call.
|
||||
std::vector<std::pair<std::string, TypePtr>> methodArgs;
|
||||
std::vector<TypePtr> methodArgs;
|
||||
if (!expr->expr->isType()) // self argument
|
||||
methodArgs.emplace_back(make_pair("", typ));
|
||||
methodArgs.emplace_back(typ);
|
||||
for (auto i = 1; i < oldType->generics.size(); i++)
|
||||
methodArgs.emplace_back(make_pair("", oldType->generics[i].type));
|
||||
methodArgs.emplace_back(oldType->generics[i].type);
|
||||
bestMethod = findBestMethod(expr->expr.get(), expr->member, methodArgs);
|
||||
if (!bestMethod) {
|
||||
// Print a nice error message.
|
||||
std::vector<std::string> nice;
|
||||
for (auto &t : methodArgs)
|
||||
nice.emplace_back(format("{} = {}", t.first, t.second->toString()));
|
||||
nice.emplace_back(format("{}", t->toString()));
|
||||
error("cannot find a method '{}' in {} with arguments {}", expr->member,
|
||||
typ->toString(), join(nice, ", "));
|
||||
}
|
||||
@ -1360,12 +1360,12 @@ std::pair<bool, ExprPtr> TypecheckVisitor::transformSpecialCall(CallExpr *expr)
|
||||
if (!typ || !expr->args[1].value->staticValue.evaluated)
|
||||
return {true, nullptr};
|
||||
auto member = expr->args[1].value->staticValue.getString();
|
||||
std::vector<std::pair<std::string, TypePtr>> args{{std::string(), typ}};
|
||||
std::vector<TypePtr> args{typ};
|
||||
for (int i = 2; i < expr->args.size(); i++) {
|
||||
expr->args[i].value = transformType(expr->args[i].value);
|
||||
if (!expr->args[i].value->getType()->getClass())
|
||||
return {true, nullptr};
|
||||
args.push_back({std::string(), expr->args[i].value->getType()});
|
||||
args.push_back(expr->args[i].value->getType());
|
||||
}
|
||||
bool exists = !ctx->findMethod(typ->getClass()->name, member).empty() ||
|
||||
ctx->findMember(typ->getClass()->name, member);
|
||||
@ -1613,9 +1613,20 @@ ExprPtr TypecheckVisitor::partializeFunction(ExprPtr expr) {
|
||||
return call;
|
||||
}
|
||||
|
||||
types::FuncTypePtr TypecheckVisitor::findBestMethod(
|
||||
const Expr *expr, const std::string &member,
|
||||
const std::vector<std::pair<std::string, types::TypePtr>> &args) {
|
||||
types::FuncTypePtr
|
||||
TypecheckVisitor::findBestMethod(const Expr *expr, const std::string &member,
|
||||
const std::vector<types::TypePtr> &args) {
|
||||
std::vector<CallExpr::Arg> callArgs;
|
||||
for (auto &a : args) {
|
||||
callArgs.push_back({"", std::make_shared<NoneExpr>()}); // dummy expression
|
||||
callArgs.back().value->setType(a);
|
||||
}
|
||||
return findBestMethod(expr, member, callArgs);
|
||||
}
|
||||
|
||||
types::FuncTypePtr
|
||||
TypecheckVisitor::findBestMethod(const Expr *expr, const std::string &member,
|
||||
const std::vector<CallExpr::Arg> &args) {
|
||||
auto typ = expr->getType()->getClass();
|
||||
seqassert(typ, "not a class");
|
||||
|
||||
@ -1624,13 +1635,8 @@ types::FuncTypePtr TypecheckVisitor::findBestMethod(
|
||||
for (int mi = 0; mi < methods.size(); mi++) {
|
||||
auto m = ctx->instantiate(expr, methods[mi], typ.get(), false)->getFunc();
|
||||
std::vector<types::TypePtr> reordered;
|
||||
std::vector<CallExpr::Arg> callArgs;
|
||||
for (auto &a : args) {
|
||||
callArgs.push_back({a.first, std::make_shared<NoneExpr>()}); // dummy expression
|
||||
callArgs.back().value->setType(a.second);
|
||||
}
|
||||
auto score = ctx->reorderNamedArgs(
|
||||
m.get(), callArgs,
|
||||
m.get(), args,
|
||||
[&](int s, int k, const std::vector<std::vector<int>> &slots, bool _) {
|
||||
for (int si = 0; si < slots.size(); si++) {
|
||||
if (m->ast->args[si].generic) {
|
||||
@ -1639,13 +1645,12 @@ types::FuncTypePtr TypecheckVisitor::findBestMethod(
|
||||
// Ignore *args, *kwargs and default arguments
|
||||
reordered.emplace_back(nullptr);
|
||||
} else {
|
||||
reordered.emplace_back(args[slots[si][0]].second);
|
||||
reordered.emplace_back(args[slots[si][0]].value->type);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
[](const std::string &) { return -1; });
|
||||
|
||||
for (int ai = 0, mi = 1, gi = 0; score != -1 && ai < reordered.size(); ai++) {
|
||||
auto expectTyp =
|
||||
m->ast->args[ai].generic ? m->generics[gi++].type : m->args[mi++];
|
||||
|
@ -155,7 +155,7 @@ void TypecheckVisitor::visit(UpdateStmt *stmt) {
|
||||
auto rhsTyp = c->args[1].value->getType()->getClass();
|
||||
if (auto method = findBestMethod(stmt->lhs.get(),
|
||||
format("__atomic_{}__", c->expr->getId()->value),
|
||||
{{"", ptrTyp}, {"", rhsTyp}})) {
|
||||
{ptrTyp, rhsTyp})) {
|
||||
resultStmt = transform(N<ExprStmt>(N<CallExpr>(
|
||||
N<IdExpr>(method->ast->name), N<PtrExpr>(stmt->lhs), c->args[1].value)));
|
||||
return;
|
||||
@ -168,8 +168,8 @@ void TypecheckVisitor::visit(UpdateStmt *stmt) {
|
||||
if (stmt->isAtomic && lhsClass && rhsClass) {
|
||||
auto ptrType =
|
||||
ctx->instantiateGeneric(stmt->lhs.get(), ctx->findInternal("Ptr"), {lhsClass});
|
||||
if (auto m = findBestMethod(stmt->lhs.get(), "__atomic_xchg__",
|
||||
{{"", ptrType}, {"", rhsClass}})) {
|
||||
if (auto m =
|
||||
findBestMethod(stmt->lhs.get(), "__atomic_xchg__", {ptrType, rhsClass})) {
|
||||
resultStmt = transform(N<ExprStmt>(
|
||||
N<CallExpr>(N<IdExpr>(m->ast->name), N<PtrExpr>(stmt->lhs), stmt->rhs)));
|
||||
return;
|
||||
|
@ -22,12 +22,12 @@ translateGenerics(std::vector<types::Generic> &generics) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, codon::ast::types::TypePtr>>
|
||||
std::vector<codon::ast::types::TypePtr>
|
||||
generateDummyNames(std::vector<types::Type *> &types) {
|
||||
std::vector<std::pair<std::string, codon::ast::types::TypePtr>> ret;
|
||||
std::vector<codon::ast::types::TypePtr> ret;
|
||||
for (auto *t : types) {
|
||||
seqassert(t->getAstType(), "{} must have an ast type", *t);
|
||||
ret.emplace_back("", t->getAstType());
|
||||
ret.emplace_back(t->getAstType());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -3,14 +3,14 @@ class complex:
|
||||
real: float
|
||||
imag: float
|
||||
|
||||
def __new__():
|
||||
return complex(0.0, 0.0)
|
||||
def __new__() -> complex:
|
||||
return (0.0, 0.0)
|
||||
|
||||
def __new__(other):
|
||||
return other.__complex__()
|
||||
|
||||
def __new__(real, imag):
|
||||
return complex(float(real), float(imag))
|
||||
def __new__(real, imag) -> complex:
|
||||
return (float(real), float(imag))
|
||||
|
||||
def __complex__(self):
|
||||
return self
|
||||
|
@ -558,7 +558,7 @@ print f.foo() #: F
|
||||
class Foo:
|
||||
def foo(self):
|
||||
return 'F'
|
||||
Foo.foo(1) #! cannot unify int and Foo
|
||||
Foo.foo(1) #! cannot find a method 'foo' in Foo with arguments = int
|
||||
|
||||
#%% function_nested,barebones
|
||||
def foo(v):
|
||||
@ -941,12 +941,12 @@ print FooBarBaz[str]().foo() #: foo 0
|
||||
print FooBarBaz[float]().bar() #: bar 0/float
|
||||
print FooBarBaz[str]().baz() #: baz! foo 0 bar /str
|
||||
|
||||
#%% inherit_class_2,barebones
|
||||
#%% inherit_class_err_2,barebones
|
||||
class defdict(Dict[str,float]):
|
||||
def __init__(self, d: Dict[str, float]):
|
||||
self.__init__(d.items())
|
||||
z = defdict()
|
||||
z[1.1] #! cannot unify float and str
|
||||
z[1.1] #! cannot find a method '__getitem__' in defdict with arguments = defdict, = float
|
||||
|
||||
#%% inherit_tuple,barebones
|
||||
class Foo:
|
||||
|
@ -306,7 +306,7 @@ class Foo:
|
||||
print 'foo'
|
||||
def method(self, a):
|
||||
print a
|
||||
Foo().clsmethod() #! too many arguments for Foo.clsmethod (expected maximum 0, got 1)
|
||||
Foo().clsmethod() #! cannot find a method 'clsmethod' in Foo with arguments = Foo
|
||||
|
||||
#%% call,barebones
|
||||
def foo(a, b, c='hi'):
|
||||
|
@ -298,7 +298,7 @@ print h(list(map(lambda i: i-1, map(lambda i: i+2, range(5)))))
|
||||
#%% func_unify_error,barebones
|
||||
def foo(x:int):
|
||||
print x
|
||||
z = 1 & foo #! cannot unify foo[...] and int
|
||||
z = 1 & foo #! cannot find magic 'and' in int
|
||||
|
||||
#%% void_error,barebones
|
||||
def foo():
|
||||
@ -515,7 +515,7 @@ class A[T]:
|
||||
def foo[W](t: V, u: V, v: V, w: W):
|
||||
return (t, u, v, w)
|
||||
|
||||
print A.B.C[bool].foo(W=str, ...).__class__ #: A.B.C.foo[bool,bool,bool,str,str]
|
||||
print A.B.C[bool].foo(W=str, ...).__class__ #: A.B.C.foo.2[bool,bool,bool,str,str]
|
||||
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')
|
||||
@ -533,7 +533,8 @@ class A[T]:
|
||||
c: V
|
||||
def foo[W](t: V, u: V, v: V, w: W):
|
||||
return (t, u, v, w)
|
||||
print A.B.C[str].foo(1,1,1,True) #! cannot unify int and str
|
||||
|
||||
print A.B.C[str].foo(1,1,1,True) #! cannot find a method 'foo' in A.B.C[str] with arguments = int, = int, = int, = bool
|
||||
|
||||
#%% nested_deep_class_error_2,barebones
|
||||
class A[T]:
|
||||
@ -744,8 +745,8 @@ class X[T]:
|
||||
return (x+x, y+y)
|
||||
y = X[X[int]]()
|
||||
print y.__class__ #: X[X[int]]
|
||||
print X[float].foo(U=int, ...).__class__ #: X.foo[X[float],float,int,int]
|
||||
# print y.foo[float].__class__
|
||||
print X[float].foo(U=int, ...).__class__ #: X.foo.2[X[float],float,int,int]
|
||||
# print y.foo.1[float].__class__
|
||||
print X[int]().foo(1, 's') #: (2, 'ss')
|
||||
|
||||
#%% class_partial_access,barebones
|
||||
@ -753,7 +754,7 @@ class X[T]:
|
||||
def foo[U](self, x, y: U):
|
||||
return (x+x, y+y)
|
||||
y = X[X[int]]()
|
||||
print y.foo(U=float,...).__class__ #: X.foo[X[X[int]],...,...]
|
||||
print y.foo(U=float,...).__class__ #: X.foo.2[X[X[int]],...,...]
|
||||
print y.foo(1, 2.2, float) #: (2, 4.4)
|
||||
|
||||
#%% forward,barebones
|
||||
|
@ -10,60 +10,69 @@ class I:
|
||||
def __float__(self: int) -> float:
|
||||
%tmp = sitofp i64 %self to double
|
||||
ret double %tmp
|
||||
|
||||
@llvm
|
||||
def __bool__(self: int) -> bool:
|
||||
%0 = icmp ne i64 %self, 0
|
||||
%1 = zext i1 %0 to i8
|
||||
ret i8 %1
|
||||
|
||||
def __pos__(self: int) -> int:
|
||||
return self
|
||||
|
||||
def __neg__(self: int) -> int:
|
||||
return I.__sub__(0, self)
|
||||
|
||||
@llvm
|
||||
def __abs__(self: int) -> int:
|
||||
%0 = icmp sgt i64 %self, 0
|
||||
%1 = sub i64 0, %self
|
||||
%2 = select i1 %0, i64 %self, i64 %1
|
||||
ret i64 %2
|
||||
|
||||
@llvm
|
||||
def __lshift__(self: int, other: int) -> int:
|
||||
%0 = shl i64 %self, %other
|
||||
ret i64 %0
|
||||
|
||||
@llvm
|
||||
def __rshift__(self: int, other: int) -> int:
|
||||
%0 = ashr i64 %self, %other
|
||||
ret i64 %0
|
||||
@llvm
|
||||
def __add__(self: int, b: int) -> int:
|
||||
%tmp = add i64 %self, %b
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __add__(self: int, other: float) -> float:
|
||||
%0 = sitofp i64 %self to double
|
||||
%1 = fadd double %0, %other
|
||||
ret double %1
|
||||
|
||||
@llvm
|
||||
def __sub__(self: int, b: int) -> int:
|
||||
%tmp = sub i64 %self, %b
|
||||
def __add__(self: int, b: int) -> int:
|
||||
%tmp = add i64 %self, %b
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __sub__(self: int, other: float) -> float:
|
||||
%0 = sitofp i64 %self to double
|
||||
%1 = fsub double %0, %other
|
||||
ret double %1
|
||||
|
||||
@llvm
|
||||
def __mul__(self: int, b: int) -> int:
|
||||
%tmp = mul i64 %self, %b
|
||||
def __sub__(self: int, b: int) -> int:
|
||||
%tmp = sub i64 %self, %b
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __mul__(self: int, other: float) -> float:
|
||||
%0 = sitofp i64 %self to double
|
||||
%1 = fmul double %0, %other
|
||||
ret double %1
|
||||
|
||||
@llvm
|
||||
def __floordiv__(self: int, b: int) -> int:
|
||||
%tmp = sdiv i64 %self, %b
|
||||
def __mul__(self: int, b: int) -> int:
|
||||
%tmp = mul i64 %self, %b
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __floordiv__(self: int, other: float) -> float:
|
||||
declare double @llvm.floor.f64(double)
|
||||
@ -71,141 +80,177 @@ class I:
|
||||
%1 = fdiv double %0, %other
|
||||
%2 = call double @llvm.floor.f64(double %1)
|
||||
ret double %2
|
||||
|
||||
@llvm
|
||||
def __floordiv__(self: int, b: int) -> int:
|
||||
%tmp = sdiv i64 %self, %b
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __truediv__(self: int, other: float) -> float:
|
||||
%0 = sitofp i64 %self to double
|
||||
%1 = fdiv double %0, %other
|
||||
ret double %1
|
||||
|
||||
@llvm
|
||||
def __truediv__(self: int, other: int) -> float:
|
||||
%0 = sitofp i64 %self to double
|
||||
%1 = sitofp i64 %other to double
|
||||
%2 = fdiv double %0, %1
|
||||
ret double %2
|
||||
@llvm
|
||||
def __truediv__(self: int, other: float) -> float:
|
||||
%0 = sitofp i64 %self to double
|
||||
%1 = fdiv double %0, %other
|
||||
ret double %1
|
||||
@llvm
|
||||
def __mod__(a: int, b: int) -> int:
|
||||
%tmp = srem i64 %a, %b
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __mod__(self: int, other: float) -> float:
|
||||
%0 = sitofp i64 %self to double
|
||||
%1 = frem double %0, %other
|
||||
ret double %1
|
||||
|
||||
@llvm
|
||||
def __mod__(a: int, b: int) -> int:
|
||||
%tmp = srem i64 %a, %b
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __invert__(a: int) -> int:
|
||||
%tmp = xor i64 %a, -1
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __and__(a: int, b: int) -> int:
|
||||
%tmp = and i64 %a, %b
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __or__(a: int, b: int) -> int:
|
||||
%tmp = or i64 %a, %b
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __xor__(a: int, b: int) -> int:
|
||||
%tmp = xor i64 %a, %b
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __shr__(a: int, b: int) -> int:
|
||||
%tmp = ashr i64 %a, %b
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __shl__(a: int, b: int) -> int:
|
||||
%tmp = shl i64 %a, %b
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __bitreverse__(a: int) -> int:
|
||||
declare i64 @llvm.bitreverse.i64(i64 %a)
|
||||
%tmp = call i64 @llvm.bitreverse.i64(i64 %a)
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __bswap__(a: int) -> int:
|
||||
declare i64 @llvm.bswap.i64(i64 %a)
|
||||
%tmp = call i64 @llvm.bswap.i64(i64 %a)
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __ctpop__(a: int) -> int:
|
||||
declare i64 @llvm.ctpop.i64(i64 %a)
|
||||
%tmp = call i64 @llvm.ctpop.i64(i64 %a)
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __ctlz__(a: int) -> int:
|
||||
declare i64 @llvm.ctlz.i64(i64 %a, i1 %is_zero_undef)
|
||||
%tmp = call i64 @llvm.ctlz.i64(i64 %a, i1 false)
|
||||
ret i64 %tmp
|
||||
|
||||
@llvm
|
||||
def __cttz__(a: int) -> int:
|
||||
declare i64 @llvm.cttz.i64(i64 %a, i1 %is_zero_undef)
|
||||
%tmp = call i64 @llvm.cttz.i64(i64 %a, i1 false)
|
||||
ret i64 %tmp
|
||||
@llvm
|
||||
def __eq__(a: int, b: int) -> bool:
|
||||
%tmp = icmp eq i64 %a, %b
|
||||
%res = zext i1 %tmp to i8
|
||||
ret i8 %res
|
||||
|
||||
@llvm
|
||||
def __eq__(self: int, b: float) -> bool:
|
||||
%0 = sitofp i64 %self to double
|
||||
%1 = fcmp oeq double %0, %b
|
||||
%2 = zext i1 %1 to i8
|
||||
ret i8 %2
|
||||
|
||||
@llvm
|
||||
def __ne__(a: int, b: int) -> bool:
|
||||
%tmp = icmp ne i64 %a, %b
|
||||
def __eq__(a: int, b: int) -> bool:
|
||||
%tmp = icmp eq i64 %a, %b
|
||||
%res = zext i1 %tmp to i8
|
||||
ret i8 %res
|
||||
|
||||
@llvm
|
||||
def __ne__(self: int, b: float) -> bool:
|
||||
%0 = sitofp i64 %self to double
|
||||
%1 = fcmp one double %0, %b
|
||||
%2 = zext i1 %1 to i8
|
||||
ret i8 %2
|
||||
|
||||
@llvm
|
||||
def __lt__(a: int, b: int) -> bool:
|
||||
%tmp = icmp slt i64 %a, %b
|
||||
def __ne__(a: int, b: int) -> bool:
|
||||
%tmp = icmp ne i64 %a, %b
|
||||
%res = zext i1 %tmp to i8
|
||||
ret i8 %res
|
||||
|
||||
@llvm
|
||||
def __lt__(self: int, b: float) -> bool:
|
||||
%0 = sitofp i64 %self to double
|
||||
%1 = fcmp olt double %0, %b
|
||||
%2 = zext i1 %1 to i8
|
||||
ret i8 %2
|
||||
|
||||
@llvm
|
||||
def __gt__(a: int, b: int) -> bool:
|
||||
%tmp = icmp sgt i64 %a, %b
|
||||
def __lt__(a: int, b: int) -> bool:
|
||||
%tmp = icmp slt i64 %a, %b
|
||||
%res = zext i1 %tmp to i8
|
||||
ret i8 %res
|
||||
|
||||
@llvm
|
||||
def __gt__(self: int, b: float) -> bool:
|
||||
%0 = sitofp i64 %self to double
|
||||
%1 = fcmp ogt double %0, %b
|
||||
%2 = zext i1 %1 to i8
|
||||
ret i8 %2
|
||||
|
||||
@llvm
|
||||
def __le__(a: int, b: int) -> bool:
|
||||
%tmp = icmp sle i64 %a, %b
|
||||
def __gt__(a: int, b: int) -> bool:
|
||||
%tmp = icmp sgt i64 %a, %b
|
||||
%res = zext i1 %tmp to i8
|
||||
ret i8 %res
|
||||
|
||||
@llvm
|
||||
def __le__(self: int, b: float) -> bool:
|
||||
%0 = sitofp i64 %self to double
|
||||
%1 = fcmp ole double %0, %b
|
||||
%2 = zext i1 %1 to i8
|
||||
ret i8 %2
|
||||
|
||||
@llvm
|
||||
def __ge__(a: int, b: int) -> bool:
|
||||
%tmp = icmp sge i64 %a, %b
|
||||
def __le__(a: int, b: int) -> bool:
|
||||
%tmp = icmp sle i64 %a, %b
|
||||
%res = zext i1 %tmp to i8
|
||||
ret i8 %res
|
||||
|
||||
@llvm
|
||||
def __ge__(self: int, b: float) -> bool:
|
||||
%0 = sitofp i64 %self to double
|
||||
%1 = fcmp oge double %0, %b
|
||||
%2 = zext i1 %1 to i8
|
||||
ret i8 %2
|
||||
|
||||
@llvm
|
||||
def __ge__(a: int, b: int) -> bool:
|
||||
%tmp = icmp sge i64 %a, %b
|
||||
%res = zext i1 %tmp to i8
|
||||
ret i8 %res
|
||||
|
||||
def __pow__(self: int, exp: float):
|
||||
return float(self) ** exp
|
||||
|
||||
def __pow__(self: int, exp: int):
|
||||
if exp < 0:
|
||||
return 0
|
||||
@ -218,8 +263,6 @@ class I:
|
||||
break
|
||||
self *= self
|
||||
return result
|
||||
def __pow__(self: int, exp: float):
|
||||
return float(self) ** exp
|
||||
|
||||
@extend
|
||||
class int:
|
||||
@ -227,158 +270,197 @@ class int:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return self
|
||||
|
||||
def __float__(self) -> float:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__float__(self)
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__bool__(self)
|
||||
|
||||
def __pos__(self) -> int:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return self
|
||||
|
||||
def __neg__(self) -> int:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__neg__(self)
|
||||
|
||||
def __lshift__(self, other: int) -> int:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__lshift__(self, other)
|
||||
|
||||
def __rshift__(self, other: int) -> int:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__rshift__(self, other)
|
||||
def __add__(self, b: int) -> int:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__add__(self, b)
|
||||
|
||||
def __add__(self, other: float) -> float:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__add__(self, other)
|
||||
def __sub__(self, b: int) -> int:
|
||||
|
||||
def __add__(self, b: int) -> int:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__sub__(self, b)
|
||||
return I.__add__(self, b)
|
||||
|
||||
def __sub__(self, other: float) -> float:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__sub__(self, other)
|
||||
def __mul__(self, b: int) -> int:
|
||||
|
||||
def __sub__(self, b: int) -> int:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__mul__(self, b)
|
||||
return I.__sub__(self, b)
|
||||
|
||||
def __mul__(self, other: float) -> float:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__mul__(self, other)
|
||||
def __floordiv__(self, b: int) -> int:
|
||||
|
||||
def __mul__(self, b: int) -> int:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__floordiv__(self, b)
|
||||
return I.__mul__(self, b)
|
||||
|
||||
def __floordiv__(self, other: float) -> float:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__floordiv__(self, other)
|
||||
def __truediv__(self, other: int) -> float:
|
||||
|
||||
def __floordiv__(self, b: int) -> int:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__truediv__(self, other)
|
||||
return I.__floordiv__(self, b)
|
||||
|
||||
def __truediv__(self, other: float) -> float:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__truediv__(self, other)
|
||||
def __mod__(self, b: int) -> int:
|
||||
|
||||
def __truediv__(self, other: int) -> float:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__mod__(self, b)
|
||||
return I.__truediv__(self, other)
|
||||
|
||||
def __mod__(self, other: float) -> float:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__mod__(self, other)
|
||||
|
||||
def __mod__(self, b: int) -> int:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__mod__(self, b)
|
||||
|
||||
def __invert__(self) -> int:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__invert__(self)
|
||||
|
||||
def __and__(self, b: int) -> int:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__and__(self, b)
|
||||
|
||||
def __or__(self, b: int) -> int:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__or__(self, b)
|
||||
|
||||
def __xor__(self, b: int) -> int:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__xor__(self, b)
|
||||
def __eq__(self, b: int) -> bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__eq__(self, b)
|
||||
|
||||
def __eq__(self, b: float) -> bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__eq__(self, b)
|
||||
def __ne__(self, b: int) -> bool:
|
||||
|
||||
def __eq__(self, b: int) -> bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__ne__(self, b)
|
||||
return I.__eq__(self, b)
|
||||
|
||||
def __ne__(self, b: float) -> bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__ne__(self, b)
|
||||
def __lt__(self, b: int) -> bool:
|
||||
|
||||
def __ne__(self, b: int) -> bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__lt__(self, b)
|
||||
return I.__ne__(self, b)
|
||||
|
||||
def __lt__(self, b: float) -> bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__lt__(self, b)
|
||||
def __gt__(self, b: int) -> bool:
|
||||
|
||||
def __lt__(self, b: int) -> bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__gt__(self, b)
|
||||
return I.__lt__(self, b)
|
||||
|
||||
def __gt__(self, b: float) -> bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__gt__(self, b)
|
||||
def __le__(self, b: int) -> bool:
|
||||
|
||||
def __gt__(self, b: int) -> bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__le__(self, b)
|
||||
return I.__gt__(self, b)
|
||||
|
||||
def __le__(self, b: float) -> bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__le__(self, b)
|
||||
def __ge__(self, b: int) -> bool:
|
||||
|
||||
def __le__(self, b: int) -> bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__ge__(self, b)
|
||||
return I.__le__(self, b)
|
||||
|
||||
def __ge__(self, b: float) -> bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__ge__(self, b)
|
||||
def __pow__(self, exp: int):
|
||||
|
||||
def __ge__(self, b: int) -> bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__pow__(self, exp)
|
||||
return I.__ge__(self, b)
|
||||
|
||||
def __pow__(self, exp: float):
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__pow__(self, exp)
|
||||
|
||||
def __pow__(self, exp: int):
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return I.__pow__(self, exp)
|
||||
|
||||
|
||||
class F:
|
||||
@llvm
|
||||
def __int__(self: float) -> int:
|
||||
%0 = fptosi double %self to i64
|
||||
ret i64 %0
|
||||
|
||||
def __float__(self: float):
|
||||
return self
|
||||
|
||||
@llvm
|
||||
def __bool__(self: float) -> bool:
|
||||
%0 = fcmp one double %self, 0.000000e+00
|
||||
@ -391,10 +473,12 @@ class float:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return F.__int__(self)
|
||||
|
||||
def __float__(self) -> float:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return self
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
@ -406,10 +490,12 @@ class bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return 1 if self else 0
|
||||
|
||||
def __float__(self) -> float:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
return 1. if self else 0.
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
global OP_COUNT
|
||||
OP_COUNT = inc(OP_COUNT)
|
||||
|
Loading…
x
Reference in New Issue
Block a user