blueloveTH 2 лет назад
Родитель
Сommit
83d6ac2e78
6 измененных файлов с 88 добавлено и 270 удалено
  1. BIN
      .github/workflows.rar
  2. 0 129
      .github/workflows/main.yml
  3. 4 11
      src/ceval.h
  4. 83 126
      src/compiler.h
  5. 1 0
      src/expr.h
  6. 0 4
      src/frame.h

BIN
.github/workflows.rar


+ 0 - 129
.github/workflows/main.yml

@@ -1,129 +0,0 @@
-name: build
-on: [push, pull_request]
-jobs:
-  build_win:
-    runs-on: windows-latest
-    steps:
-    - uses: actions/checkout@v3
-    - name: Setup Clang
-      uses: egor-tensin/setup-clang@v1
-      with:
-        version: 15
-        platform: x64
-    - name: Compiling
-      shell: bash
-      run: |
-        python3 build.py windows
-        python3 build.py windows -lib
-        mkdir -p output/windows/x86_64
-        cp pocketpy.exe output/windows/x86_64
-        cp pocketpy.dll output/windows/x86_64
-    - uses: actions/upload-artifact@v3
-      with:
-        path: output
-    - name: Unit Test
-      run: python3 scripts/run_tests.py
-    - name: Benchmark
-      run: python3 scripts/run_tests.py benchmark
-  build_web:
-    runs-on: ubuntu-latest
-    steps:
-    - uses: actions/checkout@v3
-    - name: Setup emsdk
-      uses: mymindstorm/setup-emsdk@v12
-      with:
-        version: 3.1.25
-        actions-cache-folder: 'emsdk-cache'
-    - name: Verify emsdk
-      run: emcc -v
-    - name: Compiling
-      run: |
-        mkdir -p output/web/lib
-        python3 build.py web
-        cp web/lib/* output/web/lib
-    - uses: crazy-max/ghaction-github-pages@v3
-      with:
-        target_branch: gh-pages
-        build_dir: web
-      env:
-        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-      if: github.event_name == 'push' && github.ref == 'refs/heads/main'
-    - uses: actions/upload-artifact@v3
-      with:
-        path: output
-  build_linux:
-    runs-on: ubuntu-latest
-    steps:
-    - uses: actions/checkout@v3
-    - name: Setup Clang
-      uses: egor-tensin/setup-clang@v1
-      with:
-        version: 15
-        platform: x64
-    - name: Coverage Test
-      run: |
-        sudo apt install -y libc++-15-dev libc++1-15 libc++abi-15-dev libc++abi1-15 libclang-rt-15-dev
-        python3 preprocess.py
-        bash run_tests.sh
-    - uses: actions/upload-artifact@v3
-      with:
-        name: coverage
-        path: .coverage
-    - name: Compiling
-      run: |
-        python3 build.py linux
-        python3 build.py linux -lib
-        mkdir -p output/linux/x86_64
-        cp pocketpy output/linux/x86_64
-        cp pocketpy.so output/linux/x86_64
-    - uses: actions/upload-artifact@v3
-      with:
-        path: output
-    - name: Unit Test
-      run: python3 scripts/run_tests.py
-    - name: Benchmark
-      run: python3 scripts/run_tests.py benchmark
-  build_android:
-      runs-on: ubuntu-latest
-      steps:
-      - uses: actions/checkout@v3
-      - uses: subosito/flutter-action@v2
-        with:
-          flutter-version: '3.3.0'
-          channel: 'stable'
-          cache: true
-      - run: flutter --version
-      - name: Compiling
-        run: |
-          python3 amalgamate.py
-          cd plugins/flutter/example
-          flutter build apk --split-debug-info=.debug-info --split-per-abi
-          cd build/app/outputs/flutter-apk
-          mkdir -p output/android/arm64-v8a
-          mkdir -p output/android/armeabi-v7a
-          mkdir -p output/android/x86_64
-          unzip -q app-arm64-v8a-release.apk -d tmp
-          mv tmp/lib/arm64-v8a/libpocketpy.so output/android/arm64-v8a/libpocketpy.so
-          rm -rf tmp
-          unzip -q app-armeabi-v7a-release.apk -d tmp
-          mv tmp/lib/armeabi-v7a/libpocketpy.so output/android/armeabi-v7a/libpocketpy.so
-          rm -rf tmp
-          unzip -q app-x86_64-release.apk -d tmp
-          mv tmp/lib/x86_64/libpocketpy.so output/android/x86_64/libpocketpy.so
-          rm -rf tmp
-      - uses: actions/upload-artifact@v3
-        with:
-          path: plugins/flutter/example/build/app/outputs/flutter-apk/output
-  build_macos:
-      runs-on: macos-latest
-      steps:
-      - uses: actions/checkout@v3
-      - run: |
-          python3 amalgamate.py
-          cd plugins/macos/pocketpy
-          mkdir -p output/macos
-          xcodebuild clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
-          cp -r build/Release/pocketpy.bundle output/macos
-      - uses: actions/upload-artifact@v3
-        with:
-          path: plugins/macos/pocketpy/output

+ 4 - 11
src/ceval.h

@@ -1,13 +1,14 @@
 #pragma once
 
+#include "common.h"
 #include "vm.h"
 #include "ref.h"
 
 namespace pkpy{
 
 inline PyObject* VM::run_frame(Frame* frame){
-    while(frame->has_next_bytecode()){
-        heap._auto_collect(this);
+    while(true){
+        heap._auto_collect(this);   // gc
 
         const Bytecode& byte = frame->next_bytecode();
         switch (byte.op)
@@ -320,15 +321,7 @@ inline PyObject* VM::run_frame(Frame* frame){
         default: throw std::runtime_error(Str("opcode ") + OP_NAMES[byte.op] + " is not implemented");
         }
     }
-
-    if(frame->co->src->mode == EVAL_MODE || frame->co->src->mode == JSON_MODE){
-        if(frame->_data.size() != 1) throw std::runtime_error("_data.size() != 1 in EVAL/JSON_MODE");
-        return frame->pop_value(this);
-    }
-#if DEBUG_EXTRA_CHECK
-    if(!frame->_data.empty()) throw std::runtime_error("_data.size() != 0 in EXEC_MODE");
-#endif
-    return None;
+    UNREACHABLE();
 }
 
 } // namespace pkpy

+ 83 - 126
src/compiler.h

@@ -20,8 +20,6 @@ struct PrattRule{
     Precedence precedence;
 };
 
-enum ExprAction { EXPR_PUSH_STACK, EXPR_RVALUE, EXPR_LVALUE };
-
 class Compiler {
     std::unique_ptr<Lexer> lexer;
     stack<CodeEmitContext> contexts;
@@ -42,8 +40,10 @@ class Compiler {
     }
 
     void pop_context(){
-        if(!ctx()->s_expr.empty()){
-            ctx()->emit_expr();
+        if(!ctx()->s_expr.empty()) UNREACHABLE();
+        if(ctx()->co->codes.back().op != OP_RETURN_VALUE){
+            ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE);
+            ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
         }
         ctx()->co->optimize(vm);
         contexts.pop();
@@ -164,16 +164,12 @@ private:
         if (!match_end_stmt()) SyntaxError("expected statement end");
     }
 
-    void exprLiteral(){
-        ctx()->s_expr.push(
-            expr_prev_line<LiteralExpr>(prev().value)
-        );
+    void EXPR(ExprAction action=EXPR_PUSH_STACK) {
+        parse_expression(PREC_TUPLE + 1, action);
     }
 
-    void exprFString(){
-        ctx()->s_expr.push(
-            expr_prev_line<FStringExpr>(std::get<Str>(prev().value))
-        );
+    void EXPR_TUPLE(ExprAction action=EXPR_PUSH_STACK) {
+        parse_expression(PREC_TUPLE, action);
     }
 
     template <typename T, typename... Args>
@@ -183,6 +179,19 @@ private:
         return expr;
     }
 
+    /********************************************/
+
+    // PASS
+    void exprLiteral(){
+        ctx()->s_expr.push(expr_prev_line<LiteralExpr>(prev().value));
+    }
+
+    // PASS
+    void exprFString(){
+        ctx()->s_expr.push(expr_prev_line<FStringExpr>(std::get<Str>(prev().value)));
+    }
+
+    // PASS
     void exprLambda(){
         auto e = expr_prev_line<LambdaExpr>();
         e->func.name = "<lambda>";
@@ -192,42 +201,14 @@ private:
             consume(TK(":"));
         }
         e->func.code = push_context(lexer->src, "<lambda>");
