raise error on literal ints overflow

This commit is contained in:
blueloveTH 2024-03-04 16:48:47 +08:00
parent e3fa25d774
commit 7f7e1a14ee
4 changed files with 44 additions and 25 deletions

View File

@ -136,6 +136,13 @@ struct Lexer {
std::vector<Token> run(); std::vector<Token> run();
}; };
bool parse_int(std::string_view text, i64* out, int base);
enum class IntParsingResult{
Success,
Failure,
Overflow,
};
IntParsingResult parse_int(std::string_view text, i64* out, int base);
} // namespace pkpy } // namespace pkpy

View File

@ -284,9 +284,15 @@ static bool is_unicode_Lo_char(uint32_t c) {
} }
// try integer // try integer
i64 int_out; i64 int_out;
if(parse_int(text, &int_out, -1)){ switch(parse_int(text, &int_out, -1)){
case IntParsingResult::Success:
add_token(TK("@num"), int_out); add_token(TK("@num"), int_out);
return; return;
case IntParsingResult::Overflow:
SyntaxError("integer literal too large");
return;
case IntParsingResult::Failure:
break; // do nothing
} }
} }
@ -476,7 +482,7 @@ static bool is_unicode_Lo_char(uint32_t c) {
return std::move(nexts); return std::move(nexts);
} }
bool parse_int(std::string_view text, i64* out, int base){ IntParsingResult parse_int(std::string_view text, i64* out, int base){
*out = 0; *out = 0;
const auto f_startswith_2 = [](std::string_view t, const char* prefix) -> bool{ const auto f_startswith_2 = [](std::string_view t, const char* prefix) -> bool{
@ -493,63 +499,63 @@ bool parse_int(std::string_view text, i64* out, int base){
if(base == 10){ if(base == 10){
// 10-base 12334 // 10-base 12334
if(text.length() == 0) return false; if(text.length() == 0) return IntParsingResult::Failure;
for(char c : text){ for(char c : text){
if(c >= '0' && c <= '9'){ if(c >= '0' && c <= '9'){
*out = (*out * 10) + (c - '0'); *out = (*out * 10) + (c - '0');
if(*out < 0) return false; // overflow if(*out < 0) return IntParsingResult::Overflow;
}else{ }else{
return false; return IntParsingResult::Failure;
} }
} }
return true; return IntParsingResult::Success;
}else if(base == 2){ }else if(base == 2){
// 2-base 0b101010 // 2-base 0b101010
if(f_startswith_2(text, "0b")) text.remove_prefix(2); if(f_startswith_2(text, "0b")) text.remove_prefix(2);
if(text.length() == 0) return false; if(text.length() == 0) return IntParsingResult::Failure;
for(char c : text){ for(char c : text){
if(c == '0' || c == '1'){ if(c == '0' || c == '1'){
*out = (*out << 1) | (c - '0'); *out = (*out << 1) | (c - '0');
if(*out < 0) return false; // overflow if(*out < 0) return IntParsingResult::Overflow;
}else{ }else{
return false; return IntParsingResult::Failure;
} }
} }
return true; return IntParsingResult::Success;
}else if(base == 8){ }else if(base == 8){
// 8-base 0o123 // 8-base 0o123
if(f_startswith_2(text, "0o")) text.remove_prefix(2); if(f_startswith_2(text, "0o")) text.remove_prefix(2);
if(text.length() == 0) return false; if(text.length() == 0) return IntParsingResult::Failure;
for(char c : text){ for(char c : text){
if(c >= '0' && c <= '7'){ if(c >= '0' && c <= '7'){
*out = (*out << 3) | (c - '0'); *out = (*out << 3) | (c - '0');
if(*out < 0) return false; // overflow if(*out < 0) return IntParsingResult::Overflow;
}else{ }else{
return false; return IntParsingResult::Failure;
} }
} }
return true; return IntParsingResult::Success;
}else if(base == 16){ }else if(base == 16){
// 16-base 0x123 // 16-base 0x123
if(f_startswith_2(text, "0x")) text.remove_prefix(2); if(f_startswith_2(text, "0x")) text.remove_prefix(2);
if(text.length() == 0) return false; if(text.length() == 0) return IntParsingResult::Failure;
for(char c : text){ for(char c : text){
if(c >= '0' && c <= '9'){ if(c >= '0' && c <= '9'){
*out = (*out << 4) | (c - '0'); *out = (*out << 4) | (c - '0');
if(*out < 0) return false; // overflow if(*out < 0) return IntParsingResult::Overflow;
}else if(c >= 'a' && c <= 'f'){ }else if(c >= 'a' && c <= 'f'){
*out = (*out << 4) | (c - 'a' + 10); *out = (*out << 4) | (c - 'a' + 10);
if(*out < 0) return false; // overflow if(*out < 0) return IntParsingResult::Overflow;
}else if(c >= 'A' && c <= 'F'){ }else if(c >= 'A' && c <= 'F'){
*out = (*out << 4) | (c - 'A' + 10); *out = (*out << 4) | (c - 'A' + 10);
if(*out < 0) return false; // overflow if(*out < 0) return IntParsingResult::Overflow;
}else{ }else{
return false; return IntParsingResult::Failure;
} }
} }
return true; return IntParsingResult::Success;
} }
return false; return IntParsingResult::Failure;
} }
} // namespace pkpy } // namespace pkpy

View File

@ -415,7 +415,7 @@ void init_builtins(VM* _vm) {
sv.remove_prefix(1); sv.remove_prefix(1);
} }
i64 val; i64 val;
if(!parse_int(sv, &val, base)){ if(parse_int(sv, &val, base) != IntParsingResult::Success){
vm->ValueError(_S("invalid literal for int() with base ", base, ": ", s.escape())); vm->ValueError(_S("invalid literal for int() with base ", base, ": ", s.escape()));
} }
if(negative) val = -val; if(negative) val = -val;

View File

@ -124,3 +124,9 @@ except ZeroDivisionError:
pass pass
assert not 1 < 2 > 3 assert not 1 < 2 > 3
try:
eval("231231312312312312312312312312312312314354657553423345632")
exit(1)
except SyntaxError:
pass