This commit is contained in:
blueloveTH 2023-05-11 18:37:39 +08:00
parent df2f7bb58e
commit d872ae7596
9 changed files with 395 additions and 12 deletions

View File

@ -9,7 +9,7 @@ pipeline = [
["common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "lexer.h"], ["common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "lexer.h"],
["obj.h", "codeobject.h", "frame.h"], ["obj.h", "codeobject.h", "frame.h"],
["gc.h", "vm.h", "ceval.h", "expr.h", "compiler.h", "repl.h"], ["gc.h", "vm.h", "ceval.h", "expr.h", "compiler.h", "repl.h"],
["_generated.h", "iter.h", "base64.h", "cffi.h", "requests.h", "io.h", "pocketpy.h"] ["_generated.h", "iter.h", "base64.h", "cffi.h", "mat3x3.h", "requests.h", "io.h", "pocketpy.h"]
] ]
copied = set() copied = set()

View File

@ -325,6 +325,12 @@ __NEXT_STEP:;
DISPATCH() DISPATCH()
#undef INT_BINARY_OP #undef INT_BINARY_OP
TARGET(BINARY_MATMUL)
_1 = POPX();
_0 = TOP();
TOP() = call_method(_0, __matmul__, _1);
DISPATCH();
TARGET(IS_OP) TARGET(IS_OP)
_1 = POPX(); // rhs _1 = POPX(); // rhs
_0 = TOP(); // lhs _0 = TOP(); // lhs

View File

@ -104,6 +104,7 @@ class Compiler {
rules[TK("&")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_AND }; rules[TK("&")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_AND };
rules[TK("|")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_OR }; rules[TK("|")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_OR };
rules[TK("^")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_XOR }; rules[TK("^")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_XOR };
rules[TK("@")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR };
rules[TK("if")] = { nullptr, METHOD(exprTernary), PREC_TERNARY }; rules[TK("if")] = { nullptr, METHOD(exprTernary), PREC_TERNARY };
rules[TK(",")] = { nullptr, METHOD(exprTuple), PREC_TUPLE }; rules[TK(",")] = { nullptr, METHOD(exprTuple), PREC_TUPLE };
rules[TK("not in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; rules[TK("not in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST };

View File

@ -702,6 +702,8 @@ struct BinaryExpr: Expr{
case TK("&"): ctx->emit(OP_BITWISE_AND, BC_NOARG, line); break; case TK("&"): ctx->emit(OP_BITWISE_AND, BC_NOARG, line); break;
case TK("|"): ctx->emit(OP_BITWISE_OR, BC_NOARG, line); break; case TK("|"): ctx->emit(OP_BITWISE_OR, BC_NOARG, line); break;
case TK("^"): ctx->emit(OP_BITWISE_XOR, BC_NOARG, line); break; case TK("^"): ctx->emit(OP_BITWISE_XOR, BC_NOARG, line); break;
case TK("@"): ctx->emit(OP_BINARY_MATMUL, BC_NOARG, line); break;
default: FATAL_ERROR(); default: FATAL_ERROR();
} }
} }

View File