-        EXPR();
+        // https://github.com/blueloveTH/pocketpy/issues/37
+        EXPR(true);
         ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
         pop_context();
         ctx()->s_expr.push(std::move(e));
     }
 
-    // assignment是一种特殊的无返回值表达式,他不应该位于PREC中
-    void exprInplaceAssign(){
-        auto e = expr_prev_line<InplaceAssignExpr>();
-        e->op = prev().type;
-        e->lhs = ctx()->s_expr.popx();
-        // lhs cannot be a assignment expression, i.e. a = b += c is not allowed
-        if(e->lhs->is_assignment()) SyntaxError();
-        EXPR_TUPLE();
-        e->rhs = ctx()->s_expr.popx();
-        ctx()->s_expr.push(std::move(e));
-    }
-
-    void EXPR(ExprAction action=EXPR_PUSH_STACK) {
-        parse_expression(PREC_TUPLE + 1, action);
-    }
-
-    void EXPR_TUPLE(ExprAction action=EXPR_PUSH_STACK) {
-        parse_expression(PREC_TUPLE, action);
-    }
-
     void exprAssign(){
-        auto e = expr_prev_line<AssignExpr>();
-        e->lhs = ctx()->s_expr.popx();
-        // lhs cannot be a assignment expression, i.e. a = b = c is not allowed
-        // however in cpython, it is allowed, we'll fix it later
-        if(e->lhs->is_assignment()) SyntaxError();
-        EXPR_TUPLE();
-        e->rhs = ctx()->s_expr.popx();
-        ctx()->s_expr.push(std::move(e));
-
         // if(co()->codes.empty()) UNREACHABLE();
         // bool is_load_name_ref = co()->codes.back().op == OP_LOAD_NAME_REF;
         // int _name_arg = co()->codes.back().arg;
@@ -277,6 +258,7 @@ private:
         // co()->_rvalue -= 1;
     }
 
