blueloveTH 3 лет назад
Родитель
Сommit
3eb8e257d0
4 измененных файлов с 120 добавлено и 3 удалено
  1. 110 0
      src/cffi.h
  2. 6 2
      src/compiler.h
  3. 1 1
      src/parser.h
  4. 3 0
      src/pocketpy.h

+ 110 - 0
src/cffi.h

@@ -0,0 +1,110 @@
+#pragma once
+
+#include "vm.h"
+
+struct CType{
+    PY_CLASS(c, type)
+
+    StrName name;
+    int size;
+    CType(const StrName& name, int size) : name(name), size(size) {}
+
+    static void _register(VM* vm, PyVar mod, PyVar type){
+        vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED());
+    }
+};
+
+struct Pointer{
+    PY_CLASS(c, ptr)
+
+    void* ptr;
+    CType ctype;
+
+    Pointer(void* ptr, CType ctype) : ptr(ptr), ctype(ctype) {}
+
+    static void _register(VM* vm, PyVar mod, PyVar type){
+        vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED());
+
+        vm->bind_method<0>(type, "__repr__", [](VM* vm, pkpy::Args& args) {
+            Pointer& self = vm->py_cast<Pointer>(args[0]);
+            StrStream ss;
+            ss << "<" << self.ctype.name.str() << "* at " << std::hex << self.ptr << ">";
+            return vm->PyStr(ss.str());
+        });
+    }
+
+    template<class T>
+    inline T cast() noexcept {
+        return reinterpret_cast<T>(ptr);
+    }
+};
+
+void add_module_c(VM* vm){
+    PyVar mod = vm->new_module("c");
+    PyVar ptr_t = vm->register_class<Pointer>(mod);
+    PyVar ctype_t = vm->register_class<CType>(mod);
+
+    vm->setattr(mod, "char", vm->new_object<CType>("char", 1));
+    vm->setattr(mod, "int8", vm->new_object<CType>("int8", 1));
+    vm->setattr(mod, "int16", vm->new_object<CType>("int16", 2));
+    vm->setattr(mod, "int32", vm->new_object<CType>("int32", 4));
+    vm->setattr(mod, "int64", vm->new_object<CType>("int64", 8));
+    vm->setattr(mod, "uint8", vm->new_object<CType>("uchar", 1));
+    vm->setattr(mod, "uint16", vm->new_object<CType>("uint16", 2));
+    vm->setattr(mod, "uint32", vm->new_object<CType>("uint32", 4));
+    vm->setattr(mod, "uint64", vm->new_object<CType>("uint64", 8));
+    vm->setattr(mod, "float", vm->new_object<CType>("float", 4));
+    vm->setattr(mod, "double", vm->new_object<CType>("double", 8));
+    vm->setattr(mod, "bool", vm->new_object<CType>("bool", 1));
+
+    vm->bind_func<1>(mod, "malloc", [](VM* vm, pkpy::Args& args) {
+        i64 size = vm->PyInt_AS_C(args[0]);
+        return vm->new_object<Pointer>(malloc(size), CType("char", 1));
+    });
+
+    vm->bind_func<1>(mod, "free", [](VM* vm, pkpy::Args& args) {
+        Pointer& self = vm->py_cast<Pointer>(args[0]);
+        free(self.ptr);
+        return vm->None;
+    });
+
+    vm->bind_func<1>(mod, "sizeof", [](VM* vm, pkpy::Args& args) {
+        CType& ctype = vm->py_cast<CType>(args[0]);
+        return vm->PyInt(ctype.size);
+    });
+
+    vm->bind_func<3>(mod, "memcpy", [](VM* vm, pkpy::Args& args) {
+        Pointer& dst = vm->py_cast<Pointer>(args[0]);
+        Pointer& src = vm->py_cast<Pointer>(args[1]);
+        i64 size = vm->PyInt_AS_C(args[2]);
+        memcpy(dst.ptr, src.ptr, size);
+        return vm->None;
+    });
+
+    vm->bind_func<3>(mod, "memset", [](VM* vm, pkpy::Args& args) {
+        Pointer& dst = vm->py_cast<Pointer>(args[0]);
+        i64 val = vm->PyInt_AS_C(args[1]);
+        i64 size = vm->PyInt_AS_C(args[2]);
+        memset(dst.ptr, (int)val, size);
+        return vm->None;
+    });
+
+    vm->bind_func<1>(mod, "strdup", [ptr_t](VM* vm, pkpy::Args& args) {
+        if(is_type(args[0], vm->tp_str)){
+            const Str& s = vm->PyStr_AS_C(args[0]);
+            return vm->new_object<Pointer>(strdup(s.c_str()), CType("char", 1));
+        }else if(is_type(args[0], OBJ_GET(Type, ptr_t))){
+            Pointer& p = vm->py_cast<Pointer>(args[0]);
+            return vm->new_object<Pointer>(strdup(p.cast<char*>()), CType("char", 1));
+        }else{
+            vm->TypeError("strdup() argument must be 'str' or 'c.ptr'");
+            return vm->None;
+        }
+    });
+
+    vm->bind_func<2>(mod, "strcmp", [](VM* vm, pkpy::Args& args) {
+        Pointer& p1 = vm->py_cast<Pointer>(args[0]);
+        Pointer& p2 = vm->py_cast<Pointer>(args[1]);
+        return vm->PyInt(strcmp(p1.cast<char*>(), p2.cast<char*>()));
+    });
+}