@ -86,7 +86,7 @@ enum Precedence {
PREC_BITWISE_AND, // & PREC_BITWISE_AND, // &
PREC_BITWISE_SHIFT, // << >> PREC_BITWISE_SHIFT, // << >>
PREC_TERM, // + - PREC_TERM, // + -
PREC_FACTOR, // * / % // PREC_FACTOR, // * / % // @
PREC_UNARY, // - not PREC_UNARY, // - not
PREC_EXPONENT, // ** PREC_EXPONENT, // **
PREC_CALL, // () PREC_CALL, // ()

377
src/mat3x3.h Normal file
View File

@ -0,0 +1,377 @@
#pragma once
#include <cmath>
#include "cffi.h"
namespace pkpy{
struct Mat3x3{
static constexpr float kEpsilon = 1e-5f;
union {
struct {
float _11, _12, _13;
float _21, _22, _23;
float _31, _32, _33;
};
float m[3][3];
float v[9];
};
void set_zeros(){
for (int i=0; i<9; ++i) v[i] = 0.0f;
}
void set_ones(){
for (int i=0; i<9; ++i) v[i] = 1.0f;
}
void set_identity(){
_11 = 1.0f; _12 = 0.0f; _13 = 0.0f;
_21 = 0.0f; _22 = 1.0f; _23 = 0.0f;
_31 = 0.0f; _32 = 0.0f; _33 = 1.0f;
}
void add_(const Mat3x3& other){ for (int i=0; i<9; ++i) v[i] += other.v[i]; }
void sub_(const Mat3x3& other){ for (int i=0; i<9; ++i) v[i] -= other.v[i]; }
void mul_(float s){ for (int i=0; i<9; ++i) v[i] *= s; }
void div_(float s){ for (int i=0; i<9; ++i) v[i] /= s; }
Mat3x3 add(const Mat3x3& other) const{ Mat3x3 ret(*this); ret.add_(other); return ret; }
Mat3x3 sub(const Mat3x3& other) const{ Mat3x3 ret(*this); ret.sub_(other); return ret; }
Mat3x3 mul(float s) const{ Mat3x3 ret(*this); ret.mul_(s); return ret; }
Mat3x3 div(float s) const{ Mat3x3 ret(*this); ret.div_(s); return ret; }
void matmul(const Mat3x3& other, Mat3x3& ret) const{
ret._11 = _11 * other._11 + _12 * other._21 + _13 * other._31;
ret._12 = _11 * other._12 + _12 * other._22 + _13 * other._32;
ret._13 = _11 * other._13 + _12 * other._23 + _13 * other._33;
ret._21 = _21 * other._11 + _22 * other._21 + _23 * other._31;
ret._22 = _21 * other._12 + _22 * other._22 + _23 * other._32;
ret._23 = _21 * other._13 + _22 * other._23 + _23 * other._33;
ret._31 = _31 * other._11 + _32 * other._21 + _33 * other._31;
ret._32 = _31 * other._12 + _32 * other._22 + _33 * other._32;
ret._33 = _31 * other._13 + _32 * other._23 + _33 * other._33;
}
Mat3x3 matmul(const Mat3x3& other) const{
Mat3x3 ret;
matmul(other, ret);
return ret;
}
bool operator==(const Mat3x3& other) const{
for (int i=0; i<9; ++i){
if (v[i] != other.v[i]) return false;
}
return true;
}
bool operator!=(const Mat3x3& other) const{
for (int i=0; i<9; ++i){
if (v[i] != other.v[i]) return true;
}
return false;
}
float determinant() const{
return _11 * _22 * _33 + _12 * _23 * _31 + _13 * _21 * _32
- _11 * _23 * _32 - _12 * _21 * _33 - _13 * _22 * _31;
}
Mat3x3 transpose() const{
Mat3x3 ret;
ret._11 = _11; ret._12 = _21; ret._13 = _31;
ret._21 = _12; ret._22 = _22; ret._23 = _32;
ret._31 = _13; ret._32 = _23; ret._33 = _33;
return ret;
}
bool inverse(Mat3x3& ret) const{
float det = determinant();
if (fabsf(det) < kEpsilon) return false;
float inv_det = 1.0f / det;
ret._11 = (_22 * _33 - _23 * _32) * inv_det;
ret._12 = (_13 * _32 - _12 * _33) * inv_det;
ret._13 = (_12 * _23 - _13 * _22) * inv_det;
ret._21 = (_23 * _31 - _21 * _33) * inv_det;
ret._22 = (_11 * _33 - _13 * _31) * inv_det;
ret._23 = (_13 * _21 - _11 * _23) * inv_det;
ret._31 = (_21 * _32 - _22 * _31) * inv_det;
ret._32 = (_12 * _31 - _11 * _32) * inv_det;
ret._33 = (_11 * _22 - _12 * _21) * inv_det;
return true;
}
bool is_identity() const{
return _11 == 1.0f && _12 == 0.0f && _13 == 0.0f
&& _21 == 0.0f && _22 == 1.0f && _23 == 0.0f
&& _31 == 0.0f && _32 == 0.0f && _33 == 1.0f;
}
/*************** affine transform (no bindings) ***************/
bool is_affine() const{
float det = _11 * _22 - _12 * _21;
if(fabsf(det) < kEpsilon) return false;
return _31 == 0.0f && _32 == 0.0f && _33 == 1.0f;
}
void set_translate(float x, float y){
_11 = 1.0f; _12 = 0.0f; _13 = x;
_21 = 0.0f; _22 = 1.0f; _23 = y;
_31 = 0.0f; _32 = 0.0f; _33 = 1.0f;
}
void set_rotate(float radian){
float c = cosf(radian);
float s = sinf(radian);
_11 = c; _12 = -s; _13 = 0.0f;
_21 = s; _22 = c; _23 = 0.0f;
_31 = 0.0f; _32 = 0.0f; _33 = 1.0f;
}
void set_scale(float sx, float sy){
_11 = sx; _12 = 0.0f; _13 = 0.0f;
_21 = 0.0f; _22 = sy; _23 = 0.0f;
_31 = 0.0f; _32 = 0.0f; _33 = 1.0f;
}
void set_trs(float x, float y, float radian, float sx, float sy){
float c = cosf(radian);
float s = sinf(radian);
_11 = sx * c; _12 = -sy * s; _13 = x;
_21 = sx * s; _22 = sy * c; _23 = y;
_31 = 0.0f; _32 = 0.0f; _33 = 1.0f;
}
void inverse_affine(Mat3x3& ret) const{
float det = _11 * _22 - _12 * _21;
float inv_det = 1.0f / det;
ret._11 = _22 * inv_det;
ret._12 = -_12 * inv_det;
ret._13 = (_12 * _23 - _13 * _22) * inv_det;
ret._21 = -_21 * inv_det;
ret._22 = _11 * inv_det;
ret._23 = (_13 * _21 - _11 * _23) * inv_det;
ret._31 = 0.0f;
ret._32 = 0.0f;
ret._33 = 1.0f;
}
void matmul_affine(const Mat3x3& other, Mat3x3& ret) const{
ret._11 = _11 * other._11 + _12 * other._21;
ret._12 = _11 * other._12 + _12 * other._22;
ret._13 = _11 * other._13 + _12 * other._23 + _13;
ret._21 = _21 * other._11 + _22 * other._21;
ret._22 = _21 * other._12 + _22 * other._22;
ret._23 = _21 * other._13 + _22 * other._23 + _23;
ret._31 = 0.0f;
ret._32 = 0.0f;
ret._33 = 1.0f;
}
Mat3x3 matmul_affine(const Mat3x3& other) const{
Mat3x3 ret;
matmul_affine(other, ret);
return ret;
}
float x() const { return _13; }
float y() const { return _23; }
float rotation() const { return atan2f(_21, _11); }
float scale_x() const { return sqrtf(_11 * _11 + _21 * _21); }
float scale_y() const { return sqrtf(_12 * _12 + _22 * _22); }
void transform_point(float& x, float& y) const {
float tx = x;
float ty = y;
x = _11 * tx + _12 * ty + _13;
y = _21 * tx + _22 * ty + _23;
}
void transform_vector(float& x, float& y) const {
float tx = x;
float ty = y;
x = _11 * tx + _12 * ty;
y = _21 * tx + _22 * ty;
}
void set_ortho(float left, float right, float bottom, float top){
_11 = 2.0f / (right - left); _12 = 0.0f; _13 = -(right + left) / (right - left);
_21 = 0.0f; _22 = 2.0f / (top - bottom); _23 = -(top + bottom) / (top - bottom);
_31 = 0.0f; _32 = 0.0f; _33 = 1.0f;
}
};
struct PyMat3x3: Mat3x3{
PY_CLASS(PyMat3x3, builtins, mat3x3)
PyMat3x3(): Mat3x3(){}
PyMat3x3(const Mat3x3& other): Mat3x3(other){}
PyMat3x3(const PyMat3x3& other): Mat3x3(other){}
static void _register(VM* vm, PyObject* mod, PyObject* type){
vm->bind_constructor<-1>(type, [](VM* vm, ArgsView args){
if(args.size() == 1+0) return VAR_T(PyMat3x3);
if(args.size() == 1+1){
List& a = CAST(List&, args[1]);
if(a.size() != 3) vm->ValueError("Mat3x3.__new__ takes 3x3 list");
Mat3x3 mat;
for(int i=0; i<3; i++){
List& b = CAST(List&, a[i]);
if(b.size() != 3) vm->ValueError("Mat3x3.__new__ takes 3x3 list");
for(int j=0; j<3; j++){
mat.m[i][j] = vm->num_to_float(b[j]);
}
}
return VAR_T(PyMat3x3, mat);
}
vm->TypeError("Mat3x3.__new__ takes 0 or 1 arguments");
return vm->None;
});
#define METHOD_PROXY_NONE(name) \
vm->bind_method<0>(type, #name, [](VM* vm, ArgsView args){ \
PyMat3x3& self = _CAST(PyMat3x3&, args[0]); \
self.name(); \
return vm->None; \
});
METHOD_PROXY_NONE(set_zeros)
METHOD_PROXY_NONE(set_ones)
METHOD_PROXY_NONE(set_identity)
#undef METHOD_PROXY_NONE
vm->bind_method<0>(type, "__repr__", [](VM* vm, ArgsView args){
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
std::stringstream ss;
ss << "mat3x3([[" << self._11 << ", " << self._12 << ", " << self._13 << "],\n";
ss << " [" << self._21 << ", " << self._22 << ", " << self._23 << "],\n";
ss << " [" << self._31 << ", " << self._32 << ", " << self._33 << "]])";
return VAR(ss.str());
});
vm->bind_method<1>(type, "__getitem__", [](VM* vm, ArgsView args){
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
Tuple& t = CAST(Tuple&, args[1]);
if(t.size() != 2){
vm->TypeError("Mat3x3.__getitem__ takes a tuple of 2 integers");
return vm->None;
}
i64 i = CAST(i64, t[0]);
i64 j = CAST(i64, t[1]);
if(i < 0 || i >= 3 || j < 0 || j >= 3){
vm->IndexError("index out of range");
return vm->None;
}
return VAR(self.m[i][j]);
});
vm->bind_method<2>(type, "__setitem__", [](VM* vm, ArgsView args){
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
Tuple& t = CAST(Tuple&, args[1]);
if(t.size() != 2){
vm->TypeError("Mat3x3.__setitem__ takes a tuple of 2 integers");
return vm->None;
}
i64 i = CAST(i64, t[0]);
i64 j = CAST(i64, t[1]);
if(i < 0 || i >= 3 || j < 0 || j >= 3){
vm->IndexError("index out of range");
return vm->None;
}
self.m[i][j] = vm->num_to_float(args[2]);
return vm->None;
});
#define PROPERTY_FIELD(field) \
type->attr().set(#field, vm->property([](VM* vm, ArgsView args){ \
PyMat3x3& self = _CAST(PyMat3x3&, args[0]); \
return VAR(self.field); \
}, [](VM* vm, ArgsView args){ \
PyMat3x3& self = _CAST(PyMat3x3&, args[0]); \
self.field = vm->num_to_float(args[1]); \
return vm->None; \
}));
PROPERTY_FIELD(_11)
PROPERTY_FIELD(_12)
PROPERTY_FIELD(_13)
PROPERTY_FIELD(_21)
PROPERTY_FIELD(_22)
PROPERTY_FIELD(_23)
PROPERTY_FIELD(_31)
PROPERTY_FIELD(_32)
PROPERTY_FIELD(_33)
#undef PROPERTY_FIELD
vm->bind_method<1>(type, "__add__", [](VM* vm, ArgsView args){
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
PyMat3x3& other = CAST(PyMat3x3&, args[1]);
return VAR_T(PyMat3x3, self.add(other));
});
vm->bind_method<1>(type, "__sub__", [](VM* vm, ArgsView args){
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
PyMat3x3& other = CAST(PyMat3x3&, args[1]);
return VAR_T(PyMat3x3, self.sub(other));
});
vm->bind_method<1>(type, "__mul__", [](VM* vm, ArgsView args){
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
f64 other = vm->num_to_float(args[1]);
return VAR_T(PyMat3x3, self.mul(other));
});
vm->bind_method<1>(type, "__truediv__", [](VM* vm, ArgsView args){
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
f64 other = vm->num_to_float(args[1]);
return VAR_T(PyMat3x3, self.div(other));
});
vm->bind_method<1>(type, "__matmul__", [](VM* vm, ArgsView args){
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
PyMat3x3& other = CAST(PyMat3x3&, args[1]);
return VAR_T(PyMat3x3, self.matmul(other));
});
vm->bind_method<1>(type, "__eq__", [](VM* vm, ArgsView args){
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
PyMat3x3& other = _CAST(PyMat3x3&, args[1]);
return VAR(self == other);
});
vm->bind_method<1>(type, "__ne__", [](VM* vm, ArgsView args){
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
PyMat3x3& other = CAST(PyMat3x3&, args[1]);
return VAR(self != other);
});
vm->bind_method<0>(type, "deteminant", [](VM* vm, ArgsView args){
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
return VAR(self.determinant());
});
vm->bind_method<0>(type, "transpose", [](VM* vm, ArgsView args){
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
return VAR_T(PyMat3x3, self.transpose());
});
vm->bind_method<0>(type, "inverse", [](VM* vm, ArgsView args){
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
Mat3x3 ret;
bool ok = self.inverse(ret);
if(!ok) vm->ValueError("matrix is not invertible");
return VAR_T(PyMat3x3, ret);
});
vm->bind_method<0>(type, "is_identity", [](VM* vm, ArgsView args){
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
return VAR(self.is_identity());
});
}
};
} // namespace pkpy

