Skip to content

Commit 5b51c3c

Browse files
Add support for base in int() (#2338)
1 parent f76dff7 commit 5b51c3c

File tree

2 files changed

+87
-28
lines changed

2 files changed

+87
-28
lines changed

integration_tests/test_str_to_int.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,12 @@ def f():
2020
i = i32(int(s))
2121
assert i == -1234
2222

23+
assert i32(int("01010",10)) == 1010
24+
assert i32(int("01010",2)) == 10
25+
assert i32(int("Beef",16)) == 48879
26+
assert i32(int("0xE",16)) == 14
27+
assert i32(int("0xE",0)) == 14
28+
assert i32(int("123",0)) == 123
29+
assert i32(int("0bE",16)) == 190
30+
2331
f()

src/lpython/semantics/python_intrinsic_eval.h

Lines changed: 79 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,89 @@ struct IntrinsicNodeHandler {
4949
const Location &loc) {
5050
ASR::expr_t *arg = nullptr, *value = nullptr;
5151
ASR::ttype_t *type = nullptr;
52-
if (args.size() > 1) {
53-
throw SemanticError("Either 0 or 1 argument is expected in 'int()'",
52+
if (args.size() > 2) {
53+
throw SemanticError("'int()' takes at most 2 arguments (" + std::to_string(args.size()) + " given)",
5454
loc);
5555
}
56-
if (args.size() > 0) {
56+
if (args.size() >= 1) {
5757
arg = args[0].m_value;
5858
type = ASRUtils::expr_type(arg);
59+
if (ASRUtils::is_character(*type)) {
60+
int32_t base;
61+
if (args.size() == 1) {
62+
base = 10;
63+
} else {
64+
arg = args[1].m_value;
65+
type = ASRUtils::expr_type(arg);
66+
if (ASRUtils::is_integer(*type)) {
67+
base = ASR::down_cast<ASR::IntegerConstant_t>(
68+
ASRUtils::expr_value(arg))->m_n;
69+
if ((base != 0 && base < 2) || base > 36) {
70+
throw SemanticError("int() base must be >= 2 and <= 36, or 0", loc);
71+
}
72+
} else {
73+
throw SemanticError("'" + ASRUtils::type_to_str_python(type) + "' object cannot be interpreted as an integer",
74+
arg->base.loc);
75+
}
76+
}
77+
arg = args[0].m_value;
78+
type = ASRUtils::expr_type(arg);
79+
ASR::ttype_t *to_type = ASRUtils::TYPE(ASR::make_Integer_t(al, loc, 8));
80+
if (ASRUtils::expr_value(arg) != nullptr) {
81+
char *c = ASR::down_cast<ASR::StringConstant_t>(
82+
ASRUtils::expr_value(arg))->m_s;
83+
int ival = 0;
84+
bool zero_based = false;
85+
char *ch = c;
86+
if (*ch == '-') {
87+
ch++;
88+
}
89+
if (base == 0) {
90+
zero_based = true;
91+
if (*ch == '0') {
92+
ch++;
93+
if (*ch == 'x' || *ch == 'X') {
94+
base = 16;
95+
ch++;
96+
} else if (*ch == 'o' || *ch == 'O') {
97+
base = 8;
98+
ch++;
99+
} else if (*ch == 'b' || *ch == 'B') {
100+
base = 2;
101+
ch++;
102+
}
103+
} else {
104+
base = 10;
105+
}
106+
} else {
107+
if (*ch == '0' &&
108+
((base == 16 && (ch[1] == 'x'|| ch[1] == 'X')) ||
109+
(base == 8 && (ch[1] == 'o' || ch[1] == 'O')) ||
110+
(base == 2 && (ch[1] == 'b' || ch[1] == 'B')))) {
111+
ch += 2;
112+
}
113+
}
114+
while (*ch) {
115+
if (*ch == '.') {
116+
throw SemanticError("invalid literal for int() with base " + std::to_string(zero_based ? 0: base) + ": '" + std::string(c) + "'", arg->base.loc);
117+
}
118+
if (!((*ch >= '0' && (*ch <= std::min((int)'9', '0' + base - 1))) || (*ch >= 'A' && (*ch < 'A' + base - 10)) || (*ch >= 'a' && (*ch < 'a' + base - 10)))) {
119+
throw SemanticError("invalid literal for int() with base " + std::to_string(zero_based ? 0: base) + ": '" + std::string(c) + "'", arg->base.loc);
120+
}
121+
ch++;
122+
}
123+
ival = std::stoi(c,0,base);
124+
return (ASR::asr_t *)ASR::down_cast<ASR::expr_t>(ASR::make_IntegerConstant_t(al,
125+
loc, ival, to_type));
126+
}
127+
return (ASR::asr_t *)ASR::down_cast<ASR::expr_t>(ASR::make_Cast_t(
128+
al, loc, arg, ASR::cast_kindType::CharacterToInteger,
129+
to_type, value));
130+
} else {
131+
if (args.size() == 2) {
132+
throw SemanticError("int() can't convert non-string with explicit base", loc);
133+
}
134+
}
59135
}
60136
ASR::ttype_t *to_type = ASRUtils::TYPE(ASR::make_Integer_t(al, loc, 8));
61137
if (!arg) {
@@ -71,31 +147,6 @@ struct IntrinsicNodeHandler {
71147
return (ASR::asr_t *)ASR::down_cast<ASR::expr_t>(ASR::make_Cast_t(
72148
al, loc, arg, ASR::cast_kindType::RealToInteger,
73149
to_type, value));
74-
} else if (ASRUtils::is_character(*type)) {
75-
if (ASRUtils::expr_value(arg) != nullptr) {
76-
char *c = ASR::down_cast<ASR::StringConstant_t>(
77-
ASRUtils::expr_value(arg))->m_s;
78-
int ival = 0;
79-
char *ch = c;
80-
if (*ch == '-') {
81-
ch++;
82-
}
83-
while (*ch) {
84-
if (*ch == '.') {
85-
throw SemanticError("invalid literal for int() with base 10: '"+ std::string(c) + "'", arg->base.loc);
86-
}
87-
if (*ch < '0' || *ch > '9') {
88-
throw SemanticError("invalid literal for int() with base 10: '"+ std::string(c) + "'", arg->base.loc);
89-
}
90-
ch++;
91-
}
92-
ival = std::stoi(c);
93-
return (ASR::asr_t *)ASR::down_cast<ASR::expr_t>(ASR::make_IntegerConstant_t(al,
94-
loc, ival, to_type));
95-
}
96-
return (ASR::asr_t *)ASR::down_cast<ASR::expr_t>(ASR::make_Cast_t(
97-
al, loc, arg, ASR::cast_kindType::CharacterToInteger,
98-
to_type, value));
99150
} else if (ASRUtils::is_logical(*type)) {
100151
if (ASRUtils::expr_value(arg) != nullptr) {
101152
int32_t ival = ASR::down_cast<ASR::LogicalConstant_t>(

0 commit comments

Comments
 (0)