Explorar el Código

fix https://github.com/blueloveTH/pocketpy/issues/192

blueloveTH hace 2 años
padre
commit
88c0102e79
Se han modificado 4 ficheros con 59 adiciones y 24 borrados
  1. 3 3
      include/pocketpy/compiler.h
  2. 31 21
      src/compiler.cpp
  3. 10 0
      src/pocketpy.cpp
  4. 15 0
      tests/05_list.py

+ 3 - 3
include/pocketpy/compiler.h

@@ -57,7 +57,7 @@ class Compiler {
 
     /*************************************************/
     void EXPR();
-    void EXPR_TUPLE();
+    void EXPR_TUPLE(bool allow_slice=false);
     Expr_ EXPR_VARS();  // special case for `for loop` and `comp`
 
     template <typename T, typename... Args>
@@ -111,8 +111,8 @@ class Compiler {
     void compile_block_body(void (Compiler::*callback)()=nullptr);
     void compile_normal_import();
     void compile_from_import();
-    bool is_expression();
-    void parse_expression(int precedence, bool push_stack=true);
+    bool is_expression(bool allow_slice=false);
+    void parse_expression(int precedence, bool allow_slice=false);
     void compile_if_stmt();
     void compile_while_loop();
     void compile_for_loop();

+ 31 - 21
src/compiler.cpp

@@ -169,16 +169,17 @@ namespace pkpy{
         parse_expression(PREC_LOWEST+1);
     }
 
-    void Compiler::EXPR_TUPLE() {
-        EXPR();
+    void Compiler::EXPR_TUPLE(bool allow_slice) {
+        parse_expression(PREC_LOWEST+1, allow_slice);
         if(!match(TK(","))) return;
         // tuple expression
         std::vector<Expr_> items;
         items.push_back(ctx()->s_expr.popx());
         do {
             if(curr().brackets_level) match_newlines_repl();
-            if(!is_expression()) break;
-            EXPR(); items.push_back(ctx()->s_expr.popx());
+            if(!is_expression(allow_slice)) break;
+            parse_expression(PREC_LOWEST+1, allow_slice);
+            items.push_back(ctx()->s_expr.popx());
             if(curr().brackets_level) match_newlines_repl();
         } while(match(TK(",")));
         ctx()->s_expr.push(make_expr<TupleExpr>(std::move(items)));
@@ -223,7 +224,8 @@ namespace pkpy{
             consume(TK(":"));
         }
         // https://github.com/blueloveTH/pocketpy/issues/37
-        parse_expression(PREC_LAMBDA + 1, false);
+        parse_expression(PREC_LAMBDA + 1);
+        ctx()->emit_expr();
         ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
         pop_context();
         ctx()->s_expr.push(std::move(e));
@@ -418,38 +420,48 @@ namespace pkpy{
 
     void Compiler::exprSlice0() {
         auto slice = make_expr<SliceExpr>();
-        if(is_expression()){    // :<expr>
+        if(is_expression()){        // :<stop>
             EXPR();
             slice->stop = ctx()->s_expr.popx();
             // try optional step
-            if(match(TK(":"))){
+            if(match(TK(":"))){     // :<stop>:<step>
                 EXPR();
                 slice->step = ctx()->s_expr.popx();
             }
-        }
+        }else if(match(TK(":"))){
+            if(is_expression()){    // ::<step>
+                EXPR();
+                slice->step = ctx()->s_expr.popx();
+            }   // else ::
+        }   // else :
         ctx()->s_expr.push(std::move(slice));
     }
 
     void Compiler::exprSlice1() {
         auto slice = make_expr<SliceExpr>();
         slice->start = ctx()->s_expr.popx();
-        if(is_expression()){    // <expr>:<expr>
+        if(is_expression()){        // <start>:<stop>
             EXPR();
             slice->stop = ctx()->s_expr.popx();
             // try optional step
-            if(match(TK(":"))){
+            if(match(TK(":"))){     // <start>:<stop>:<step>
                 EXPR();
                 slice->step = ctx()->s_expr.popx();
             }
-        }
+        }else if(match(TK(":"))){   // <start>::<step>
+            EXPR();
+            slice->step = ctx()->s_expr.popx();
+        }   // else <start>:
         ctx()->s_expr.push(std::move(slice));
     }
     
     void Compiler::exprSubscr() {
         auto e = make_expr<SubscrExpr>();
-        e->a = ctx()->s_expr.popx();        // a[...]
-        EXPR_TUPLE();                       // a[<expr>]
-        e->b = ctx()->s_expr.popx();
+        match_newlines_repl();
+        e->a = ctx()->s_expr.popx();        // a
+        EXPR_TUPLE(true);
+        e->b = ctx()->s_expr.popx();        // a[<expr>]
+        match_newlines_repl();
         consume(TK("]"));
         ctx()->s_expr.push(std::move(e));
     }
@@ -561,27 +573,25 @@ __EAT_DOTS_END:
         consume_end_stmt();
     }
 
-    bool Compiler::is_expression(){
+    bool Compiler::is_expression(bool allow_slice){
         PrattCallback prefix = rules[curr().type].prefix;
-        // slice expression is restricted to be used in subscript
-        return prefix != nullptr && curr().type != TK(":");
+        return prefix != nullptr && (allow_slice || curr().type!=TK(":"));
     }
 
-    void Compiler::parse_expression(int precedence, bool push_stack) {
+    void Compiler::parse_expression(int precedence, bool allow_slice) {
         PrattCallback prefix = rules[curr().type].prefix;
-        if (prefix == nullptr || curr().type == TK(":")){
+        if (prefix==nullptr || (curr().type==TK(":") && !allow_slice)){
             SyntaxError(Str("expected an expression, got ") + TK_STR(curr().type));
         }
         advance();
         (this->*prefix)();
-        while (rules[curr().type].precedence >= precedence && curr().type != TK(":")) {
+        while (rules[curr().type].precedence >= precedence && (allow_slice || curr().type!=TK(":"))) {
             TokenIndex op = curr().type;
             advance();
             PrattCallback infix = rules[op].infix;
             PK_ASSERT(infix != nullptr);
             (this->*infix)();
         }
-        if(!push_stack) ctx()->emit_expr();
     }
 
     void Compiler::compile_if_stmt() {

+ 10 - 0
src/pocketpy.cpp

@@ -1016,6 +1016,16 @@ void init_builtins(VM* _vm) {
         return VAR(Slice(args[1], args[2], args[3]));
     });
 
+    _vm->bind__eq__(VM::tp_slice, [](VM* vm, PyObject* _0, PyObject* _1){
+        const Slice& self = _CAST(Slice&, _0);
+        if(!is_non_tagged_type(_1, vm->tp_slice)) return vm->NotImplemented;
+        const Slice& other = _CAST(Slice&, _1);
+        if(vm->py_ne(self.start, other.start)) return vm->False;
+        if(vm->py_ne(self.stop, other.stop)) return vm->False;
+        if(vm->py_ne(self.step, other.step)) return vm->False;
+        return vm->True;
+    });
+
     _vm->bind__repr__(VM::tp_slice, [](VM* vm, PyObject* _0) {
         const Slice& self = _CAST(Slice&, _0);
         SStream ss;

+ 15 - 0
tests/05_list.py

@@ -101,3 +101,18 @@ a.append(0)
 a.append([1, 2, a])
 
 assert repr(a) == "[0, [1, 2, [...]]]"
+
+# slice extras
+class A:
+    def __getitem__(self, index):
+        return index
+    
+assert A()[1:2, 3] == (slice(1, 2, None), 3)
+assert A()[1:2, 3:4] == (slice(1, 2, None), slice(3, 4, None))
+assert A()[1:2, 3:4, 5] == (slice(1, 2, None), slice(3, 4, None), 5)
+assert A()[:, :] == (slice(None, None, None), slice(None, None, None))
+assert A()[::, :] == (slice(None, None, None), slice(None, None, None))
+assert A()[::, :2] == (slice(None, None, None), slice(None, 2, None))
+assert A()['b':'c':1, :] == (slice('b', 'c', 1), slice(None, None, None))
+assert A()[1:2, :A()[3:4, ::-1]] == (slice(1, 2, None), slice(None, (slice(3, 4, None), slice(None, None, -1)), None))
+