View File

@ -66,6 +66,8 @@ OPCODE(BITWISE_AND)
OPCODE(BITWISE_OR) OPCODE(BITWISE_OR)
OPCODE(BITWISE_XOR) OPCODE(BITWISE_XOR)
OPCODE(BINARY_MATMUL)
OPCODE(IS_OP) OPCODE(IS_OP)
OPCODE(CONTAINS_OP) OPCODE(CONTAINS_OP)
/**************************/ /**************************/

View File

@ -7,6 +7,7 @@
#include "iter.h" #include "iter.h"
#include "base64.h" #include "base64.h"
#include "cffi.h" #include "cffi.h"
#include "mat3x3.h"
#include "requests.h" #include "requests.h"
#include "io.h" #include "io.h"
#include "_generated.h" #include "_generated.h"
@ -1051,6 +1052,8 @@ inline void VM::post_init(){
add_module_os(this); add_module_os(this);
add_module_requests(this); add_module_requests(this);
} }
PyMat3x3::register_class(this, builtins);
#endif #endif
} }

View File

@ -412,19 +412,11 @@ const StrName __exit__ = StrName::get("__exit__");
const StrName __add__ = StrName::get("__add__"); const StrName __add__ = StrName::get("__add__");
const StrName __sub__ = StrName::get("__sub__"); const StrName __sub__ = StrName::get("__sub__");
const StrName __mul__ = StrName::get("__mul__"); const StrName __mul__ = StrName::get("__mul__");
// 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__");
// const StrName __pow__ = StrName::get("__pow__");
const StrName BINARY_SPECIAL_METHODS[] = {
StrName::get("__add__"), StrName::get("__sub__"), StrName::get("__mul__"),
StrName::get("__truediv__"), StrName::get("__floordiv__"),
StrName::get("__mod__"), StrName::get("__pow__")
};
const StrName __truediv__ = StrName::get("__truediv__");
const StrName __pow__ = StrName::get("__pow__"); const StrName __pow__ = StrName::get("__pow__");
const StrName __matmul__ = StrName::get("__matmul__");
const StrName __lt__ = StrName::get("__lt__"); const StrName __lt__ = StrName::get("__lt__");
const StrName __le__ = StrName::get("__le__"); const StrName __le__ = StrName::get("__le__");