summaryrefslogtreecommitdiffstats
path: root/Python/compile.c
diff options
context:
space:
mode:
authorEric V. Smith <eric@trueblade.com>2015-11-03 17:45:05 (GMT)
committerEric V. Smith <eric@trueblade.com>2015-11-03 17:45:05 (GMT)
commita78c7954d549fba967a842143b4e3050ff488468 (patch)
tree26e0270948bb638d1b11dec80cfbc6397fdc2643 /Python/compile.c
parent2753a096e0365bf93e1fd3a3e20735f598c14e91 (diff)
downloadcpython-a78c7954d549fba967a842143b4e3050ff488468.zip
cpython-a78c7954d549fba967a842143b4e3050ff488468.tar.gz
cpython-a78c7954d549fba967a842143b4e3050ff488468.tar.bz2
Issue 25483: Add an opcode to make f-string formatting more robust.
Diffstat (limited to 'Python/compile.c')
-rw-r--r--Python/compile.c98
1 files changed, 33 insertions, 65 deletions
diff --git a/Python/compile.c b/Python/compile.c
index 5b53de3..030afed 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -1067,6 +1067,10 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
return 1;
case GET_YIELD_FROM_ITER:
return 0;
+ case FORMAT_VALUE:
+ /* If there's a fmt_spec on the stack, we go from 2->1,
+ else 1->1. */
+ return (oparg & FVS_MASK) == FVS_HAVE_SPEC ? -1 : 0;
default:
return PY_INVALID_STACK_EFFECT;
}
@@ -3241,83 +3245,47 @@ compiler_joined_str(struct compiler *c, expr_ty e)
return 1;
}
-/* Note that this code uses the builtin functions format(), str(),
- repr(), and ascii(). You can break this code, or make it do odd
- things, by redefining those functions. */
+/* Used to implement f-strings. Format a single value. */
static int
compiler_formatted_value(struct compiler *c, expr_ty e)
{
- PyObject *conversion_name = NULL;
-
- static PyObject *format_string;
- static PyObject *str_string;
- static PyObject *repr_string;
- static PyObject *ascii_string;
-
- if (!format_string) {
- format_string = PyUnicode_InternFromString("format");
- if (!format_string)
- return 0;
- }
-
- if (!str_string) {
- str_string = PyUnicode_InternFromString("str");
- if (!str_string)
- return 0;
- }
-
- if (!repr_string) {
- repr_string = PyUnicode_InternFromString("repr");
- if (!repr_string)
- return 0;
- }
- if (!ascii_string) {
- ascii_string = PyUnicode_InternFromString("ascii");
- if (!ascii_string)
- return 0;
- }
+ /* Our oparg encodes 2 pieces of information: the conversion
+ character, and whether or not a format_spec was provided.
+
+ Convert the conversion char to 2 bits:
+ None: 000 0x0 FVC_NONE
+ !s : 001 0x1 FVC_STR
+ !r : 010 0x2 FVC_REPR
+ !a : 011 0x3 FVC_ASCII
+
+ next bit is whether or not we have a format spec:
+ yes : 100 0x4
+ no : 000 0x0
+ */
- ADDOP_NAME(c, LOAD_GLOBAL, format_string, names);
+ int oparg;
- /* If needed, convert via str, repr, or ascii. */
- if (e->v.FormattedValue.conversion != -1) {
- switch (e->v.FormattedValue.conversion) {
- case 's':
- conversion_name = str_string;
- break;
- case 'r':
- conversion_name = repr_string;
- break;
- case 'a':
- conversion_name = ascii_string;
- break;
- default:
- PyErr_SetString(PyExc_SystemError,
- "Unrecognized conversion character");
- return 0;
- }
- ADDOP_NAME(c, LOAD_GLOBAL, conversion_name, names);
- }
-
- /* Evaluate the value. */
+ /* Evaluate the expression to be formatted. */
VISIT(c, expr, e->v.FormattedValue.value);
- /* If needed, convert via str, repr, or ascii. */
- if (conversion_name) {
- /* Call the function we previously pushed. */
- ADDOP_I(c, CALL_FUNCTION, 1);
+ switch (e->v.FormattedValue.conversion) {
+ case 's': oparg = FVC_STR; break;
+ case 'r': oparg = FVC_REPR; break;
+ case 'a': oparg = FVC_ASCII; break;
+ case -1: oparg = FVC_NONE; break;
+ default:
+ PyErr_SetString(PyExc_SystemError,
+ "Unrecognized conversion character");
+ return 0;
}
-
- /* If we have a format spec, use format(value, format_spec). Otherwise,
- use the single argument form. */
if (e->v.FormattedValue.format_spec) {
+ /* Evaluate the format spec, and update our opcode arg. */
VISIT(c, expr, e->v.FormattedValue.format_spec);
- ADDOP_I(c, CALL_FUNCTION, 2);
- } else {
- /* No format spec specified, call format(value). */
- ADDOP_I(c, CALL_FUNCTION, 1);
+ oparg |= FVS_HAVE_SPEC;
}
+ /* And push our opcode and oparg */
+ ADDOP_I(c, FORMAT_VALUE, oparg);
return 1;
}