1
0
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:
Ibrahim Numanagić 2021-12-15 11:44:17 -08:00
parent a68e95fb2b
commit 3d6090322d
14 changed files with 224 additions and 131 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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'):

View File

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

View File

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