blueloveTH 2024-01-19 20:31:12 +08:00
parent d2becdb9f5
commit 88c0102e79
4 changed files with 59 additions and 24 deletions

View File

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

View File

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

View File

@ -1016,6 +1016,16 @@ void init_builtins(VM* _vm) {
return VAR(Slice(args[1], args[2], args[3])); 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) { _vm->bind__repr__(VM::tp_slice, [](VM* vm, PyObject* _0) {
const Slice& self = _CAST(Slice&, _0); const Slice& self = _CAST(Slice&, _0);
SStream ss; SStream ss;

View File

@ -101,3 +101,18 @@ a.append(0)
a.append([1, 2, a]) a.append([1, 2, a])
assert repr(a) == "[0, [1, 2, [...]]]" 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))