Commit 0b7b8d55 authored by Travis Hance's avatar Travis Hance

add truediv support

parent ccb7cff9
......@@ -1037,9 +1037,12 @@ public:
if (op_type == AST_TYPE::Mod) {
v = emitter.createCall2(info.exc_info, g.funcs.mod_float_float, var->getValue(),
converted_right->getValue()).getInstruction();
} else if (op_type == AST_TYPE::Div || op_type == AST_TYPE::FloorDiv) {
} else if (op_type == AST_TYPE::Div || op_type == AST_TYPE::TrueDiv) {
v = emitter.createCall2(info.exc_info, g.funcs.div_float_float, var->getValue(),
converted_right->getValue()).getInstruction();
} else if (op_type == AST_TYPE::FloorDiv) {
v = emitter.createCall2(info.exc_info, g.funcs.floordiv_float_float, var->getValue(),
converted_right->getValue()).getInstruction();
} else if (op_type == AST_TYPE::Pow) {
v = emitter.createCall2(info.exc_info, g.funcs.pow_float_float, var->getValue(),
converted_right->getValue()).getInstruction();
......
......@@ -16,6 +16,21 @@
namespace pyston {
struct FutureOption {
int optional_version_hex;
int mandatory_version_hex;
int ff_mask;
};
const std::map<std::string, FutureOption> future_options
= { { "absolute_import", { version_hex(2, 5, 0), version_hex(3, 0, 0), FF_ABSOLUTE_IMPORT } },
{ "division", { version_hex(2, 2, 0), version_hex(3, 0, 0), FF_DIVISION } },
{ "generators", { version_hex(2, 2, 0), version_hex(3, 0, 0), FF_GENERATOR } },
{ "unicode_literals", { version_hex(2, 6, 0), version_hex(3, 0, 0), FF_UNICODE_LITERALS } },
{ "print_functions", { version_hex(2, 6, 0), version_hex(3, 0, 0), FF_PRINT_FUNCTIONS } },
{ "nested_scopes", { version_hex(2, 1, 0), version_hex(2, 2, 0), FF_NESTED_SCOPES } },
{ "with_statement", { version_hex(2, 5, 0), version_hex(3, 6, 0), FF_WITH_STATEMENT } } };
// Helper function:
void raiseSyntaxError(const char* file, AST* node_at, const char* msg, ...) {
va_list ap;
......@@ -105,7 +120,7 @@ FutureFlags getFutureFlags(AST_Module* m, const char* file) {
raiseFutureImportErrorNotFound(file, alias, option_name.c_str());
} else {
const FutureOption& fo = iter->second;
if (PYTHON_VERSION_HEX >= fo.mandatory_version_hex) {
if (PYTHON_VERSION_HEX >= fo.optional_version_hex) {
ff |= fo.ff_mask;
} else {
raiseFutureImportErrorNotFound(file, alias, option_name.c_str());
......
......@@ -31,23 +31,8 @@ namespace pyston {
#define FF_NESTED_SCOPES 0x20
#define FF_WITH_STATEMENT 0x40
struct FutureOption {
int optional_version_hex;
int mandatory_version_hex;
int ff_mask;
};
typedef int FutureFlags;
const std::map<std::string, FutureOption> future_options
= { { "absolute_import", { version_hex(2, 5, 0), version_hex(3, 0, 0), FF_ABSOLUTE_IMPORT } },
{ "division", { version_hex(2, 2, 0), version_hex(3, 0, 0), FF_DIVISION } },
{ "generators", { version_hex(2, 2, 0), version_hex(3, 0, 0), FF_GENERATOR } },
{ "unicode_literals", { version_hex(2, 6, 0), version_hex(3, 0, 0), FF_UNICODE_LITERALS } },
{ "print_functions", { version_hex(2, 6, 0), version_hex(3, 0, 0), FF_PRINT_FUNCTIONS } },
{ "nested_scopes", { version_hex(2, 1, 0), version_hex(2, 2, 0), FF_NESTED_SCOPES } },
{ "with_statement", { version_hex(2, 5, 0), version_hex(3, 6, 0), FF_WITH_STATEMENT } } };
// Loop through import statements to find __future__ imports throwing errors for
// bad __future__ imports. Returns the futures that are turned on. This is used
// for irgeneration; the parser still has to handle some futures on its own,
......
......@@ -237,7 +237,7 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
Timer _t("for compileModule()");
FutureFlags ff = getFutureFlags(m, bm->fn.c_str());
bm->future_flags = getFutureFlags(m, bm->fn.c_str());
ScopingAnalysis* scoping = runScopingAnalysis(m);
......
......@@ -405,6 +405,10 @@ private:
assert(left);
assert(right);
if (type == AST_TYPE::Div && (irstate->getSourceInfo()->parent_module->future_flags & FF_DIVISION)) {
type = AST_TYPE::TrueDiv;
}
return left->binexp(emitter, getOpInfoForNode(node, exc_info), right, type, exp_type);
}
......
......@@ -235,6 +235,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(raise3);
GET(div_float_float);
GET(floordiv_float_float);
GET(mod_float_float);
GET(pow_float_float);
}
......
......@@ -49,7 +49,7 @@ struct GlobalFuncs {
llvm::Value* __cxa_begin_catch, *__cxa_end_catch;
llvm::Value* raise0, *raise3;
llvm::Value* div_float_float, *mod_float_float, *pow_float_float;
llvm::Value* div_float_float, *floordiv_float_float, *mod_float_float, *pow_float_float;
};
}
......
......@@ -22,8 +22,6 @@
#include "core/cfg.h"
#define FUTURE_DIVISION 0
namespace pyston {
llvm::StringRef getOpSymbol(int op_type) {
......@@ -37,6 +35,7 @@ llvm::StringRef getOpSymbol(int op_type) {
case AST_TYPE::BitXor:
return "^";
case AST_TYPE::Div:
case AST_TYPE::TrueDiv:
return "/";
case AST_TYPE::Eq:
return "==";
......@@ -110,10 +109,9 @@ const std::string& getOpName(int op_type) {
case AST_TYPE::BitXor:
return strBitXor;
case AST_TYPE::Div:
if (FUTURE_DIVISION)
return strTrueDiv;
else
return strDiv;
return strDiv;
case AST_TYPE::TrueDiv:
return strTrueDiv;
case AST_TYPE::Eq:
return strEq;
case AST_TYPE::FloorDiv:
......
......@@ -125,6 +125,7 @@ enum AST_TYPE {
Invoke = 204,
LangPrimitive = 205,
Unreachable = 206,
TrueDiv = 207,
};
};
......
......@@ -52,6 +52,11 @@ extern "C" double div_float_float(double lhs, double rhs) {
return lhs / rhs;
}
extern "C" double floordiv_float_float(double lhs, double rhs) {
raiseDivZeroExcIfZero(rhs);
return floor(lhs / rhs);
}
extern "C" Box* floatAddFloat(BoxedFloat* lhs, BoxedFloat* rhs) {
assert(lhs->cls == float_cls);
assert(rhs->cls == float_cls);
......@@ -100,6 +105,17 @@ extern "C" Box* floatDiv(BoxedFloat* lhs, Box* rhs) {
}
}
extern "C" Box* floatTruediv(BoxedFloat* lhs, Box* rhs) {
assert(lhs->cls == float_cls);
if (rhs->cls == int_cls) {
return floatDivInt(lhs, static_cast<BoxedInt*>(rhs));
} else if (rhs->cls == float_cls) {
return floatDivFloat(lhs, static_cast<BoxedFloat*>(rhs));
} else {
return NotImplemented;
}
}
extern "C" Box* floatRDivFloat(BoxedFloat* lhs, BoxedFloat* rhs) {
assert(lhs->cls == float_cls);
assert(rhs->cls == float_cls);
......@@ -563,6 +579,7 @@ void setupFloat() {
_addFunc("__div__", BOXED_FLOAT, (void*)floatDivFloat, (void*)floatDivInt, (void*)floatDiv);
_addFunc("__rdiv__", BOXED_FLOAT, (void*)floatRDivFloat, (void*)floatRDivInt, (void*)floatRDiv);
float_cls->giveAttr("__floordiv__", new BoxedFunction(boxRTFunction((void*)floatFloorDiv, UNKNOWN, 2)));
_addFunc("__truediv__", BOXED_FLOAT, (void*)floatDivFloat, (void*)floatDivInt, (void*)floatTruediv);
_addFunc("__eq__", BOXED_BOOL, (void*)floatEqFloat, (void*)floatEqInt, (void*)floatEq);
_addFunc("__ge__", BOXED_BOOL, (void*)floatGeFloat, (void*)floatGeInt, (void*)floatGe);
......
......@@ -19,6 +19,7 @@ namespace pyston {
extern "C" double mod_float_float(double lhs, double rhs);
extern "C" double div_float_float(double lhs, double rhs);
extern "C" double floordiv_float_float(double lhs, double rhs);
extern "C" double pow_float_float(double lhs, double rhs);
class BoxedFloat;
......
......@@ -110,6 +110,7 @@ void force() {
FORCE(pow_i64_i64);
FORCE(div_float_float);
FORCE(floordiv_float_float);
FORCE(mod_float_float);
FORCE(pow_float_float);
......
......@@ -317,6 +317,37 @@ extern "C" Box* intFloordiv(BoxedInt* lhs, Box* rhs) {
}
}
extern "C" Box* intTruedivInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(lhs->cls == int_cls);
assert(rhs->cls == int_cls);
if (rhs->n == 0) {
raiseExcHelper(ZeroDivisionError, "division by zero");
}
return boxFloat(lhs->n / (float)rhs->n);
}
extern "C" Box* intTruedivFloat(BoxedInt* lhs, BoxedFloat* rhs) {
assert(lhs->cls == int_cls);
assert(rhs->cls == float_cls);
if (rhs->d == 0) {
raiseExcHelper(ZeroDivisionError, "division by zero");
}
return boxFloat(lhs->n / rhs->d);
}
extern "C" Box* intTruediv(BoxedInt* lhs, Box* rhs) {
assert(lhs->cls == int_cls);
if (rhs->cls == int_cls) {
return intTruedivInt(lhs, static_cast<BoxedInt*>(rhs));
} else if (rhs->cls == float_cls) {
return intTruedivFloat(lhs, static_cast<BoxedFloat*>(rhs));
} else {
return NotImplemented;
}
}
extern "C" Box* intEqInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(lhs->cls == int_cls);
assert(rhs->cls == int_cls);
......@@ -685,6 +716,7 @@ void setupInt() {
_addFuncIntFloatUnknown("__sub__", (void*)intSubInt, (void*)intSubFloat, (void*)intSub);
_addFuncIntFloatUnknown("__div__", (void*)intDivInt, (void*)intDivFloat, (void*)intDiv);
_addFuncIntFloatUnknown("__floordiv__", (void*)intFloordivInt, (void*)intFloordivFloat, (void*)intFloordiv);
_addFuncIntFloatUnknown("__truediv__", (void*)intTruedivInt, (void*)intDivFloat, (void*)intTruediv);
_addFuncIntFloatUnknown("__mul__", (void*)intMulInt, (void*)intMulFloat, (void*)intMul);
_addFuncIntUnknown("__mod__", BOXED_INT, (void*)intModInt, (void*)intMod);
_addFuncIntFloatUnknown("__pow__", (void*)intPowInt, (void*)intPowFloat, (void*)intPow);
......
......@@ -20,6 +20,7 @@
#include "Python.h"
#include "structmember.h"
#include "codegen/irgen/future.h"
#include "core/threading.h"
#include "core/types.h"
#include "gc/gc_alloc.h"
......@@ -307,6 +308,7 @@ class BoxedModule : public Box {
public:
HCAttrs attrs;
std::string fn; // for traceback purposes; not the same as __file__
FutureFlags future_flags;
BoxedModule(const std::string& name, const std::string& fn);
std::string name();
......
# allow-warning
# The __future__ module has an old-style class, so we allow warnings for now
"docstring"
from __future__ import division
def test(a, b):
print a, '/', b, '=', a / b
t = a
t /= b
print a, '/', b, '=', t
print a, '//', b, '=', a // b
t = a
t //= b
print a, '//', b, '=', t
test(3, 2)
test(3, 2.0)
test(3.0, 2)
test(3.0, 2.0)
......@@ -106,6 +106,7 @@ def run_test(fn, check_stats, run_memcheck):
statchecks = []
jit_args = ["-csrq"] + EXTRA_JIT_ARGS
expected = "success"
allow_warning = False
for l in open(fn):
l = l.strip()
if not l:
......@@ -125,6 +126,8 @@ def run_test(fn, check_stats, run_memcheck):
skip = eval(skip_if)
if skip:
return r + " (skipped due to 'skip-if: %s')" % skip_if[:30]
elif l.startswith("# allow-warning"):
allow_warning = True
assert expected in ("success", "fail", "statfail"), expected
......@@ -143,6 +146,9 @@ def run_test(fn, check_stats, run_memcheck):
elapsed = time.time() - start
stats = {}
if allow_warning:
out_lines = [l for l in out.split('\n') if not l.startswith("Warning: ")]
out = "\n".join(out_lines)
if code == 0 and not TEST_PYPY:
assert out.count("Stats:") == 1
out, stats_str = out.split("Stats:")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment