Format spec support in f-strings
This commit is contained in:
parent
9230d4fee1
commit
7d409ebcbb
@ -2724,43 +2724,46 @@ static void string(int exprType) {
|
||||
krk_rewindScanner(beforeExpression); /* To get us back to where we were with a string token */
|
||||
parser = parserBefore;
|
||||
c = inner.start;
|
||||
KrkToken which = syntheticToken("str");
|
||||
int hasEq = 0;
|
||||
|
||||
int formatType = 0;
|
||||
|
||||
while (*c == ' ') c++;
|
||||
if (*c == '=') {
|
||||
c++;
|
||||
while (*c == ' ') c++;
|
||||
emitConstant(OBJECT_VAL(krk_copyString(start,c-start)));
|
||||
emitByte(OP_SWAP);
|
||||
hasEq = 1;
|
||||
formatType |= FORMAT_OP_EQ;
|
||||
}
|
||||
|
||||
if (*c == '!') {
|
||||
c++;
|
||||
/* Conversion specifiers, must only be one */
|
||||
if (*c == 'r') {
|
||||
which = syntheticToken("repr");
|
||||
formatType |= FORMAT_OP_REPR;
|
||||
} else if (*c == 's') {
|
||||
which = syntheticToken("str");
|
||||
formatType |= FORMAT_OP_STR;
|
||||
} else {
|
||||
error("Unsupported conversion flag '%c' for f-string expression.", *c);
|
||||
goto _cleanupError;
|
||||
}
|
||||
c++;
|
||||
}
|
||||
size_t ind = identifierConstant(&which);
|
||||
EMIT_OPERAND_OP(OP_GET_GLOBAL, ind);
|
||||
emitByte(OP_SWAP);
|
||||
emitBytes(OP_CALL, 1);
|
||||
|
||||
if (*c == ':') {
|
||||
/* TODO format specs */
|
||||
error("Format spec not supported in f-string (GH-10)");
|
||||
goto _cleanupError;
|
||||
const char * formatStart = c+1;
|
||||
c++;
|
||||
while (c < end && *c != '}') c++;
|
||||
emitConstant(OBJECT_VAL(krk_copyString(formatStart,c-formatStart)));
|
||||
formatType |= FORMAT_OP_FORMAT;
|
||||
}
|
||||
|
||||
EMIT_OPERAND_OP(OP_FORMAT_VALUE, formatType);
|
||||
|
||||
if (*c != '}') {
|
||||
error("Expected closing '}' after expression in f-string");
|
||||
goto _cleanupError;
|
||||
}
|
||||
if (hasEq) emitByte(OP_ADD);
|
||||
if (atLeastOne) emitByte(OP_ADD);
|
||||
atLeastOne = 1;
|
||||
c++;
|
||||
|
@ -126,6 +126,7 @@ typedef enum {
|
||||
OP_CALL_METHOD,
|
||||
OP_CLOSE_MANY,
|
||||
OP_POP_MANY,
|
||||
OP_FORMAT_VALUE,
|
||||
|
||||
/* Two opcode instructions */
|
||||
OP_JUMP_IF_FALSE_OR_POP,
|
||||
@ -177,6 +178,7 @@ typedef enum {
|
||||
OP_CALL_METHOD_LONG,
|
||||
OP_CLOSE_MANY_LONG,
|
||||
OP_POP_MANY_LONG,
|
||||
OP_FORMAT_VALUE_LONG, /* should be unused */
|
||||
} KrkOpCode;
|
||||
|
||||
/**
|
||||
|
@ -97,6 +97,7 @@ OPERAND(OP_SLICE, (void)0)
|
||||
OPERAND(OP_CALL_METHOD, (void)0)
|
||||
OPERAND(OP_CLOSE_MANY, (void)0)
|
||||
OPERAND(OP_POP_MANY, (void)0)
|
||||
OPERAND(OP_FORMAT_VALUE, (void)0)
|
||||
JUMP(OP_JUMP_IF_FALSE_OR_POP,+)
|
||||
JUMP(OP_JUMP_IF_TRUE_OR_POP,+)
|
||||
JUMP(OP_JUMP,+)
|
||||
|
@ -51,3 +51,10 @@ typedef enum {
|
||||
METHOD__MAX,
|
||||
} KrkSpecialMethods;
|
||||
|
||||
|
||||
#define FORMAT_OP_EQ (1 << 0)
|
||||
#define FORMAT_OP_REPR (1 << 1)
|
||||
#define FORMAT_OP_STR (1 << 2)
|
||||
#define FORMAT_OP_FORMAT (1 << 3)
|
||||
|
||||
|
||||
|
76
src/vm.c
76
src/vm.c
@ -2537,6 +2537,74 @@ static inline void makeCollection(NativeFn func, size_t count) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline int doFormatString(int options) {
|
||||
if (options & FORMAT_OP_FORMAT) {
|
||||
krk_swap(1);
|
||||
if (options & FORMAT_OP_EQ) {
|
||||
krk_swap(2);
|
||||
}
|
||||
} else if (options & FORMAT_OP_EQ) {
|
||||
krk_swap(1);
|
||||
}
|
||||
|
||||
/* Was this a repr or str call? (it can't be both) */
|
||||
if (options & FORMAT_OP_STR) {
|
||||
KrkClass * type = krk_getType(krk_peek(0));
|
||||
if (likely(type->_tostr != NULL)) {
|
||||
krk_push(krk_callDirect(type->_tostr, 1));
|
||||
if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return 1;
|
||||
} else {
|
||||
krk_runtimeError(vm.exceptions->typeError,
|
||||
"Can not convert %s to str", krk_typeName(krk_peek(0)));
|
||||
return 1;
|
||||
}
|
||||
} else if (options & FORMAT_OP_REPR) {
|
||||
KrkClass * type = krk_getType(krk_peek(0));
|
||||
if (likely(type->_reprer != NULL)) {
|
||||
krk_push(krk_callDirect(type->_reprer, 1));
|
||||
if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return 1;
|
||||
} else {
|
||||
krk_runtimeError(vm.exceptions->typeError,
|
||||
"Can not repr %s", krk_typeName(krk_peek(0)));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(options & FORMAT_OP_FORMAT)) {
|
||||
/* Push empty string */
|
||||
krk_push(OBJECT_VAL(S("")));
|
||||
} else {
|
||||
/* Swap args so value is first */
|
||||
krk_swap(1);
|
||||
}
|
||||
|
||||
/* Get the type of the value */
|
||||
KrkClass * type = krk_getType(krk_peek(1));
|
||||
|
||||
if (likely(type->_format != NULL)) {
|
||||
krk_push(krk_callDirect(type->_format, 2));
|
||||
if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return 1;
|
||||
} else {
|
||||
krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'", krk_typeName(krk_peek(1)), "__format__");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!IS_STRING(krk_peek(0))) {
|
||||
krk_runtimeError(vm.exceptions->typeError, "format result is not str");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (options & FORMAT_OP_EQ) {
|
||||
krk_push(krk_operator_add(krk_peek(1), krk_peek(0)));
|
||||
krk_swap(2);
|
||||
krk_pop();
|
||||
krk_pop();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* VM main loop.
|
||||
*/
|
||||
@ -3429,6 +3497,14 @@ _finishReturn: (void)0;
|
||||
krk_currentThread.stackTop[-count] = values->values.values[0];
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_FORMAT_VALUE_LONG:
|
||||
THREE_BYTE_OPERAND;
|
||||
case OP_FORMAT_VALUE: {
|
||||
ONE_BYTE_OPERAND;
|
||||
if (doFormatString(OPERAND)) goto _finishException;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) {
|
||||
_finishException:
|
||||
|
2
test/testFormatSpecs.krk
Normal file
2
test/testFormatSpecs.krk
Normal file
@ -0,0 +1,2 @@
|
||||
print(f'{4225325:#016_x}')
|
||||
print(f'{4225325325325325325632632532432432:#016_x}')
|
2
test/testFormatSpecs.krk.expect
Normal file
2
test/testFormatSpecs.krk.expect
Normal file
@ -0,0 +1,2 @@
|
||||
0x0000_0040_792d
|
||||
0xd053_1a76_d6a2_ecdd_ed78_bd72_f630
|
Loading…
x
Reference in New Issue
Block a user