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_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();

View File

@ -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() {

View File

@ -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;

View File

@ -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))