diff --git a/include/linalg.pyi b/include/linalg.pyi index ea3dff2d..5d46dbd9 100644 --- a/include/linalg.pyi +++ b/include/linalg.pyi @@ -96,6 +96,8 @@ class mat3x3: def transpose(self) -> mat3x3: ... def inverse(self) -> mat3x3: ... + def __invert__(self) -> mat3x3: ... + @staticmethod def zeros() -> mat3x3: ... @staticmethod diff --git a/include/pocketpy/expr.h b/include/pocketpy/expr.h index 7bb87a60..3f7c1a83 100644 --- a/include/pocketpy/expr.h +++ b/include/pocketpy/expr.h @@ -78,6 +78,13 @@ struct NameExpr: Expr{ bool emit_store(CodeEmitContext* ctx) override; }; +struct InvertExpr: Expr{ + Expr_ child; + InvertExpr(Expr_&& child): child(std::move(child)) {} + std::string str() const override { return "Invert()"; } + void emit(CodeEmitContext* ctx) override; +}; + struct StarredExpr: Expr{ int level; Expr_ child; diff --git a/include/pocketpy/lexer.h b/include/pocketpy/lexer.h index fc699efd..0f30588e 100644 --- a/include/pocketpy/lexer.h +++ b/include/pocketpy/lexer.h @@ -21,7 +21,7 @@ constexpr const char* kTokens[] = { /*****************************************/ ".", ",", ":", ";", "#", "(", ")", "[", "]", "{", "}", "**", "=", ">", "<", "...", "->", "?", "@", "==", "!=", ">=", "<=", - "++", "--", + "++", "--", "~", /** SPEC_BEGIN **/ "$goto", "$label", /** KW_BEGIN **/ @@ -92,7 +92,7 @@ enum Precedence { PREC_BITWISE_SHIFT, // << >> PREC_TERM, // + - PREC_FACTOR, // * / % // @ - PREC_UNARY, // - not + PREC_UNARY, // - not ~ PREC_EXPONENT, // ** PREC_CALL, // () PREC_SUBSCRIPT, // [] diff --git a/include/pocketpy/opcodes.h b/include/pocketpy/opcodes.h index c1ce7c72..20c8b28e 100644 --- a/include/pocketpy/opcodes.h +++ b/include/pocketpy/opcodes.h @@ -99,6 +99,7 @@ OPCODE(SET_ADD) OPCODE(UNARY_NEGATIVE) OPCODE(UNARY_NOT) OPCODE(UNARY_STAR) +OPCODE(UNARY_INVERT) /**************************/ OPCODE(GET_ITER) OPCODE(FOR_ITER) diff --git a/include/pocketpy/str.h b/include/pocketpy/str.h index 4a4b4ded..7a191011 100644 --- a/include/pocketpy/str.h +++ b/include/pocketpy/str.h @@ -281,6 +281,7 @@ const StrName __rshift__ = StrName::get("__rshift__"); const StrName __and__ = StrName::get("__and__"); const StrName __or__ = StrName::get("__or__"); const StrName __xor__ = StrName::get("__xor__"); +const StrName __invert__ = StrName::get("__invert__"); // indexer const StrName __getitem__ = StrName::get("__getitem__"); const StrName __setitem__ = StrName::get("__setitem__"); diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index 5f727a95..70700913 100644 --- a/include/pocketpy/vm.h +++ b/include/pocketpy/vm.h @@ -65,6 +65,7 @@ struct PyTypeInfo{ PyObject* (*m__json__)(VM* vm, PyObject*) = nullptr; PyObject* (*m__neg__)(VM* vm, PyObject*) = nullptr; PyObject* (*m__bool__)(VM* vm, PyObject*) = nullptr; + PyObject* (*m__invert__)(VM* vm, PyObject*) = nullptr; BinaryFuncC m__eq__ = nullptr; BinaryFuncC m__lt__ = nullptr; @@ -221,6 +222,7 @@ public: BIND_UNARY_SPECIAL(__json__) BIND_UNARY_SPECIAL(__neg__) BIND_UNARY_SPECIAL(__bool__) + BIND_UNARY_SPECIAL(__invert__) void bind__hash__(Type type, i64 (*f)(VM* vm, PyObject*)); void bind__len__(Type type, i64 (*f)(VM* vm, PyObject*)); diff --git a/src/ceval.cpp b/src/ceval.cpp index f8ad4a4d..35fbe982 100644 --- a/src/ceval.cpp +++ b/src/ceval.cpp @@ -566,6 +566,12 @@ __NEXT_STEP:; TARGET(UNARY_STAR) TOP() = VAR(StarWrapper(byte.arg, TOP())); DISPATCH(); + TARGET(UNARY_INVERT) + _ti = _inst_type_info(TOP()); + if(_ti->m__invert__) _0 = _ti->m__invert__(this, TOP()); + else _0 = call_method(TOP(), __invert__); + TOP() = _0; + DISPATCH(); /*****************************************/ TARGET(GET_ITER) TOP() = py_iter(TOP()); diff --git a/src/compiler.cpp b/src/compiler.cpp index aaccef68..323149cf 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -52,6 +52,7 @@ namespace pkpy{ rules[TK("+")] = { nullptr, METHOD(exprBinaryOp), PREC_TERM }; rules[TK("-")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_TERM }; rules[TK("*")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_FACTOR }; + rules[TK("~")] = { METHOD(exprUnaryOp), nullptr, PREC_UNARY }; rules[TK("/")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; rules[TK("//")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; rules[TK("**")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_EXPONENT }; @@ -241,6 +242,9 @@ namespace pkpy{ case TK("-"): ctx()->s_expr.push(make_expr(ctx()->s_expr.popx())); break; + case TK("~"): + ctx()->s_expr.push(make_expr(ctx()->s_expr.popx())); + break; case TK("*"): ctx()->s_expr.push(make_expr(1, ctx()->s_expr.popx())); break; diff --git a/src/expr.cpp b/src/expr.cpp index 952e66b9..3b4a5f1e 100644 --- a/src/expr.cpp +++ b/src/expr.cpp @@ -139,6 +139,10 @@ namespace pkpy{ return true; } + void InvertExpr::emit(CodeEmitContext* ctx) { + child->emit(ctx); + ctx->emit(OP_UNARY_INVERT, BC_NOARG, line); + } void StarredExpr::emit(CodeEmitContext* ctx) { child->emit(ctx); diff --git a/src/lexer.cpp b/src/lexer.cpp index d6e12020..ffbac892 100644 --- a/src/lexer.cpp +++ b/src/lexer.cpp @@ -286,6 +286,7 @@ namespace pkpy{ switch (c) { case '\'': case '"': eat_string(c, NORMAL_STRING); return true; case '#': skip_line_comment(); break; + case '~': add_token(TK("~")); return true; case '{': add_token(TK("{")); return true; case '}': add_token(TK("}")); return true; case ',': add_token(TK(",")); return true; diff --git a/src/linalg.cpp b/src/linalg.cpp index cadc4d05..1ff34bea 100644 --- a/src/linalg.cpp +++ b/src/linalg.cpp @@ -375,6 +375,14 @@ namespace pkpy{ return VAR_T(PyMat3x3, ret); }); + vm->bind__invert__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ + PyMat3x3& self = _CAST(PyMat3x3&, obj); + Mat3x3 ret; + bool ok = self.inverse(ret); + if(!ok) vm->ValueError("matrix is not invertible"); + return VAR_T(PyMat3x3, ret); + }); + vm->bind_func<0>(type, "zeros", [](VM* vm, ArgsView args){ PK_UNUSED(args); return VAR_T(PyMat3x3, Mat3x3::zeros()); diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index c055a2d8..68e4ef4b 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -343,6 +343,8 @@ void init_builtins(VM* _vm) { _vm->bind__hash__(_vm->tp_int, [](VM* vm, PyObject* obj) { return _CAST(i64, obj); }); + _vm->bind__invert__(_vm->tp_int, [](VM* vm, PyObject* obj) { return VAR(~_CAST(i64, obj)); }); + #define INT_BITWISE_OP(name, op) \ _vm->bind##name(_vm->tp_int, [](VM* vm, PyObject* lhs, PyObject* rhs) { \ return VAR(_CAST(i64, lhs) op CAST(i64, rhs)); \ diff --git a/tests/01_int.py b/tests/01_int.py index 0a6d3a48..824c2af8 100644 --- a/tests/01_int.py +++ b/tests/01_int.py @@ -58,4 +58,8 @@ assert 7**21 == 558545864083284007 assert 2**60 == 1152921504606846976 assert -2**60 == -1152921504606846976 assert 4**13 == 67108864 -assert (-4)**13 == -67108864 \ No newline at end of file +assert (-4)**13 == -67108864 + +assert ~3 == -4 +assert ~-3 == 2 +assert ~0 == -1 \ No newline at end of file