support bytes literal, e.g. b'\xff\12'

This commit is contained in:
blueloveTH 2023-07-16 23:39:04 +08:00
parent d5711da2ad
commit 9732828e85
9 changed files with 42 additions and 4 deletions

View File

@ -85,6 +85,7 @@ class Compiler {
void exprLiteral(); void exprLiteral();
void exprLong(); void exprLong();
void exprBytes();
void exprFString(); void exprFString();
void exprLambda(); void exprLambda();
void exprTuple(); void exprTuple();

View File

@ -134,6 +134,13 @@ struct LongExpr: Expr{
void emit(CodeEmitContext* ctx) override; void emit(CodeEmitContext* ctx) override;
}; };
struct BytesExpr: Expr{
Str s;
BytesExpr(const Str& s): s(s) {}
std::string str() const override { return s.str(); }
void emit(CodeEmitContext* ctx) override;
};
// @num, @str which needs to invoke OP_LOAD_CONST // @num, @str which needs to invoke OP_LOAD_CONST
struct LiteralExpr: Expr{ struct LiteralExpr: Expr{
TokenValue value; TokenValue value;

View File

@ -11,7 +11,7 @@ typedef uint8_t TokenIndex;
constexpr const char* kTokens[] = { constexpr const char* kTokens[] = {
"is not", "not in", "yield from", "is not", "not in", "yield from",
"@eof", "@eol", "@sof", "@eof", "@eol", "@sof",
"@id", "@num", "@str", "@fstr", "@long", "@id", "@num", "@str", "@fstr", "@long", "@bytes",
"@indent", "@dedent", "@indent", "@dedent",
/*****************************************/ /*****************************************/
"+", "+=", "-", "-=", // (INPLACE_OP - 1) can get '=' removed "+", "+=", "-", "-=", // (INPLACE_OP - 1) can get '=' removed
@ -100,7 +100,7 @@ enum Precedence {
PREC_PRIMARY, PREC_PRIMARY,
}; };
enum StringType { NORMAL_STRING, RAW_STRING, F_STRING }; enum StringType { NORMAL_STRING, RAW_STRING, F_STRING, NORMAL_BYTES };
struct Lexer { struct Lexer {
shared_ptr<SourceData> src; shared_ptr<SourceData> src;

View File

@ -39,6 +39,7 @@ OPCODE(DELETE_ATTR)
OPCODE(DELETE_SUBSCR) OPCODE(DELETE_SUBSCR)
/**************************/ /**************************/
OPCODE(BUILD_LONG) OPCODE(BUILD_LONG)
OPCODE(BUILD_BYTES)
OPCODE(BUILD_TUPLE) OPCODE(BUILD_TUPLE)
OPCODE(BUILD_LIST) OPCODE(BUILD_LIST)
OPCODE(BUILD_DICT) OPCODE(BUILD_DICT)

View File

@ -247,6 +247,12 @@ __NEXT_STEP:;
if(_0 == nullptr) AttributeError(builtins, m_long); if(_0 == nullptr) AttributeError(builtins, m_long);
TOP() = call(_0, TOP()); TOP() = call(_0, TOP());
} DISPATCH(); } DISPATCH();
TARGET(BUILD_BYTES) {
const Str& s = CAST(Str&, TOP());
std::vector<char> buffer(s.size);
memcpy(buffer.data(), s.data, s.size);
TOP() = VAR(Bytes(std::move(buffer)));
} DISPATCH();
TARGET(BUILD_TUPLE) TARGET(BUILD_TUPLE)
_0 = VAR(STACK_VIEW(byte.arg).to_tuple()); _0 = VAR(STACK_VIEW(byte.arg).to_tuple());
STACK_SHRINK(byte.arg); STACK_SHRINK(byte.arg);

View File

@ -87,6 +87,7 @@ namespace pkpy{
rules[TK("@str")] = { METHOD(exprLiteral), NO_INFIX }; rules[TK("@str")] = { METHOD(exprLiteral), NO_INFIX };
rules[TK("@fstr")] = { METHOD(exprFString), NO_INFIX }; rules[TK("@fstr")] = { METHOD(exprFString), NO_INFIX };
rules[TK("@long")] = { METHOD(exprLong), NO_INFIX }; rules[TK("@long")] = { METHOD(exprLong), NO_INFIX };
rules[TK("@bytes")] = { METHOD(exprBytes), NO_INFIX };
#undef METHOD #undef METHOD
#undef NO_INFIX #undef NO_INFIX
} }
@ -159,6 +160,10 @@ namespace pkpy{
ctx()->s_expr.push(make_expr<LongExpr>(prev().str())); ctx()->s_expr.push(make_expr<LongExpr>(prev().str()));
} }
void Compiler::exprBytes(){
ctx()->s_expr.push(make_expr<BytesExpr>(std::get<Str>(prev().value)));
}
void Compiler::exprFString(){ void Compiler::exprFString(){
ctx()->s_expr.push(make_expr<FStringExpr>(std::get<Str>(prev().value))); ctx()->s_expr.push(make_expr<FStringExpr>(std::get<Str>(prev().value)));
} }

View File

@ -190,6 +190,12 @@ namespace pkpy{
ctx->emit(OP_BUILD_LONG, BC_NOARG, line); ctx->emit(OP_BUILD_LONG, BC_NOARG, line);
} }
void BytesExpr::emit(CodeEmitContext* ctx) {
VM* vm = ctx->vm;
ctx->emit(OP_LOAD_CONST, ctx->add_const(VAR(s)), line);
ctx->emit(OP_BUILD_BYTES, BC_NOARG, line);
}
std::string LiteralExpr::str() const{ std::string LiteralExpr::str() const{
if(std::holds_alternative<i64>(value)){ if(std::holds_alternative<i64>(value)){
return std::to_string(std::get<i64>(value)); return std::to_string(std::get<i64>(value));

View File

@ -236,9 +236,13 @@ namespace pkpy{
Str s = eat_string_until(quote, type == RAW_STRING); Str s = eat_string_until(quote, type == RAW_STRING);
if(type == F_STRING){ if(type == F_STRING){
add_token(TK("@fstr"), s); add_token(TK("@fstr"), s);
}else{ return;
add_token(TK("@str"), s);
} }
if(type == NORMAL_BYTES){
add_token(TK("@bytes"), s);
return;
}
add_token(TK("@str"), s);
} }
void Lexer::eat_number() { void Lexer::eat_number() {
@ -385,6 +389,9 @@ namespace pkpy{
}else if(c == 'r'){ }else if(c == 'r'){
if(matchchar('\'')) {eat_string('\'', RAW_STRING); return true;} if(matchchar('\'')) {eat_string('\'', RAW_STRING); return true;}
if(matchchar('"')) {eat_string('"', RAW_STRING); return true;} if(matchchar('"')) {eat_string('"', RAW_STRING); return true;}
}else if(c == 'b'){
if(matchchar('\'')) {eat_string('\'', NORMAL_BYTES); return true;}
if(matchchar('"')) {eat_string('"', NORMAL_BYTES); return true;}
} }
if (c >= '0' && c <= '9') { if (c >= '0' && c <= '9') {
eat_number(); eat_number();

5
tests/10_bytes.py Normal file
View File

@ -0,0 +1,5 @@
a = '12345'
assert a.encode() == b'12345'
assert b'\xff\xee' != b'1234'
assert b'\xff\xee' == b'\xff\xee'