diff --git a/src/interpreted/interpreter.py b/src/interpreted/interpreter.py index 54ab80b..d7518f9 100644 --- a/src/interpreted/interpreter.py +++ b/src/interpreted/interpreter.py @@ -267,40 +267,7 @@ def __repr__(self) -> str: return f"Value({self.value!r})" def as_string(self) -> None: - if not isinstance(self.value, str): - return str(self.value) - - transformed_chars = [] - index = 0 - while index < len(self.value): - char = self.value[index] - if char != "\\": - transformed_chars.append(char) - index += 1 - else: - next_char = self.value[index + 1] - if next_char == "x": - chars = self.value[index + 2 : index + 4] - index += 4 - elif next_char == "u": - chars = self.value[index + 2 : index + 6] - index += 6 - elif next_char == "U": - chars = self.value[index + 2 : index + 10] - index += 10 - else: - transformed_chars.extend(["\\", next_char]) - index += 2 - - try: - unicode_char = chr(int(chars, 16)) - transformed_chars.append(unicode_char) - except ValueError as exc: - raise InterpreterError( - f"Invalid unicode escape: \\{next_char}{chars}" - ) from exc - - return "".join(transformed_chars) + return str(self.value) def repr(self) -> None: return repr(self.value) @@ -665,11 +632,13 @@ def visit_Subscript(self, node: Subscript) -> Object: and isinstance(key, Value) ): return Value(obj.value[key.value]) - if (isinstance(obj, Value) + if ( + isinstance(obj, Value) and isinstance(obj.value, bytes) - and isinstance(key, Value)): + and isinstance(key, Value) + ): return Value(obj.value[key.value]) - + raise InterpreterError(f"{type(obj).__name__} object has no key {key.repr()}") def visit_Attribute(self, node: Attribute) -> Object: diff --git a/src/interpreted/parser.py b/src/interpreted/parser.py index db9693e..c867175 100644 --- a/src/interpreted/parser.py +++ b/src/interpreted/parser.py @@ -1,5 +1,6 @@ from __future__ import annotations +import ast import sys from keyword import iskeyword @@ -529,8 +530,8 @@ def parse_literal(self) -> Expression: if self.match_type(TokenType.STRING): token = self.current() - unquoted_string = unquote(token.string) - assert isinstance(unquoted_string, str) + unquoted_string = ast.literal_eval(token.string) + assert isinstance(unquoted_string, (str, bytes)) return Constant(unquoted_string) if self.match_op("("): diff --git a/tests/interpreted_test.py b/tests/interpreted_test.py index df80faa..559337e 100644 --- a/tests/interpreted_test.py +++ b/tests/interpreted_test.py @@ -16,6 +16,21 @@ (r"print('foo \U00002603 bar')", "foo ☃ bar\n"), (r"print('foo \U0001F643 bar')", "foo 🙃 bar\n"), (r"print('foo \x41 \U0001F643 bar')", "foo A 🙃 bar\n"), + ( + """\ + a = b'abc' + print(a) + print(a[0]) + print(a * 2) + print(a + b'd') + """, + """\ + b'abc' + 97 + b'abcabc' + b'abcd' + """, + ), ( """\ def foo(x): @@ -75,7 +90,7 @@ def test_interpret(source, output) -> None: ) assert process.stderr == b"" - assert process.stdout.decode() == output + assert process.stdout.decode() == dedent(output) def test_file_not_found() -> None: