This commit is contained in:
blueloveTH 2023-06-15 12:27:29 +08:00
parent 9625134e32
commit f59f0c373e
11 changed files with 122 additions and 49 deletions

View File

@ -10,8 +10,20 @@ in 64 bit platforms, it is 62 bit.
For arbitrary sized integers, we provide a builtin `long` type, just like python2's `long`. For arbitrary sized integers, we provide a builtin `long` type, just like python2's `long`.
`long` is implemented via pure python in [_long.py](https://github.com/blueloveTH/pocketpy/blob/main/python/_long.py). `long` is implemented via pure python in [_long.py](https://github.com/blueloveTH/pocketpy/blob/main/python/_long.py).
### Create a long object
You can use `L` suffix to create a `long` literal from a decimal literal.
Also, you can use `long()` function to create a `long` object from a `int` object or a `str` object.
```python ```python
a = long(2) # use long() to create a long explicitly a = 1000L
b = long(1000)
c = long('1000')
assert a == b == c
```
```python
a = 2L # use `L` suffix to create a `long` object
print(a ** 1000) print(a ** 1000)
# 10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376L # 10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376L
``` ```

View File

@ -143,8 +143,9 @@ def ulong_repr(x: list) -> str:
return s return s
def ulong_fromstr(s: str): def ulong_fromstr(s: str):
res = [0] if s[-1] == 'L':
base = [1] s = s[:-1]
res, base = [0], [1]
if s[0] == '-': if s[0] == '-':
sign = -1 sign = -1
s = s[1:] s = s[1:]
@ -172,8 +173,8 @@ class long:
def __add__(self, other): def __add__(self, other):
if type(other) is int: if type(other) is int:
other = long(other) other = long(other)
else: elif type(other) is not long:
assert type(other) is long return NotImplemented
if self.sign == other.sign: if self.sign == other.sign:
return long((ulong_add(self.digits, other.digits), self.sign)) return long((ulong_add(self.digits, other.digits), self.sign))
else: else:
@ -191,21 +192,24 @@ class long:
def __sub__(self, other): def __sub__(self, other):
if type(other) is int: if type(other) is int:
other = long(other) other = long(other)
else: elif type(other) is not long:
assert type(other) is long return NotImplemented
if self.sign != other.sign: if self.sign != other.sign:
return long((ulong_add(self.digits, other.digits), self.sign)) return long((ulong_add(self.digits, other.digits), self.sign))
cmp = ulong_cmp(self.digits, other.digits)
if cmp == 0:
return long(0)
if cmp > 0:
return long((ulong_sub(self.digits, other.digits), self.sign))
else: else:
cmp = ulong_cmp(self.digits, other.digits) return long((ulong_sub(other.digits, self.digits), -other.sign))
if cmp == 0:
return long(0)
if cmp > 0:
return long((ulong_sub(self.digits, other.digits), self.sign))
else:
return long((ulong_sub(other.digits, self.digits), -other.sign))
def __rsub__(self, other): def __rsub__(self, other):
return self.__sub__(other) if type(other) is int:
other = long(other)
elif type(other) is not long:
return NotImplemented
return other.__sub__(self)
def __mul__(self, other): def __mul__(self, other):
if type(other) is int: if type(other) is int:
@ -218,7 +222,7 @@ class long:
ulong_mul(self.digits, other.digits), ulong_mul(self.digits, other.digits),
self.sign * other.sign self.sign * other.sign
)) ))
raise TypeError('unsupported operand type(s) for *') return NotImplemented
def __rmul__(self, other): def __rmul__(self, other):
return self.__mul__(other) return self.__mul__(other)

View File