+    // PASS
     void exprTuple(){
         auto e = expr_prev_line<TupleExpr>();
         do {
@@ -286,6 +268,7 @@ private:
         ctx()->s_expr.push(std::move(e));
     }
 
+    // PASS
     void exprOr(){
         auto e = expr_prev_line<OrExpr>();
         e->lhs = ctx()->s_expr.popx();
@@ -294,14 +277,16 @@ private:
         ctx()->s_expr.push(std::move(e));
     }
 
+    // PASS
     void exprAnd(){
-        auto e = expr_prev_line<OrExpr>();
+        auto e = expr_prev_line<AndExpr>();
         e->lhs = ctx()->s_expr.popx();
         parse_expression(PREC_LOGICAL_AND + 1);
         e->rhs = ctx()->s_expr.popx();
         ctx()->s_expr.push(std::move(e));
     }
 
+    // PASS
     void exprTernary(){
         auto e = expr_prev_line<TernaryExpr>();
         e->cond = ctx()->s_expr.popx();
@@ -313,6 +298,7 @@ private:
         ctx()->s_expr.push(std::move(e));
     }
 
+    // PASS
     void exprBinaryOp(){
         auto e = expr_prev_line<BinaryExpr>();
         e->op = prev().type;
@@ -322,85 +308,56 @@ private:
         ctx()->s_expr.push(std::move(e));
     }
 
+    // PASS
     void exprNot() {
         parse_expression(PREC_LOGICAL_NOT + 1);
-        ctx()->s_expr.push(
-            expr_prev_line<NotExpr>(ctx()->s_expr.popx())
-        );
+        ctx()->s_expr.push(expr_prev_line<NotExpr>(ctx()->s_expr.popx()));
     }
 
+    // PASS
     void exprUnaryOp(){
-        TokenIndex type = prev().type;
+        TokenIndex op = prev().type;
         parse_expression(PREC_UNARY + 1);
-        Expr_ e;
-        switch(type){
+        switch(op){
             case TK("-"):
-                e = expr_prev_line<NegatedExpr>(ctx()->s_expr.popx());
+                ctx()->s_expr.push(expr_prev_line<NegatedExpr>(ctx()->s_expr.popx()));
+                break;
             case TK("*"):
-                e = expr_prev_line<StarredExpr>(ctx()->s_expr.popx());
+                ctx()->s_expr.push(expr_prev_line<StarredExpr>(ctx()->s_expr.popx()));
+                break;
             default: UNREACHABLE();
         }
-        ctx()->s_expr.push(std::move(e));
     }
 
-    // () is just for change precedence
+    // PASS
     void exprGroup(){
         match_newlines(mode()==REPL_MODE);
-        EXPR_TUPLE();
+        EXPR_TUPLE();   // () is just for change precedence
         match_newlines(mode()==REPL_MODE);
         consume(TK(")"));
     }
 
-    // void _consume_comp(Opcode op0, Opcode op1, int _patch, int _body_start){
-    //     int _body_end_return = emit(OP_JUMP_ABSOLUTE, -1);
-    //     int _body_end = co()->codes.size();
-    //     co()->codes[_patch].op = OP_JUMP_ABSOLUTE;
-    //     co()->codes[_patch].arg = _body_end;
-    //     emit(op0, 0);
-    //     EXPR_FOR_VARS();consume(TK("in"));EXPR_TUPLE();
-    //     match_newlines(mode()==REPL_MODE);
-        
-    //     int _skipPatch = emit(OP_JUMP_ABSOLUTE);
-    //     int _cond_start = co()->codes.size();
-    //     int _cond_end_return = -1;
-    //     if(match(TK("if"))) {
-    //         EXPR_TUPLE();
-    //         _cond_end_return = emit(OP_JUMP_ABSOLUTE, -1);
-    //     }
-    //     patch_jump(_skipPatch);
-
-    //     emit(OP_GET_ITER);
-    //     co()->_enter_block(FOR_LOOP);
-    //     emit(OP_FOR_ITER);
-
-    //     if(_cond_end_return != -1) {      // there is an if condition
-    //         emit(OP_JUMP_ABSOLUTE, _cond_start);
-    //         patch_jump(_cond_end_return);
-    //         int ifpatch = emit(OP_POP_JUMP_IF_FALSE);
-    //         emit(OP_JUMP_ABSOLUTE, _body_start);
-    //         patch_jump(_body_end_return);
-    //         emit(op1);
-    //         patch_jump(ifpatch);
-    //     }else{
-    //         emit(OP_JUMP_ABSOLUTE, _body_start);
-    //         patch_jump(_body_end_return);
-    //         emit(op1);
-    //     }
-
-    //     emit(OP_LOOP_CONTINUE, -1, true);
-    //     co()->_exit_block();
-    //     match_newlines(mode()==REPL_MODE);
-    // }
-
+    // PASS
     template<typename T>
     void _consume_comp(Expr_ expr){
         static_assert(std::is_base_of<CompExpr, T>::value);
         std::unique_ptr<CompExpr> ce = std::make_unique<T>();
         ce->expr = std::move(expr);
-        // ...
+        EXPR_TUPLE();   // must be a lvalue
+        ce->vars = ctx()->s_expr.popx();
+        consume(TK("in"));
+        EXPR();
+        ce->iter = ctx()->s_expr.popx();
+        match_newlines(mode()==REPL_MODE);
+        if(match(TK("if"))){
+            EXPR();
+            ce->cond = ctx()->s_expr.popx();
+        }
         ctx()->s_expr.push(std::move(ce));
+        match_newlines(mode()==REPL_MODE);
     }
 
+    // PASS
     void exprList() {
         auto e = expr_prev_line<ListExpr>();
         do {
@@ -414,15 +371,15 @@ private:
                 consume(TK("]"));
                 return;
             }
+            match_newlines(mode()==REPL_MODE);
         } while (match(TK(",")));
-        match_newlines(mode()==REPL_MODE);
         consume(TK("]"));
         ctx()->s_expr.push(std::move(e));
     }
 
-    // {...} may be dict or set
+    // PASS
     void exprMap() {
-        bool parsing_dict = false;
+        bool parsing_dict = false;  // {...} may be dict or set
         std::vector<Expr_> items;
         do {
             match_newlines(mode()==REPL_MODE);
@@ -446,6 +403,7 @@ private:
                 consume(TK("}"));
                 return;
             }
+            match_newlines(mode()==REPL_MODE);
         } while (match(TK(",")));
         consume(TK("}"));
         if(items.size()==0 || parsing_dict){
@@ -457,8 +415,10 @@ private:
         }
     }
 
