diff --git a/include/pocketpy/common.h b/include/pocketpy/common.h index 29c7c930..cb3c3ca1 100644 --- a/include/pocketpy/common.h +++ b/include/pocketpy/common.h @@ -21,7 +21,7 @@ #include #include -#define PK_VERSION "1.1.8" +#define PK_VERSION "1.1.9" #include "config.h" #include "export.h" diff --git a/include/pocketpy/opcodes.h b/include/pocketpy/opcodes.h index cfbb448e..1d34506b 100644 --- a/include/pocketpy/opcodes.h +++ b/include/pocketpy/opcodes.h @@ -89,6 +89,7 @@ OPCODE(LOOP_BREAK) OPCODE(GOTO) /**************************/ OPCODE(EVAL) +OPCODE(REPR) OPCODE(CALL) OPCODE(CALL_TP) OPCODE(RETURN_VALUE) diff --git a/src/ceval.cpp b/src/ceval.cpp index 403227d8..a580b7a7 100644 --- a/src/ceval.cpp +++ b/src/ceval.cpp @@ -498,6 +498,9 @@ __NEXT_STEP:; _0 = builtins->attr(pk_id_eval); TOP() = call(_0, TOP()); DISPATCH(); + TARGET(REPR) + TOP() = py_repr(TOP()); + DISPATCH(); TARGET(CALL) _0 = vectorcall( byte.arg & 0xFFFF, // ARGC diff --git a/src/expr.cpp b/src/expr.cpp index 28cb62b8..929afdcc 100644 --- a/src/expr.cpp +++ b/src/expr.cpp @@ -351,6 +351,14 @@ namespace pkpy{ void FStringExpr::_load_simple_expr(CodeEmitContext* ctx, Str expr){ + bool repr = false; + if(expr.size>=2 && expr.end()[-2]=='!'){ + switch(expr.end()[-1]){ + case 'r': repr = true; expr = expr.substr(0, expr.size-2); break; + case 's': repr = false; expr = expr.substr(0, expr.size-2); break; + default: break; // nothing happens + } + } // name or name.name std::regex pattern(R"(^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*){0,1}$)"); if(std::regex_match(expr.str(), pattern)){ @@ -368,6 +376,9 @@ namespace pkpy{ ctx->emit(OP_LOAD_CONST, index, line); ctx->emit(OP_EVAL, BC_NOARG, line); } + if(repr){ + ctx->emit(OP_REPR, BC_NOARG, line); + } } void FStringExpr::emit(CodeEmitContext* ctx){ diff --git a/tests/25_rawstring.py b/tests/25_rawstring.py index c3fa1f7a..8cf352ec 100644 --- a/tests/25_rawstring.py +++ b/tests/25_rawstring.py @@ -71,4 +71,31 @@ assert f'{"test":*>10}' == '******test' assert f'{"test":*<10}' == 'test******' assert f'{"test":*^10}' == '***test***' assert f'{"test":*^11}' == '***test****' -assert f'{12345:0>10}' == '0000012345' \ No newline at end of file +assert f'{12345:0>10}' == '0000012345' + +assert f'{obj.b!r:10}' == "'123' " +assert f'{obj.b!r:*>10}' == "*****'123'" +assert f'{obj.b!r:1}' == "'123'" +assert f'{obj.b!r:10s}' == "'123' " + +assert f'{"text"!r:10}' == "'text' " +assert f'{"test"!r:*>10}' == "****'test'" +assert f'{"test"!r:*<10}' == "'test'****" +assert f'{"test"!r:*^10}' == "**'test'**" +assert f'{"test"!r:*^11}' == "**'test'***" +assert f'{12345!r:0>10}' == "0000012345" + +class A: + def __repr__(self): + return 'A()' + def __str__(self): + return 'A' + +a = A() +assert f'{a!r:10}' == 'A() ' +assert f'{a!s:10}' == 'A ' +assert f'{a:10}' == 'A ' + +assert f'{A()!r:10}' == 'A() ' +assert f'{A()!s:10}' == 'A ' +assert f'{A():10}' == 'A ' \ No newline at end of file