@ -325,46 +325,59 @@ __NEXT_STEP:;
if(_ti->m##func){ \ if(_ti->m##func){ \
TOP() = VAR(_ti->m##func(this, _0, _1)); \ TOP() = VAR(_ti->m##func(this, _0, _1)); \
}else{ \ }else{ \
TOP() = call_method(_0, func, _1); \ PyObject* self; \
_2 = get_unbound_method(_0, func, &self, false); \
if(_2 != nullptr) TOP() = call_method(self, _2, _1); \
else TOP() = NotImplemented; \
}
#define BINARY_OP_RSPECIAL(op, func) \
if(TOP() == NotImplemented){ \
PyObject* self; \
_2 = get_unbound_method(_1, func, &self, false); \
if(_2 != nullptr) TOP() = call_method(self, _2, _0); \
else BinaryOptError(op); \
} }
TARGET(BINARY_TRUEDIV) TARGET(BINARY_TRUEDIV)
if(is_tagged(SECOND())){
f64 lhs = num_to_float(SECOND());
f64 rhs = num_to_float(TOP());
POP();
TOP() = VAR(lhs / rhs);
DISPATCH();
}
BINARY_OP_SPECIAL(__truediv__); BINARY_OP_SPECIAL(__truediv__);
if(TOP() == NotImplemented) BinaryOptError("/");
DISPATCH(); DISPATCH();
TARGET(BINARY_POW) TARGET(BINARY_POW)
BINARY_OP_SPECIAL(__pow__); BINARY_OP_SPECIAL(__pow__);
if(TOP() == NotImplemented) BinaryOptError("**");
DISPATCH(); DISPATCH();
TARGET(BINARY_ADD) TARGET(BINARY_ADD)
PREDICT_INT_OP(+); PREDICT_INT_OP(+);
BINARY_OP_SPECIAL(__add__); BINARY_OP_SPECIAL(__add__);
BINARY_OP_RSPECIAL("+", __radd__);
DISPATCH() DISPATCH()
TARGET(BINARY_SUB) TARGET(BINARY_SUB)
PREDICT_INT_OP(-); PREDICT_INT_OP(-);
BINARY_OP_SPECIAL(__sub__); BINARY_OP_SPECIAL(__sub__);
BINARY_OP_RSPECIAL("-", __rsub__);
DISPATCH() DISPATCH()
TARGET(BINARY_MUL) TARGET(BINARY_MUL)
BINARY_OP_SPECIAL(__mul__); BINARY_OP_SPECIAL(__mul__);
BINARY_OP_RSPECIAL("*", __rmul__);
DISPATCH() DISPATCH()
TARGET(BINARY_FLOORDIV) TARGET(BINARY_FLOORDIV)
PREDICT_INT_OP(/); PREDICT_INT_OP(/);
BINARY_OP_SPECIAL(__floordiv__); BINARY_OP_SPECIAL(__floordiv__);
if(TOP() == NotImplemented) BinaryOptError("//");
DISPATCH() DISPATCH()
TARGET(BINARY_MOD) TARGET(BINARY_MOD)
PREDICT_INT_OP(%); PREDICT_INT_OP(%);
BINARY_OP_SPECIAL(__mod__); BINARY_OP_SPECIAL(__mod__);
if(TOP() == NotImplemented) BinaryOptError("%");
DISPATCH() DISPATCH()
TARGET(COMPARE_LT) TARGET(COMPARE_LT)
BINARY_OP_SPECIAL(__lt__); BINARY_OP_SPECIAL(__lt__);
if(TOP() == NotImplemented) BinaryOptError("<");
DISPATCH() DISPATCH()
TARGET(COMPARE_LE) TARGET(COMPARE_LE)
BINARY_OP_SPECIAL(__le__); BINARY_OP_SPECIAL(__le__);
if(TOP() == NotImplemented) BinaryOptError("<=");
DISPATCH() DISPATCH()
TARGET(COMPARE_EQ) TARGET(COMPARE_EQ)
_1 = POPX(); _1 = POPX();
@ -378,32 +391,40 @@ __NEXT_STEP:;
DISPATCH() DISPATCH()
TARGET(COMPARE_GT) TARGET(COMPARE_GT)
BINARY_OP_SPECIAL(__gt__); BINARY_OP_SPECIAL(__gt__);
if(TOP() == NotImplemented) BinaryOptError(">");
DISPATCH() DISPATCH()
TARGET(COMPARE_GE) TARGET(COMPARE_GE)
BINARY_OP_SPECIAL(__ge__); BINARY_OP_SPECIAL(__ge__);
if(TOP() == NotImplemented) BinaryOptError(">=");
DISPATCH() DISPATCH()
TARGET(BITWISE_LSHIFT) TARGET(BITWISE_LSHIFT)
PREDICT_INT_OP(<<); PREDICT_INT_OP(<<);
BINARY_OP_SPECIAL(__lshift__); BINARY_OP_SPECIAL(__lshift__);
if(TOP() == NotImplemented) BinaryOptError("<<");
DISPATCH() DISPATCH()
TARGET(BITWISE_RSHIFT) TARGET(BITWISE_RSHIFT)
PREDICT_INT_OP(>>); PREDICT_INT_OP(>>);
BINARY_OP_SPECIAL(__rshift__); BINARY_OP_SPECIAL(__rshift__);
if(TOP() == NotImplemented) BinaryOptError(">>");
DISPATCH() DISPATCH()
TARGET(BITWISE_AND) TARGET(BITWISE_AND)
PREDICT_INT_OP(&); PREDICT_INT_OP(&);
BINARY_OP_SPECIAL(__and__); BINARY_OP_SPECIAL(__and__);
if(TOP() == NotImplemented) BinaryOptError("&");
DISPATCH() DISPATCH()
TARGET(BITWISE_OR) TARGET(BITWISE_OR)
PREDICT_INT_OP(|); PREDICT_INT_OP(|);
BINARY_OP_SPECIAL(__or__); BINARY_OP_SPECIAL(__or__);
if(TOP() == NotImplemented) BinaryOptError("|");
DISPATCH() DISPATCH()
TARGET(BITWISE_XOR) TARGET(BITWISE_XOR)
PREDICT_INT_OP(^); PREDICT_INT_OP(^);
BINARY_OP_SPECIAL(__xor__); BINARY_OP_SPECIAL(__xor__);
if(TOP() == NotImplemented) BinaryOptError("^");
DISPATCH() DISPATCH()
TARGET(BINARY_MATMUL) TARGET(BINARY_MATMUL)
BINARY_OP_SPECIAL(__matmul__); BINARY_OP_SPECIAL(__matmul__);
if(TOP() == NotImplemented) BinaryOptError("@");
DISPATCH(); DISPATCH();
#undef BINARY_OP_SPECIAL #undef BINARY_OP_SPECIAL

