From 88c0102e79fc594ac5105d5e2051fae85604b52d Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Fri, 19 Jan 2024 20:31:12 +0800 Subject: [PATCH] fix https://github.com/blueloveTH/pocketpy/issues/192 --- include/pocketpy/compiler.h | 6 ++--- src/compiler.cpp | 52 ++++++++++++++++++++++--------------- src/pocketpy.cpp | 10 +++++++ tests/05_list.py | 15 +++++++++++ 4 files changed, 59 insertions(+), 24 deletions(-) diff --git a/include/pocketpy/compiler.h b/include/pocketpy/compiler.h index 98ef424e..7211ae30 100644 --- a/include/pocketpy/compiler.h +++ b/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 @@ -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(); diff --git a/src/compiler.cpp b/src/compiler.cpp index dbaeb1f1..74c14eca 100644 --- a/src/compiler.cpp +++ b/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 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(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(); - if(is_expression()){ // : + if(is_expression()){ // : EXPR(); slice->stop = ctx()->s_expr.popx(); // try optional step - if(match(TK(":"))){ + if(match(TK(":"))){ // :: EXPR(); slice->step = ctx()->s_expr.popx(); } - } + }else if(match(TK(":"))){ + if(is_expression()){ // :: + EXPR(); + slice->step = ctx()->s_expr.popx(); + } // else :: + } // else : ctx()->s_expr.push(std::move(slice)); } void Compiler::exprSlice1() { auto slice = make_expr(); slice->start = ctx()->s_expr.popx(); - if(is_expression()){ // : + if(is_expression()){ // : EXPR(); slice->stop = ctx()->s_expr.popx(); // try optional step - if(match(TK(":"))){ + if(match(TK(":"))){ // :: EXPR(); slice->step = ctx()->s_expr.popx(); } - } + }else if(match(TK(":"))){ // :: + EXPR(); + slice->step = ctx()->s_expr.popx(); + } // else : ctx()->s_expr.push(std::move(slice)); } void Compiler::exprSubscr() { auto e = make_expr(); - e->a = ctx()->s_expr.popx(); // a[...] - EXPR_TUPLE(); // a[] - 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[] + 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() { diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index e245fe3a..2b2a413b 100644 --- a/src/pocketpy.cpp +++ b/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; diff --git a/tests/05_list.py b/tests/05_list.py index 91ec191a..52227ee0 100644 --- a/tests/05_list.py +++ b/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)) +