+ 6 - 2
src/compiler.h

@@ -84,6 +84,8 @@ public:
         rules[TK("&=")] =       { nullptr,               METHOD(exprAssign),         PREC_ASSIGNMENT };
         rules[TK("|=")] =       { nullptr,               METHOD(exprAssign),         PREC_ASSIGNMENT };
         rules[TK("^=")] =       { nullptr,               METHOD(exprAssign),         PREC_ASSIGNMENT };
+        rules[TK(">>=")] =      { nullptr,               METHOD(exprAssign),         PREC_ASSIGNMENT };
+        rules[TK("<<=")] =      { nullptr,               METHOD(exprAssign),         PREC_ASSIGNMENT };
         rules[TK(",")] =        { nullptr,               METHOD(exprComma),          PREC_COMMA };
         rules[TK("<<")] =       { nullptr,               METHOD(exprBinaryOp),       PREC_BITWISE_SHIFT };
         rules[TK(">>")] =       { nullptr,               METHOD(exprBinaryOp),       PREC_BITWISE_SHIFT };
@@ -228,13 +230,13 @@ private:
                 case '+': parser->set_next_token_2('=', TK("+"), TK("+=")); return;
                 case '>': {
                     if(parser->matchchar('=')) parser->set_next_token(TK(">="));
-                    else if(parser->matchchar('>')) parser->set_next_token(TK(">>"));
+                    else if(parser->matchchar('>')) parser->set_next_token_2('=', TK(">>"), TK(">>="));
                     else parser->set_next_token(TK(">"));
                     return;
                 }
                 case '<': {
                     if(parser->matchchar('=')) parser->set_next_token(TK("<="));
-                    else if(parser->matchchar('<')) parser->set_next_token(TK("<<"));
+                    else if(parser->matchchar('<')) parser->set_next_token_2('=', TK("<<"), TK("<<="));
                     else parser->set_next_token(TK("<"));
                     return;
                 }
@@ -422,6 +424,8 @@ private:
                 case TK("/="):      emit(OP_INPLACE_BINARY_OP, 3);  break;
                 case TK("//="):     emit(OP_INPLACE_BINARY_OP, 4);  break;
                 case TK("%="):      emit(OP_INPLACE_BINARY_OP, 5);  break;
+                case TK("<<="):     emit(OP_INPLACE_BITWISE_OP, 0);  break;
+                case TK(">>="):     emit(OP_INPLACE_BITWISE_OP, 1);  break;
                 case TK("&="):      emit(OP_INPLACE_BITWISE_OP, 2);  break;
                 case TK("|="):      emit(OP_INPLACE_BITWISE_OP, 3);  break;
                 case TK("^="):      emit(OP_INPLACE_BITWISE_OP, 4);  break;

+ 1 - 1
src/parser.h

@@ -10,7 +10,7 @@ constexpr const char* kTokens[] = {
     "+", "-", "*", "/", "//", "**", "=", ">", "<", "...", "->",
     "<<", ">>", "&", "|", "^", "?", "@",
     "==", "!=", ">=", "<=",
-    "+=", "-=", "*=", "/=", "//=", "%=", "&=", "|=", "^=",
+    "+=", "-=", "*=", "/=", "//=", "%=", "&=", "|=", "^=", ">>=", "<<=",
     /** KW_BEGIN **/
     "class", "import", "as", "def", "lambda", "pass", "del", "from", "with", "yield",
     "None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally",

+ 3 - 0
src/pocketpy.h

@@ -788,6 +788,8 @@ void add_module_functools(VM* vm){
     vm->_exec(code, mod);
 }
 
+#include "cffi.h"
+
 void VM::post_init(){
     init_builtins(this);
     add_module_sys(this);
@@ -800,6 +802,7 @@ void VM::post_init(){
     add_module_io(this);
     add_module_os(this);
     add_module_functools(this);
+    add_module_c(this);
 
     CodeObject_ code = compile(kBuiltinsCode, "<builtins>", EXEC_MODE);
     this->_exec(code, this->builtins);