+    // PASS
     void exprCall() {
         auto e = expr_prev_line<CallExpr>();
+        e->callable = ctx()->s_expr.popx();
         do {
             match_newlines(mode()==REPL_MODE);
             if (curr().type==TK(")")) break;
@@ -487,12 +447,12 @@ private:
         // }
     }
 
+    // PASS
     void exprName(){
-        ctx()->s_expr.push(
-            expr_prev_line<NameExpr>(prev().str(), name_scope())
-        );
+        ctx()->s_expr.push(expr_prev_line<NameExpr>(prev().str(), name_scope()));
     }
 
+    // PASS
     void exprAttrib() {
         consume(TK("@id"));
         ctx()->s_expr.push(
@@ -500,6 +460,7 @@ private:
         );
     }
 
+    // PASS
     void exprSubscr() {
         auto e = expr_prev_line<SubscrExpr>();
         std::vector<Expr_> items;
@@ -526,10 +487,9 @@ private:
         ctx()->s_expr.push(std::move(e));
     }
 
+    // PASS
     void exprLiteral0() {
-        ctx()->s_expr.push(
-            expr_prev_line<Literal0Expr>(prev().type)
-        );
+        ctx()->s_expr.push(expr_prev_line<Literal0Expr>(prev().type));
     }
 
     void compile_block_body() {
@@ -599,7 +559,7 @@ private:
         consume_end_stmt();
     }
 
-    void parse_expression(int precedence, ExprAction action=EXPR_PUSH_STACK) {
+    void parse_expression(int precedence, bool push_stack=true) {
         advance();
         PrattCallback prefix = rules[prev().type].prefix;
         if (prefix == nullptr) SyntaxError(Str("expected an expression, but got ") + TK_STR(prev().type));
@@ -611,16 +571,11 @@ private:
             if(infix == nullptr) throw std::runtime_error("(infix == nullptr) is true");
             (this->*infix)();
         }
-        switch(action){
-            case EXPR_PUSH_STACK: break;
-            case EXPR_RVALUE: ctx()->emit_rvalue(); break;
-            case EXPR_LVALUE: ctx()->emit_lvalue(); break;
-            default: UNREACHABLE();
-        }
+        if(!push_stack) ctx()->emit_expr();
     }
 
     void compile_if_stmt() {
-        EXPR(EXPR_RVALUE);   // condition
+        EXPR(true);   // condition
         int patch = ctx()->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line);
         compile_block_body();
         if (match(TK("elif"))) {
@@ -640,7 +595,7 @@ private:
 
     void compile_while_loop() {
         ctx()->enter_block(WHILE_LOOP);
-        EXPR(EXPR_RVALUE);   // condition
+        EXPR(true);   // condition
         int patch = ctx()->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line);
         compile_block_body();
         ctx()->emit(OP_LOOP_CONTINUE, BC_NOARG, BC_KEEPLINE);
@@ -649,9 +604,10 @@ private:
     }
 
     void compile_for_loop() {
-        EXPR_TUPLE(EXPR_LVALUE);
+        EXPR_TUPLE();
+        ctx()->emit_lvalue();
         consume(TK("in"));
-        EXPR_TUPLE(EXPR_RVALUE);
+        EXPR(true);
         ctx()->emit(OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
         ctx()->enter_block(FOR_LOOP);
         ctx()->emit(OP_FOR_ITER, BC_NOARG, BC_KEEPLINE);
@@ -689,10 +645,8 @@ private:
     }
 
     void compile_decorated(){
-        EXPR(EXPR_RVALUE);
-        if(!match_newlines(mode()==REPL_MODE)){
-            SyntaxError("expected a new line after '@'");
-        }
+        EXPR(true);
+        if(!match_newlines(mode()==REPL_MODE)) SyntaxError();
         ctx()->emit(OP_SETUP_DECORATOR, BC_NOARG, prev().line);
         consume(TK("def"));
         compile_function();
@@ -718,7 +672,7 @@ private:
                 break;
             case TK("yield"):
                 if (contexts.size() <= 1) SyntaxError("'yield' outside function");
-                EXPR_TUPLE(EXPR_RVALUE);
+                EXPR_TUPLE(true);
                 // if yield present, the function is a generator
                 ctx()->co->is_generator = true;
                 ctx()->emit(OP_YIELD_VALUE, BC_NOARG, kw_line);
@@ -729,7 +683,7 @@ private:
                 if(match_end_stmt()){
                     ctx()->emit(OP_LOAD_NONE, BC_NOARG, kw_line);
                 }else{
-                    EXPR_TUPLE(EXPR_RVALUE);
+                    EXPR_TUPLE(true);
                     consume_end_stmt();
                 }
                 ctx()->emit(OP_RETURN_VALUE, BC_NOARG, kw_line);
@@ -746,13 +700,14 @@ private:
             case TK("pass"): consume_end_stmt(); break;
             /*************************************************/
             case TK("assert"):
-                EXPR_TUPLE(EXPR_RVALUE);
+                EXPR_TUPLE(true);
                 // TODO: change OP_ASSERT impl in ceval.h
                 ctx()->emit(OP_ASSERT, BC_NOARG, kw_line);
                 consume_end_stmt();
                 break;
             case TK("del"):
-                EXPR_TUPLE(EXPR_LVALUE);
+                EXPR_TUPLE();
+                ctx()->emit_lvalue();
                 ctx()->emit(OP_DELETE_REF, BC_NOARG, kw_line);
                 consume_end_stmt();
                 break;
@@ -767,7 +722,7 @@ private:
                 consume(TK("@id"));
                 int dummy_t = ctx()->add_name(prev().str(), NAME_SPECIAL);
                 if(match(TK("(")) && !match(TK(")"))){
-                    EXPR(EXPR_RVALUE); consume(TK(")"));
+                    EXPR(true); consume(TK(")"));
                 }else{
                     ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE);
                 }
@@ -775,7 +730,7 @@ private:
                 consume_end_stmt();
             } break;
             case TK("with"): {
-                EXPR(EXPR_RVALUE);
+                EXPR(true);
                 consume(TK("as"));
                 consume(TK("@id"));
                 int index = ctx()->add_name(prev().str(), name_scope());
@@ -953,6 +908,7 @@ public:
         if(mode()==EVAL_MODE) {
             EXPR_TUPLE();
             consume(TK("@eof"));
+            ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
             pop_context();
             return code;
         }else if(mode()==JSON_MODE){
@@ -962,6 +918,7 @@ public:
             else if(match(TK("["))) exprList();
             else SyntaxError("expect a JSON object or array");
             consume(TK("@eof"));
+            ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
             pop_context();
             return code;
         }

+ 1 - 0
src/expr.h

@@ -343,6 +343,7 @@ struct AttribExpr: Expr{
 };
 
 struct CallExpr: Expr{
+    Expr_ callable;
     std::vector<Expr_> args;
     std::vector<std::pair<Str, Expr_>> kwargs;
     Str str() const override { return "()"; }

+ 0 - 4
src/frame.h

@@ -53,10 +53,6 @@ struct Frame {
     //     return ss.str();
     // }
 
-    bool has_next_bytecode() const {
-        return _next_ip < co->codes.size();
-    }
-
     PyObject* pop(){
 #if DEBUG_EXTRA_CHECK
         if(_data.empty()) throw std::runtime_error("_data.empty() is true");