diff --git a/build_g.sh b/build_g.sh index b668a308..d9cac018 100644 --- a/build_g.sh +++ b/build_g.sh @@ -4,7 +4,7 @@ python prebuild.py SRC=$(find src/ -name "*.c") -FLAGS="-std=c11 -Iinclude -O0 -Wfatal-errors -g -DDEBUG -DPK_ENABLE_OS=1" # -fsanitize=address,leak,undefined" +FLAGS="-std=c11 -lm -Iinclude -O0 -Wfatal-errors -g -DDEBUG -DPK_ENABLE_OS=1" # -fsanitize=address,leak,undefined" echo "Compiling C files..." clang $FLAGS $SRC src2/main.c -o main diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 7ac13f62..ae2883d6 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -82,6 +82,8 @@ void pk_VM__dtor(pk_VM* self); void pk_VM__push_frame(pk_VM* self, Frame* frame); void pk_VM__pop_frame(pk_VM* self); +void pk_VM__init_builtins(pk_VM* self); + typedef enum pk_FrameResult{ RES_RETURN, RES_CALL, diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 4fb6f050..177f20c9 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -10,7 +10,7 @@ typedef struct pk_VM pk_VM; typedef uint16_t py_Name; typedef int16_t py_Type; typedef PyVar* py_Ref; -typedef int (*py_CFunction)(const py_Ref, int); +typedef int (*py_CFunction)(int argc, py_Ref argv); typedef struct py_Str py_Str; @@ -48,11 +48,37 @@ void py_newtuple(py_Ref, int); // void py_newlist(py_Ref); // new style decl-based function -void py_newfunction(py_Ref, py_CFunction, const char* sig, BindType bt); -void py_newfunction2(py_Ref, py_CFunction, const char* sig, BindType bt, const char* docstring, const py_Ref userdata); +void py_newfunction(py_Ref self, py_CFunction, const char* sig); +void py_newfunction2(py_Ref self, py_CFunction, const char* sig, BindType bt, const char* docstring, const py_Ref userdata); // old style argc-based function -void py_newnativefunc(py_Ref, py_CFunction, int argc, BindType bt); -void py_newnativefunc2(py_Ref, py_CFunction, int argc, BindType bt, const char* docstring, const py_Ref userdata); +void py_newnativefunc(py_Ref self, py_CFunction, int argc); +void py_newnativefunc2(py_Ref self, py_CFunction, int argc, BindType bt, const char* docstring, const py_Ref userdata); + +/************* Stack Values Creation *************/ +void py_pushint(int64_t); +void py_pushfloat(double); +void py_pushbool(bool); +void py_pushstr(const py_Str*); +void py_pushcstr(const char*); +void py_pushcstrn(const char*, int); +void py_push_notimplemented(); + +/************* Type Cast *************/ +int64_t py_toint(py_Ref); +double py_tofloat(py_Ref); +bool py_castfloat(py_Ref, double* out); +bool py_tobool(py_Ref); +const py_Str* py_tostr(py_Ref); +const char* py_tocstr(py_Ref); + +#define py_isint(self) py_istype(self, tp_int) +#define py_isfloat(self) py_istype(self, tp_float) +#define py_isbool(self) py_istype(self, tp_bool) +#define py_isstr(self) py_istype(self, tp_str) + +bool py_istype(const py_Ref, py_Type); +// bool py_isinstance(const py_Ref obj, py_Type type); +// bool py_issubclass(py_Type derived, py_Type base); /************* References *************/ py_Ref py_getdict(const py_Ref self, py_Name name); @@ -134,15 +160,6 @@ void py_dict__clear(py_Ref self); int py_str(const py_Ref, py_Str* out); int py_repr(const py_Ref, py_Str* out); -int py_toint(py_Ref, int64_t* out); -int py_tofloat(py_Ref, double* out); -int py_tostr(py_Ref, py_Str** out); -int py_tobool(py_Ref, bool* out); - -bool py_istype(const py_Ref, py_Type); -bool py_isinstance(const py_Ref obj, py_Type type); -bool py_issubclass(py_Type derived, py_Type base); - #ifdef __cplusplus } #endif diff --git a/src/interpreter/py_number.c b/src/interpreter/py_number.c new file mode 100644 index 00000000..9d9ab283 --- /dev/null +++ b/src/interpreter/py_number.c @@ -0,0 +1,293 @@ +#include "pocketpy/interpreter/vm.h" + +#include + +// static int _py_print(const py_Ref args, int argc){ +// int length = py_tuple__len(args+0); +// py_Str* sep; +// py_Str* end; + +// int err; +// err = py_tostr(args+1, &sep); +// if(err) return err; +// err = py_tostr(args+2, &end); +// if(err) return err; + +// pk_SStream ss; +// pk_SStream__ctor(&ss); + +// for(int i=0; i_stdout(py_Str__data(&out)); +// py_Str__dtor(&out); +// return 0; +// } + +#define DEF_NUM_BINARY_OP(name, op) \ + static int _py_int##name(int argc, py_Ref argv) { \ + if(py_isint(&argv[1])) { \ + int64_t lhs = py_toint(&argv[0]); \ + int64_t rhs = py_toint(&argv[1]); \ + py_pushint(lhs op rhs); \ + } else if(py_isfloat(&argv[1])) { \ + int64_t lhs = py_toint(&argv[0]); \ + double rhs = py_tofloat(&argv[1]); \ + py_pushfloat(lhs op rhs); \ + } else { \ + py_push_notimplemented(); \ + } \ + return 1; \ + } \ + static int _py_float##name(int argc, py_Ref argv) { \ + double lhs = py_tofloat(&argv[0]); \ + double rhs; \ + if(py_castfloat(&argv[1], &rhs)) { \ + py_pushfloat(lhs op rhs); \ + } else { \ + py_push_notimplemented(); \ + } \ + return 1; \ + } + +DEF_NUM_BINARY_OP(__add__, +) +DEF_NUM_BINARY_OP(__sub__, -) +DEF_NUM_BINARY_OP(__mul__, *) + +DEF_NUM_BINARY_OP(__eq__, ==) +DEF_NUM_BINARY_OP(__lt__, <) +DEF_NUM_BINARY_OP(__le__, <=) +DEF_NUM_BINARY_OP(__gt__, >) +DEF_NUM_BINARY_OP(__ge__, >=) + +#undef DEF_NUM_BINARY_OP + +static int _py_int__neg__(int argc, py_Ref argv) { + int64_t val = py_toint(&argv[0]); + py_pushint(-val); + return 1; +} + +static int _py_float__neg__(int argc, py_Ref argv) { + double val = py_tofloat(&argv[0]); + py_pushfloat(-val); + return 1; +} + +static int _py_int__truediv__(int argc, py_Ref argv) { + int64_t lhs = py_toint(&argv[0]); + double rhs; + if(py_castfloat(&argv[1], &rhs)) { + py_pushfloat(lhs / rhs); + } else { + py_push_notimplemented(); + } + return 1; +} + +static int _py_float__truediv__(int argc, py_Ref argv) { + double lhs = py_tofloat(&argv[0]); + double rhs; + if(py_castfloat(&argv[1], &rhs)) { + py_pushfloat(lhs / rhs); + } else { + py_push_notimplemented(); + } + return 1; +} + +static int _py_number__pow__(int argc, py_Ref argv) { + if(py_isint(&argv[0]) && py_isint(&argv[1])) { + int64_t lhs = py_toint(&argv[0]); + int64_t rhs = py_toint(&argv[1]); + if(rhs < 0) { + if(lhs == 0) { + // py_pusherror("0.0 cannot be raised to a negative power"); + // TODO: ZeroDivisionError + return -1; + } else { + py_pushfloat(pow(lhs, rhs)); + } + } else { + int64_t ret = 1; + while(rhs) { + if(rhs & 1) ret *= lhs; + lhs *= lhs; + rhs >>= 1; + } + py_pushint(ret); + } + } else { + double lhs, rhs; + py_castfloat(&argv[0], &lhs); + if(py_castfloat(&argv[1], &rhs)) { + py_pushfloat(pow(lhs, rhs)); + } else { + py_push_notimplemented(); + } + } + return 1; +} + +static int _py_int__floordiv__(int argc, py_Ref argv) { + int64_t lhs = py_toint(&argv[0]); + if(py_isint(&argv[1])) { + int64_t rhs = py_toint(&argv[1]); + if(rhs == 0) return -1; + py_pushint(lhs / rhs); + } else { + py_push_notimplemented(); + } + return 1; +} + +static int _py_int__mod__(int argc, py_Ref argv) { + int64_t lhs = py_toint(&argv[0]); + if(py_isint(&argv[1])) { + int64_t rhs = py_toint(&argv[1]); + if(rhs == 0) return -1; + py_pushint(lhs % rhs); + } else { + py_push_notimplemented(); + } + return 1; +} + +static int _py_int__invert__(int argc, py_Ref argv) { + int64_t val = py_toint(&argv[0]); + py_pushint(~val); + return 1; +} + +static int _py_int__bit_length(int argc, py_Ref argv) { + int64_t x = py_toint(&argv[0]); + if(x < 0) x = -x; + int bits = 0; + while(x) { + x >>= 1; + bits++; + } + py_pushint(bits); + return 1; +} + +#define DEF_INT_BITWISE_OP(name, op) \ + static int _py_int##name(int argc, py_Ref argv) { \ + int64_t lhs = py_toint(&argv[0]); \ + if(py_isint(&argv[1])) { \ + int64_t rhs = py_toint(&argv[1]); \ + py_pushint(lhs op rhs); \ + } else { \ + py_push_notimplemented(); \ + } \ + return 1; \ + } + +DEF_INT_BITWISE_OP(__and__, &) +DEF_INT_BITWISE_OP(__or__, |) +DEF_INT_BITWISE_OP(__xor__, ^) +DEF_INT_BITWISE_OP(__lshift__, <<) +DEF_INT_BITWISE_OP(__rshift__, >>) + +#undef DEF_INT_BITWISE_OP + +void pk_VM__init_builtins(pk_VM* self) { + /****** tp_int & tp_float ******/ + py_Ref tmp = py_pushtmp(); + py_Ref int_type = py_pushtmp(); + *int_type = *py_getdict(&self->builtins, py_name("int")); + py_Ref float_type = py_pushtmp(); + *float_type = *py_getdict(&self->builtins, py_name("float")); + +#define BIND_INT_BINARY_OP(name) \ + py_newnativefunc(tmp, _py_int##name, 2); \ + py_setdict(int_type, name, tmp); + +#define BIND_FLOAT_BINARY_OP(name) \ + py_newnativefunc(tmp, _py_float##name, 2); \ + py_setdict(float_type, name, tmp); + + BIND_INT_BINARY_OP(__add__); + BIND_FLOAT_BINARY_OP(__add__); + BIND_INT_BINARY_OP(__sub__); + BIND_FLOAT_BINARY_OP(__sub__); + BIND_INT_BINARY_OP(__mul__); + BIND_FLOAT_BINARY_OP(__mul__); + + BIND_INT_BINARY_OP(__eq__); + BIND_FLOAT_BINARY_OP(__eq__); + BIND_INT_BINARY_OP(__lt__); + BIND_FLOAT_BINARY_OP(__lt__); + BIND_INT_BINARY_OP(__le__); + BIND_FLOAT_BINARY_OP(__le__); + BIND_INT_BINARY_OP(__gt__); + BIND_FLOAT_BINARY_OP(__gt__); + BIND_INT_BINARY_OP(__ge__); + BIND_FLOAT_BINARY_OP(__ge__); + + // __neg__ + py_newnativefunc(tmp, _py_int__neg__, 1); + py_setdict(int_type, __neg__, tmp); + py_newnativefunc(tmp, _py_float__neg__, 1); + py_setdict(float_type, __neg__, tmp); + + // TODO: __repr__, __new__, __hash__ + + // __truediv__ + py_newnativefunc(tmp, _py_int__truediv__, 2); + py_setdict(int_type, __truediv__, tmp); + py_newnativefunc(tmp, _py_float__truediv__, 2); + py_setdict(float_type, __truediv__, tmp); + + // __pow__ + py_newnativefunc(tmp, _py_number__pow__, 2); + py_setdict(int_type, __pow__, tmp); + py_setdict(float_type, __pow__, tmp); + + // __floordiv__ & __mod__ + py_newnativefunc(tmp, _py_int__floordiv__, 2); + py_setdict(int_type, __floordiv__, tmp); + py_newnativefunc(tmp, _py_int__mod__, 2); + py_setdict(int_type, __mod__, tmp); + + // int.__invert__ & int. + py_newnativefunc(tmp, _py_int__invert__, 1); + py_setdict(int_type, __invert__, tmp); + + BIND_INT_BINARY_OP(__and__); + BIND_INT_BINARY_OP(__or__); + BIND_INT_BINARY_OP(__xor__); + BIND_INT_BINARY_OP(__lshift__); + BIND_INT_BINARY_OP(__rshift__); + + // int.bit_length + py_newnativefunc(tmp, _py_int__bit_length, 1); + py_setdict(int_type, py_name("bit_length"), tmp); + +#undef BIND_INT_BINARY_OP +#undef BIND_FLOAT_BINARY_OP + + py_poptmp(3); + + // py_Ref builtins = py_getmodule("builtins"); + // py_newfunction(py_reg(0), _py_print, + // "print(*args, sep=' ', end='\\n')", + // BindType_FUNCTION + // ); + // py_setdict(builtins, py_name("hello"), py_reg(0)); +} \ No newline at end of file diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 58e6b1c9..7e6c7fe8 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -34,52 +34,6 @@ void pk_TypeInfo__dtor(pk_TypeInfo *self){ c11_vector__dtor(&self->annotated_fields); } -// static int _py_print(const py_Ref args, int argc){ -// int length = py_tuple__len(args+0); -// py_Str* sep; -// py_Str* end; - -// int err; -// err = py_tostr(args+1, &sep); -// if(err) return err; -// err = py_tostr(args+2, &end); -// if(err) return err; - -// pk_SStream ss; -// pk_SStream__ctor(&ss); - -// for(int i=0; i_stdout(py_Str__data(&out)); -// py_Str__dtor(&out); -// return 0; -// } - -static void do_builtin_bindings(){ - // py_Ref builtins = py_getmodule("builtins"); - // py_newfunction(py_reg(0), _py_print, - // "print(*args, sep=' ', end='\\n')", - // BindType_FUNCTION - // ); - // py_setdict(builtins, py_name("hello"), py_reg(0)); -} - void pk_VM__ctor(pk_VM* self){ self->top_frame = NULL; @@ -189,7 +143,7 @@ void pk_VM__ctor(pk_VM* self){ py_setdict(&self->builtins, py_name("NotImplemented"), &self->NotImplemented); /* Do Buildin Bindings*/ - do_builtin_bindings(); + pk_VM__init_builtins(self); self->main = *py_newmodule("__main__", NULL); } diff --git a/src/public/cast.c b/src/public/cast.c new file mode 100644 index 00000000..69f2915d --- /dev/null +++ b/src/public/cast.c @@ -0,0 +1,46 @@ +#include "pocketpy/pocketpy.h" + +#include "pocketpy/common/utils.h" +#include "pocketpy/objects/object.h" +#include "pocketpy/interpreter/vm.h" + +int64_t py_toint(py_Ref self){ + return self->_i64; +} + +double py_tofloat(py_Ref self){ + return self->_f64; +} + +bool py_castfloat(py_Ref self, double* out){ + switch(self->type){ + case tp_int: + *out = (double)self->_i64; + return true; + case tp_float: + *out = self->_f64; + return true; + case tp_bool: + *out = self->extra; + return true; + default: + return false; + } +} + +bool py_tobool(py_Ref self){ + return self->extra; +} + +const py_Str* py_tostr(py_Ref self){ + return PyObject__value(self->_obj); +} + +const char* py_tocstr(py_Ref self){ + const py_Str* s = PyObject__value(self->_obj); + return py_Str__data(s); +} + +bool py_istype(const py_Ref self, py_Type type){ + return self->type == type; +} diff --git a/src/public/values.c b/src/public/values.c index 8eaecfed..243a5c24 100644 --- a/src/public/values.c +++ b/src/public/values.c @@ -4,24 +4,24 @@ #include "pocketpy/objects/object.h" #include "pocketpy/interpreter/vm.h" -void py_newint(py_Ref self, int64_t val){ +void py_newint(py_Ref self, int64_t val) { self->type = tp_int; self->is_ptr = false; self->_i64 = val; } -void py_newfloat(py_Ref self, double val){ +void py_newfloat(py_Ref self, double val) { self->type = tp_float; self->is_ptr = false; self->_f64 = val; } -void py_newbool(py_Ref self, bool val){ +void py_newbool(py_Ref self, bool val) { pk_VM* vm = pk_current_vm; *self = val ? vm->True : vm->False; } -void py_newstr(py_Ref self, const char* data){ +void py_newstr(py_Ref self, const char* data) { pk_ManagedHeap* heap = &pk_current_vm->heap; PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_str, 0, sizeof(py_Str)); py_Str__ctor((py_Str*)PyObject__value(obj), data); @@ -30,7 +30,7 @@ void py_newstr(py_Ref self, const char* data){ self->_obj = obj; } -void py_newstrn(py_Ref self, const char* data, int size){ +void py_newstrn(py_Ref self, const char* data, int size) { pk_ManagedHeap* heap = &pk_current_vm->heap; PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_str, 0, sizeof(py_Str)); py_Str__ctor2((py_Str*)PyObject__value(obj), data, size); @@ -39,16 +39,14 @@ void py_newstrn(py_Ref self, const char* data, int size){ self->_obj = obj; } -void py_newnone(py_Ref self){ +void py_newnone(py_Ref self) { pk_VM* vm = pk_current_vm; *self = vm->None; } -void py_newnull(py_Ref self){ - self->type = 0; -} +void py_newnull(py_Ref self) { self->type = 0; } -void py_newtuple(py_Ref self, int n){ +void py_newtuple(py_Ref self, int n) { pk_VM* vm = pk_current_vm; PyObject* obj = pk_ManagedHeap__gcnew(&vm->heap, tp_tuple, n, 0); self->type = tp_tuple; @@ -56,18 +54,41 @@ void py_newtuple(py_Ref self, int n){ self->_obj = obj; } -void py_newfunction(py_Ref self, py_CFunction f, const char* sig, BindType bt){ - py_newfunction2(self, f, sig, bt, NULL, NULL); +void py_newfunction(py_Ref self, py_CFunction f, const char* sig) { + py_newfunction2(self, f, sig, BindType_FUNCTION, NULL, NULL); } -void py_newfunction2(py_Ref self, py_CFunction f, const char *sig, BindType bt, const char *docstring, const py_Ref userdata){ +void py_newfunction2(py_Ref self, + py_CFunction f, + const char* sig, + BindType bt, + const char* docstring, + const py_Ref userdata) {} +void py_newnativefunc(py_Ref self, py_CFunction f, int argc) { + py_newnativefunc2(self, f, argc, BindType_FUNCTION, NULL, NULL); } -void py_newnativefunc(py_Ref self, py_CFunction f, int argc, BindType bt){ - py_newnativefunc2(self, f, argc, bt, NULL, NULL); +void py_newnativefunc2(py_Ref self, + py_CFunction f, + int argc, + BindType bt, + const char* docstring, + const py_Ref userdata) {} + +void py_pushint(int64_t val) { py_newint(pk_current_vm->stack.sp++, val); } + +void py_pushfloat(double val) { py_newfloat(pk_current_vm->stack.sp++, val); } + +void py_pushbool(bool val) { py_newbool(pk_current_vm->stack.sp++, val); } + +void py_pushstr(const py_Str* val) { py_newstr(pk_current_vm->stack.sp++, py_Str__data(val)); } + +void py_pushcstr(const char* val) { py_newstr(pk_current_vm->stack.sp++, val); } + +void py_pushcstrn(const char* val, int size) { py_newstrn(pk_current_vm->stack.sp++, val, size); } + +void py_push_notimplemented() { + pk_VM* vm = pk_current_vm; + *vm->stack.sp++ = vm->NotImplemented; } - -void py_newnativefunc2(py_Ref self, py_CFunction f, int argc, BindType bt, const char *docstring, const py_Ref userdata){ - -} \ No newline at end of file