Move StringBuilder functions out of header, into obj_str; add pushStringBuilderFormat
This commit is contained in:
parent
6029d50749
commit
6b8d7ee6d0
119
src/exceptions.c
119
src/exceptions.c
@ -451,125 +451,10 @@ KrkValue krk_runtimeError(KrkClass * type, const char * fmt, ...) {
|
||||
|
||||
if (!strcmp(fmt,"%V")) {
|
||||
msg = va_arg(args, KrkValue);
|
||||
goto _finish;
|
||||
} else if (!krk_pushStringBuilderFormatV(&sb, fmt, args)) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
for (const char * f = fmt; *f; ++f) {
|
||||
if (*f != '%') {
|
||||
pushStringBuilder(&sb, *f);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Unset exception flag if it was already set. */
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
|
||||
krk_currentThread.flags &= ~(KRK_THREAD_HAS_EXCEPTION);
|
||||
}
|
||||
|
||||
++f;
|
||||
|
||||
int size = ' ';
|
||||
int len = -1;
|
||||
|
||||
if (*f == 'z') size = *f++;
|
||||
else if (*f == 'l') size = *f++;
|
||||
else if (*f == 'L') size = *f++;
|
||||
|
||||
if (*f == '.') {
|
||||
if (f[1] == '*') {
|
||||
len = va_arg(args, int);
|
||||
f += 2;
|
||||
}
|
||||
}
|
||||
|
||||
switch (*f) {
|
||||
case 0: break;
|
||||
case '%':
|
||||
pushStringBuilder(&sb, '%');
|
||||
break;
|
||||
|
||||
case 'c': {
|
||||
char val = (char)va_arg(args, int);
|
||||
pushStringBuilder(&sb, val);
|
||||
break;
|
||||
}
|
||||
|
||||
case 's': {
|
||||
const char * c = va_arg(args, const char *);
|
||||
pushStringBuilderStr(&sb, c, len == -1 ? strlen(c) : (size_t)len);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'u': {
|
||||
size_t val = 0;
|
||||
if (size == ' ') {
|
||||
val = va_arg(args, unsigned int);
|
||||
} else if (size == 'l') {
|
||||
val = va_arg(args, unsigned long);
|
||||
} else if (size == 'L') {
|
||||
val = va_arg(args, unsigned long long);
|
||||
} else if (size == 'z') {
|
||||
val = va_arg(args, size_t);
|
||||
}
|
||||
char tmp[100];
|
||||
snprintf(tmp, 32, "%zu", val);
|
||||
pushStringBuilderStr(&sb, tmp, strlen(tmp));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd': {
|
||||
ssize_t val = 0;
|
||||
if (size == ' ') {
|
||||
val = va_arg(args, int);
|
||||
} else if (size == 'l') {
|
||||
val = va_arg(args, long);
|
||||
} else if (size == 'L') {
|
||||
val = va_arg(args, long long);
|
||||
} else if (size == 'z') {
|
||||
val = va_arg(args, ssize_t);
|
||||
}
|
||||
char tmp[100];
|
||||
snprintf(tmp, 32, "%zd", val);
|
||||
pushStringBuilderStr(&sb, tmp, strlen(tmp));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'T': {
|
||||
KrkValue val = va_arg(args, KrkValue);
|
||||
const char * typeName = krk_typeName(val);
|
||||
pushStringBuilderStr(&sb, typeName, strlen(typeName));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'S': {
|
||||
KrkString * val = va_arg(args, KrkString*);
|
||||
pushStringBuilderStr(&sb, val->chars, val->length);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'R': {
|
||||
KrkValue val = va_arg(args, KrkValue);
|
||||
KrkClass * type = krk_getType(val);
|
||||
if (likely(type->_reprer != NULL)) {
|
||||
krk_push(val);
|
||||
KrkValue res = krk_callDirect(type->_reprer, 1);
|
||||
if (IS_STRING(res)) {
|
||||
pushStringBuilderStr(&sb, AS_CSTRING(res), AS_STRING(res)->length);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
va_arg(args, void*);
|
||||
pushStringBuilderStr(&sb, "(unsupported: ", 14);
|
||||
pushStringBuilder(&sb, *f);
|
||||
pushStringBuilder(&sb, ')');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_finish:
|
||||
va_end(args);
|
||||
krk_currentThread.flags |= KRK_THREAD_HAS_EXCEPTION;
|
||||
|
||||
|
@ -125,14 +125,8 @@ struct StringBuilder {
|
||||
* @param sb String builder to append to.
|
||||
* @param c Character to append.
|
||||
*/
|
||||
static inline void pushStringBuilder(struct StringBuilder * sb, char c) {
|
||||
if (sb->capacity < sb->length + 1) {
|
||||
size_t old = sb->capacity;
|
||||
sb->capacity = GROW_CAPACITY(old);
|
||||
sb->bytes = GROW_ARRAY(char, sb->bytes, old, sb->capacity);
|
||||
}
|
||||
sb->bytes[sb->length++] = c;
|
||||
}
|
||||
void krk_pushStringBuilder(struct StringBuilder * sb, char c);
|
||||
#define pushStringBuilder krk_pushStringBuilder
|
||||
|
||||
/**
|
||||
* @brief Append a string to the end of a string builder.
|
||||
@ -141,19 +135,8 @@ static inline void pushStringBuilder(struct StringBuilder * sb, char c) {
|
||||
* @param str C string to add.
|
||||
* @param len Length of the C string.
|
||||
*/
|
||||
static inline void pushStringBuilderStr(struct StringBuilder * sb, const char *str, size_t len) {
|
||||
if (sb->capacity < sb->length + len) {
|
||||
size_t prevcap = sb->capacity;
|
||||
while (sb->capacity < sb->length + len) {
|
||||
size_t old = sb->capacity;
|
||||
sb->capacity = GROW_CAPACITY(old);
|
||||
}
|
||||
sb->bytes = GROW_ARRAY(char, sb->bytes, prevcap, sb->capacity);
|
||||
}
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
sb->bytes[sb->length++] = *(str++);
|
||||
}
|
||||
}
|
||||
void krk_pushStringBuilderStr(struct StringBuilder * sb, const char *str, size_t len);
|
||||
#define pushStringBuilderStr krk_pushStringBuilderStr
|
||||
|
||||
/**
|
||||
* @brief Finalize a string builder into a string object.
|
||||
@ -165,11 +148,8 @@ static inline void pushStringBuilderStr(struct StringBuilder * sb, const char *s
|
||||
* @param sb String builder to finalize.
|
||||
* @return A value representing a string object.
|
||||
*/
|
||||
static inline KrkValue finishStringBuilder(struct StringBuilder * sb) {
|
||||
KrkValue out = OBJECT_VAL(krk_copyString(sb->bytes, sb->length));
|
||||
FREE_ARRAY(char,sb->bytes, sb->capacity);
|
||||
return out;
|
||||
}
|
||||
KrkValue krk_finishStringBuilder(struct StringBuilder * sb);
|
||||
#define finishStringBuilder krk_finishStringBuilder
|
||||
|
||||
/**
|
||||
* @brief Finalize a string builder in a bytes object.
|
||||
@ -180,11 +160,8 @@ static inline KrkValue finishStringBuilder(struct StringBuilder * sb) {
|
||||
* @param sb String builder to finalize.
|
||||
* @return A value representing a bytes object.
|
||||
*/
|
||||
static inline KrkValue finishStringBuilderBytes(struct StringBuilder * sb) {
|
||||
KrkValue out = OBJECT_VAL(krk_newBytes(sb->length, (uint8_t*)sb->bytes));
|
||||
FREE_ARRAY(char,sb->bytes, sb->capacity);
|
||||
return out;
|
||||
}
|
||||
KrkValue krk_finishStringBuilderBytes(struct StringBuilder * sb);
|
||||
#define finishStringBuilderBytes krk_finishStringBuilderBytes
|
||||
|
||||
/**
|
||||
* @brief Discard the contents of a string builder.
|
||||
@ -196,10 +173,8 @@ static inline KrkValue finishStringBuilderBytes(struct StringBuilder * sb) {
|
||||
* @param sb String builder to discard.
|
||||
* @return None, as a convenience.
|
||||
*/
|
||||
static inline KrkValue discardStringBuilder(struct StringBuilder * sb) {
|
||||
FREE_ARRAY(char,sb->bytes, sb->capacity);
|
||||
return NONE_VAL();
|
||||
}
|
||||
KrkValue krk_discardStringBuilder(struct StringBuilder * sb);
|
||||
#define discardStringBuilder krk_discardStringBuilder
|
||||
|
||||
#define IS_int(o) (IS_INTEGER(o))
|
||||
#define AS_int(o) (AS_INTEGER(o))
|
||||
@ -337,3 +312,7 @@ extern int krk_parseArgs_impl(
|
||||
* @returns 1 on success, 0 on failure with an exception set.
|
||||
*/
|
||||
#define krk_parseArgs(f,n,...) krk_parseArgs_impl(_method_name,argc,argv,hasKw,f,n,__VA_ARGS__)
|
||||
|
||||
|
||||
extern int krk_pushStringBuilderFormatV(struct StringBuilder * sb, const char * fmt, va_list args);
|
||||
extern int krk_pushStringBuilderFormat(struct StringBuilder * sb, const char * fmt, ...);
|
||||
|
179
src/obj_str.c
179
src/obj_str.c
@ -1035,6 +1035,185 @@ _corrupt:
|
||||
return krk_runtimeError(vm.exceptions->typeError, "Corrupt str iterator: %s", errorStr);
|
||||
}
|
||||
|
||||
|
||||
void krk_pushStringBuilder(struct StringBuilder * sb, char c) {
|
||||
if (sb->capacity < sb->length + 1) {
|
||||
size_t old = sb->capacity;
|
||||
sb->capacity = GROW_CAPACITY(old);
|
||||
sb->bytes = GROW_ARRAY(char, sb->bytes, old, sb->capacity);
|
||||
}
|
||||
sb->bytes[sb->length++] = c;
|
||||
}
|
||||
|
||||
void krk_pushStringBuilderStr(struct StringBuilder * sb, const char *str, size_t len) {
|
||||
if (sb->capacity < sb->length + len) {
|
||||
size_t prevcap = sb->capacity;
|
||||
while (sb->capacity < sb->length + len) {
|
||||
size_t old = sb->capacity;
|
||||
sb->capacity = GROW_CAPACITY(old);
|
||||
}
|
||||
sb->bytes = GROW_ARRAY(char, sb->bytes, prevcap, sb->capacity);
|
||||
}
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
sb->bytes[sb->length++] = *(str++);
|
||||
}
|
||||
}
|
||||
|
||||
KrkValue krk_finishStringBuilder(struct StringBuilder * sb) {
|
||||
KrkValue out = OBJECT_VAL(krk_copyString(sb->bytes, sb->length));
|
||||
FREE_ARRAY(char,sb->bytes, sb->capacity);
|
||||
return out;
|
||||
}
|
||||
|
||||
KrkValue krk_finishStringBuilderBytes(struct StringBuilder * sb) {
|
||||
KrkValue out = OBJECT_VAL(krk_newBytes(sb->length, (uint8_t*)sb->bytes));
|
||||
FREE_ARRAY(char,sb->bytes, sb->capacity);
|
||||
return out;
|
||||
}
|
||||
|
||||
KrkValue krk_discardStringBuilder(struct StringBuilder * sb) {
|
||||
FREE_ARRAY(char,sb->bytes, sb->capacity);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
int krk_pushStringBuilderFormatV(struct StringBuilder * sb, const char * fmt, va_list args) {
|
||||
for (const char * f = fmt; *f; ++f) {
|
||||
if (*f != '%') {
|
||||
pushStringBuilder(sb, *f);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Bail on exception */
|
||||
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
++f;
|
||||
|
||||
int size = ' ';
|
||||
int len = -1;
|
||||
|
||||
if (*f == 'z') size = *f++;
|
||||
else if (*f == 'l') size = *f++;
|
||||
else if (*f == 'L') size = *f++;
|
||||
|
||||
if (*f == '.') {
|
||||
if (f[1] == '*') {
|
||||
len = va_arg(args, int);
|
||||
f += 2;
|
||||
}
|
||||
}
|
||||
|
||||
switch (*f) {
|
||||
case 0: break;
|
||||
case '%':
|
||||
pushStringBuilder(sb, '%');
|
||||
break;
|
||||
|
||||
case 'c': {
|
||||
char val = (char)va_arg(args, int);
|
||||
pushStringBuilder(sb, val);
|
||||
break;
|
||||
}
|
||||
|
||||
case 's': {
|
||||
const char * c = va_arg(args, const char *);
|
||||
pushStringBuilderStr(sb, c, len == -1 ? strlen(c) : (size_t)len);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'u': {
|
||||
size_t val = 0;
|
||||
if (size == ' ') {
|
||||
val = va_arg(args, unsigned int);
|
||||
} else if (size == 'l') {
|
||||
val = va_arg(args, unsigned long);
|
||||
} else if (size == 'L') {
|
||||
val = va_arg(args, unsigned long long);
|
||||
} else if (size == 'z') {
|
||||
val = va_arg(args, size_t);
|
||||
}
|
||||
char tmp[100];
|
||||
snprintf(tmp, 32, "%zu", val);
|
||||
pushStringBuilderStr(sb, tmp, strlen(tmp));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd': {
|
||||
ssize_t val = 0;
|
||||
if (size == ' ') {
|
||||
val = va_arg(args, int);
|
||||
} else if (size == 'l') {
|
||||
val = va_arg(args, long);
|
||||
} else if (size == 'L') {
|
||||
val = va_arg(args, long long);
|
||||
} else if (size == 'z') {
|
||||
val = va_arg(args, ssize_t);
|
||||
}
|
||||
char tmp[100];
|
||||
snprintf(tmp, 32, "%zd", val);
|
||||
pushStringBuilderStr(sb, tmp, strlen(tmp));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'T': {
|
||||
KrkValue val = va_arg(args, KrkValue);
|
||||
const char * typeName = krk_typeName(val);
|
||||
pushStringBuilderStr(sb, typeName, strlen(typeName));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'S': {
|
||||
KrkString * val = va_arg(args, KrkString*);
|
||||
pushStringBuilderStr(sb, val->chars, val->length);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'R': {
|
||||
KrkValue val = va_arg(args, KrkValue);
|
||||
KrkClass * type = krk_getType(val);
|
||||
if (likely(type->_reprer != NULL)) {
|
||||
krk_push(val);
|
||||
KrkValue res = krk_callDirect(type->_reprer, 1);
|
||||
krk_push(res);
|
||||
if (IS_STRING(res)) {
|
||||
pushStringBuilderStr(sb, AS_CSTRING(res), AS_STRING(res)->length);
|
||||
}
|
||||
krk_pop();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p': {
|
||||
uintptr_t val = va_arg(args, uintptr_t);
|
||||
char tmp[100];
|
||||
snprintf(tmp, 32, "0x%zx", (size_t)val);
|
||||
pushStringBuilderStr(sb, tmp, strlen(tmp));
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
va_arg(args, void*);
|
||||
pushStringBuilderStr(sb, "(unsupported: ", 14);
|
||||
pushStringBuilder(sb, *f);
|
||||
pushStringBuilder(sb, ')');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int krk_pushStringBuilderFormat(struct StringBuilder * sb, const char * fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int result = krk_pushStringBuilderFormatV(sb,fmt,args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
_noexport
|
||||
void _createAndBind_strClass(void) {
|
||||
KrkClass * str = ADD_BASE_CLASS(vm.baseClasses->strClass, "str", vm.baseClasses->objectClass);
|
||||
|
Loading…
Reference in New Issue
Block a user