From 291ffd26713440f8404ea2b068ea0e8e6c501166 Mon Sep 17 00:00:00 2001 From: Windel Bouwman Date: Mon, 19 Aug 2019 11:27:13 +0200 Subject: [PATCH] Add support for ascii formatting of f-strings. --- tests/snippets/fstrings.py | 8 ++++++++ vm/src/builtins.rs | 11 +++++++++-- vm/src/eval.rs | 11 ++++------- vm/src/frame.rs | 2 +- vm/src/vm.rs | 9 ++++++++- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/tests/snippets/fstrings.py b/tests/snippets/fstrings.py index 445911c68..67da5e1a7 100644 --- a/tests/snippets/fstrings.py +++ b/tests/snippets/fstrings.py @@ -39,9 +39,17 @@ v = Value() assert f'{v}' == 'foo' assert f'{v!r}' == 'bar' assert f'{v!s}' == 'baz' +assert f'{v!a}' == 'bar' # advanced expressions: assert f'{True or True}' == 'True' assert f'{1 == 1}' == 'True' assert f'{"0" if True else "1"}' == '0' + +# Test ascii representation of unicodes: +v = "\u262e" +assert f'>{v}' == '>\u262e' +assert f'>{v!r}' == ">'\u262e'" +assert f'>{v!s}' == '>\u262e' +assert f'>{v!a}' == r">'\u262e'" diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 33ad00044..6b66633ad 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -60,8 +60,15 @@ fn builtin_any(iterable: PyIterable, vm: &VirtualMachine) -> PyResult PyResult { let repr = vm.to_repr(&obj)?; + let ascii = to_ascii(&repr.value); + Ok(ascii) +} + +/// Convert a string to ascii compatible, escaping unicodes into escape +/// sequences. +pub fn to_ascii(value: &str) -> String { let mut ascii = String::new(); - for c in repr.value.chars() { + for c in value.chars() { if c.is_ascii() { ascii.push(c) } else { @@ -74,7 +81,7 @@ fn builtin_ascii(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { ascii.push_str(&hex) } } - Ok(ascii) + ascii } fn builtin_bin(x: PyIntRef, _vm: &VirtualMachine) -> String { diff --git a/vm/src/eval.rs b/vm/src/eval.rs index 8feeb8741..3d998f8b4 100644 --- a/vm/src/eval.rs +++ b/vm/src/eval.rs @@ -17,17 +17,14 @@ pub fn eval(vm: &VirtualMachine, source: &str, scope: Scope, source_path: &str) mod tests { use super::eval; use super::VirtualMachine; + use crate::pyobject::IdProtocol; #[test] fn test_print_42() { let source = String::from("print('Hello world')"); - let vm: VirtualMachine = Default::default(); + let vm = VirtualMachine::default(); let vars = vm.new_scope_with_builtins(); - let _result = eval(&vm, &source, vars, ""); - - // TODO: check result? - //assert_eq!( - // parse_ast, - // ); + let result = eval(&vm, &source, vars, "").expect("this should pass"); + assert!(result.is(&vm.ctx.none())); } } diff --git a/vm/src/frame.rs b/vm/src/frame.rs index f205f4089..c8f93d55e 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -666,7 +666,7 @@ impl Frame { let value = match conversion { Some(Str) => vm.to_str(&self.pop_value())?.into_object(), Some(Repr) => vm.to_repr(&self.pop_value())?.into_object(), - Some(Ascii) => self.pop_value(), // TODO + Some(Ascii) => vm.to_ascii(&self.pop_value())?, None => self.pop_value(), }; diff --git a/vm/src/vm.rs b/vm/src/vm.rs index ccb18f2d9..751b0a582 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -11,7 +11,7 @@ use std::fmt; use std::rc::Rc; use std::sync::{Mutex, MutexGuard}; -use crate::builtins; +use crate::builtins::{self, to_ascii}; use crate::bytecode; use crate::frame::{ExecutionResult, Frame, FrameRef}; use crate::frozen; @@ -445,6 +445,13 @@ impl VirtualMachine { TryFromObject::try_from_object(self, repr) } + pub fn to_ascii(&self, obj: &PyObjectRef) -> PyResult { + let repr = self.call_method(obj, "__repr__", vec![])?; + let repr: PyStringRef = TryFromObject::try_from_object(self, repr)?; + let ascii = to_ascii(&repr.value); + Ok(self.new_str(ascii)) + } + pub fn import(&self, module: &str, from_list: &PyObjectRef, level: usize) -> PyResult { // if the import inputs seem weird, e.g a package import or something, rather than just // a straight `import ident`