View File

@ -133,6 +133,10 @@ inline bool is_both_int(PyObject* a, PyObject* b) noexcept {
return is_int(a) && is_int(b); return is_int(a) && is_int(b);
} }
inline bool is_both_float(PyObject* a, PyObject* b) noexcept {
return is_float(a) && is_float(b);
}
// special singals, is_tagged() for them is true // special singals, is_tagged() for them is true
inline PyObject* const PY_NULL = (PyObject*)0b000011; // tagged null inline PyObject* const PY_NULL = (PyObject*)0b000011; // tagged null
inline PyObject* const PY_OP_CALL = (PyObject*)0b100011; inline PyObject* const PY_OP_CALL = (PyObject*)0b100011;

View File

@ -121,6 +121,7 @@ class Compiler {
rules[TK("@num")] = { METHOD(exprLiteral), NO_INFIX }; rules[TK("@num")] = { METHOD(exprLiteral), NO_INFIX };
rules[TK("@str")] = { METHOD(exprLiteral), NO_INFIX }; rules[TK("@str")] = { METHOD(exprLiteral), NO_INFIX };
rules[TK("@fstr")] = { METHOD(exprFString), NO_INFIX }; rules[TK("@fstr")] = { METHOD(exprFString), NO_INFIX };
rules[TK("@long")] = { METHOD(exprLong), NO_INFIX };
#undef METHOD #undef METHOD
#undef NO_INFIX #undef NO_INFIX
} }
@ -194,11 +195,14 @@ class Compiler {
return expr; return expr;
} }
void exprLiteral(){ void exprLiteral(){
ctx()->s_expr.push(make_expr<LiteralExpr>(prev().value)); ctx()->s_expr.push(make_expr<LiteralExpr>(prev().value));
} }
void exprLong(){
ctx()->s_expr.push(make_expr<LongExpr>(prev().str()));
}
void exprFString(){ void exprFString(){
ctx()->s_expr.push(make_expr<FStringExpr>(std::get<Str>(prev().value))); ctx()->s_expr.push(make_expr<FStringExpr>(std::get<Str>(prev().value)));
} }

View File

@ -259,6 +259,20 @@ struct Literal0Expr: Expr{
bool is_json_object() const override { return true; } bool is_json_object() const override { return true; }
}; };
struct LongExpr: Expr{
Str s;
LongExpr(const Str& s): s(s) {}
std::string str() const override { return s.str(); }
void emit(CodeEmitContext* ctx) override {
VM* vm = ctx->vm;
PyObject* long_type = vm->builtins->attr().try_get("long");
PK_ASSERT(long_type != nullptr);
PyObject* obj = vm->call(long_type, VAR(s));
ctx->emit(OP_LOAD_CONST, ctx->add_const(obj), line);
}
};
// @num, @str which needs to invoke OP_LOAD_CONST // @num, @str which needs to invoke OP_LOAD_CONST
struct LiteralExpr: Expr{ struct LiteralExpr: Expr{
TokenValue value; TokenValue value;

View File

@ -11,7 +11,7 @@ typedef uint8_t TokenIndex;
constexpr const char* kTokens[] = { constexpr const char* kTokens[] = {
"is not", "not in", "yield from", "is not", "not in", "yield from",
"@eof", "@eol", "@sof", "@eof", "@eol", "@sof",
"@id", "@num", "@str", "@fstr", "@id", "@num", "@str", "@fstr", "@long",
"@indent", "@dedent", "@indent", "@dedent",
/*****************************************/ /*****************************************/
"+", "+=", "-", "-=", // (INPLACE_OP - 1) can get '=' removed "+", "+=", "-", "-=", // (INPLACE_OP - 1) can get '=' removed
@ -342,29 +342,34 @@ struct Lexer {
} }
void eat_number() { void eat_number() {
static const std::regex pattern("^(0x)?[0-9a-fA-F]+(\\.[0-9]+)?"); static const std::regex pattern("^(0x)?[0-9a-fA-F]+(\\.[0-9]+)?(L)?");
std::smatch m; std::smatch m;
const char* i = token_start; const char* i = token_start;
while(*i != '\n' && *i != '\0') i++; while(*i != '\n' && *i != '\0') i++;
std::string s = std::string(token_start, i); std::string s = std::string(token_start, i);
try{ bool ok = std::regex_search(s, m, pattern);
if (std::regex_search(s, m, pattern)) { PK_ASSERT(ok);
// here is m.length()-1, since the first char was eaten by lex_token() // here is m.length()-1, since the first char was eaten by lex_token()
for(int j=0; j<m.length()-1; j++) eatchar(); for(int j=0; j<m.length()-1; j++) eatchar();
int base = 10; if(m[3].matched){
size_t size; add_token(TK("@long"));
if (m[1].matched) base = 16; return;
if (m[2].matched) { }
if(base == 16) SyntaxError("hex literal should not contain a dot");
add_token(TK("@num"), Number::stof(m[0], &size)); try{
} else { int base = 10;
add_token(TK("@num"), Number::stoi(m[0], &size, base)); size_t size;
} if (m[1].matched) base = 16;
if (size != m.length()) FATAL_ERROR(); if (m[2].matched) {
if(base == 16) SyntaxError("hex literal should not contain a dot");
add_token(TK("@num"), Number::stof(m[0], &size));
} else {
add_token(TK("@num"), Number::stoi(m[0], &size, base));
} }
PK_ASSERT(size == m.length());
}catch(std::exception& _){ }catch(std::exception& _){
SyntaxError("invalid number literal"); SyntaxError("invalid number literal");
} }

View File

@ -36,14 +36,14 @@ inline CodeObject_ VM::compile(Str source, Str filename, CompileMode mode, bool
inline void init_builtins(VM* _vm) { inline void init_builtins(VM* _vm) {
#define BIND_NUM_ARITH_OPT(name, op) \ #define BIND_NUM_ARITH_OPT(name, op) \
_vm->bind##name(_vm->tp_int, [](VM* vm, PyObject* lhs, PyObject* rhs) { \ _vm->bind##name(_vm->tp_int, [](VM* vm, PyObject* lhs, PyObject* rhs) { \
if(is_int(rhs)){ \ if(is_int(rhs)) return VAR(_CAST(i64, lhs) op _CAST(i64, rhs)); \
return VAR(_CAST(i64, lhs) op _CAST(i64, rhs)); \ if(is_float(rhs)) return VAR(_CAST(i64, lhs) op _CAST(f64, rhs)); \
}else{ \ return vm->NotImplemented; \
return VAR(_CAST(i64, lhs) op vm->num_to_float(rhs)); \
} \
}); \ }); \
_vm->bind##name(_vm->tp_float, [](VM* vm, PyObject* lhs, PyObject* rhs) { \ _vm->bind##name(_vm->tp_float, [](VM* vm, PyObject* lhs, PyObject* rhs) { \
return VAR(_CAST(f64, lhs) op vm->num_to_float(rhs)); \ if(is_float(rhs)) return VAR(_CAST(f64, lhs) op _CAST(f64, rhs)); \
if(is_int(rhs)) return VAR(_CAST(f64, lhs) op _CAST(i64, rhs)); \
return vm->NotImplemented; \
}); });
BIND_NUM_ARITH_OPT(__add__, +) BIND_NUM_ARITH_OPT(__add__, +)

View File

@ -426,8 +426,11 @@ const StrName __ge__ = StrName::get("__ge__");
const StrName __contains__ = StrName::get("__contains__"); const StrName __contains__ = StrName::get("__contains__");
// binary operators // binary operators
const StrName __add__ = StrName::get("__add__"); const StrName __add__ = StrName::get("__add__");
const StrName __radd__ = StrName::get("__radd__");
const StrName __sub__ = StrName::get("__sub__"); const StrName __sub__ = StrName::get("__sub__");
const StrName __rsub__ = StrName::get("__rsub__");
const StrName __mul__ = StrName::get("__mul__"); const StrName __mul__ = StrName::get("__mul__");
const StrName __rmul__ = StrName::get("__rmul__");
const StrName __truediv__ = StrName::get("__truediv__"); const StrName __truediv__ = StrName::get("__truediv__");
const StrName __floordiv__ = StrName::get("__floordiv__"); const StrName __floordiv__ = StrName::get("__floordiv__");
const StrName __mod__ = StrName::get("__mod__"); const StrName __mod__ = StrName::get("__mod__");

View File

@ -512,6 +512,7 @@ public:
void ValueError(const Str& msg){ _error("ValueError", msg); } void ValueError(const Str& msg){ _error("ValueError", msg); }
void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); } void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); }
void KeyError(PyObject* obj){ _error("KeyError", OBJ_GET(Str, py_repr(obj))); } void KeyError(PyObject* obj){ _error("KeyError", OBJ_GET(Str, py_repr(obj))); }
void BinaryOptError(const char* op) { TypeError(fmt("unsupported operand type(s) for ", op)); }
void AttributeError(PyObject* obj, StrName name){ void AttributeError(PyObject* obj, StrName name){
// OBJ_NAME calls getattr, which may lead to a infinite recursion // OBJ_NAME calls getattr, which may lead to a infinite recursion
@ -1148,6 +1149,7 @@ inline void VM::init_builtin_types(){
builtins->attr().set("dict", _t(tp_dict)); builtins->attr().set("dict", _t(tp_dict));
builtins->attr().set("property", _t(tp_property)); builtins->attr().set("property", _t(tp_property));
builtins->attr().set("StopIteration", StopIteration); builtins->attr().set("StopIteration", StopIteration);
builtins->attr().set("NotImplemented", NotImplemented);
builtins->attr().set("slice", _t(tp_slice)); builtins->attr().set("slice", _t(tp_slice));
post_init(); post_init();

View File

@ -1,4 +1,4 @@
assert long(123) == long('123') == 123 assert long(123) == long('123') == 123L == 123
a = long(2) a = long(2)
assert a ** 0 == 1 assert a ** 0 == 1
@ -9,4 +9,8 @@ assert a - 1 == 1
assert a * 2 == 4 assert a * 2 == 4
assert a // 2 == 1 assert a // 2 == 1
assert -a == -2 assert -a == -2
assert 1 + a == 3L
assert 1 - a == -1L
assert 2 * a == 4L