cgen: allow printing of C.Structs containing &char/charptr fields
parent
273655ecc8
commit
79fa15ec3a
|
@ -414,6 +414,8 @@ pub const (
|
||||||
int_literal_type = new_type(int_literal_type_idx)
|
int_literal_type = new_type(int_literal_type_idx)
|
||||||
thread_type = new_type(thread_type_idx)
|
thread_type = new_type(thread_type_idx)
|
||||||
error_type = new_type(error_type_idx)
|
error_type = new_type(error_type_idx)
|
||||||
|
charptr_types = [charptr_type, new_type(char_type_idx).set_nr_muls(1)]
|
||||||
|
byteptr_types = [byteptr_type, new_type(byte_type_idx).set_nr_muls(1)]
|
||||||
)
|
)
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
|
|
|
@ -41,6 +41,18 @@ fn (mut g Gen) gen_str_default(sym ast.TypeSymbol, styp string, str_fn_name stri
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g &Gen) type_to_fmt(typ ast.Type) string {
|
fn (g &Gen) type_to_fmt(typ ast.Type) string {
|
||||||
|
if typ == ast.byte_type_idx {
|
||||||
|
return '%hhx\\000'
|
||||||
|
}
|
||||||
|
if typ == ast.char_type_idx {
|
||||||
|
return '%c\\000'
|
||||||
|
}
|
||||||
|
if typ == ast.voidptr_type_idx || typ in ast.byteptr_types {
|
||||||
|
return '%p\\000'
|
||||||
|
}
|
||||||
|
if typ in ast.charptr_types {
|
||||||
|
return '%C\\000' // a C string
|
||||||
|
}
|
||||||
sym := g.table.get_type_symbol(typ)
|
sym := g.table.get_type_symbol(typ)
|
||||||
if typ.is_ptr() && (typ.is_int_valptr() || typ.is_float_valptr()) {
|
if typ.is_ptr() && (typ.is_int_valptr() || typ.is_float_valptr()) {
|
||||||
return '%.*s\\000'
|
return '%.*s\\000'
|
||||||
|
@ -51,6 +63,8 @@ fn (g &Gen) type_to_fmt(typ ast.Type) string {
|
||||||
return "'%.*s\\000'"
|
return "'%.*s\\000'"
|
||||||
} else if sym.kind in [.f32, .f64] {
|
} else if sym.kind in [.f32, .f64] {
|
||||||
return '%g\\000' // g removes trailing zeros unlike %f
|
return '%g\\000' // g removes trailing zeros unlike %f
|
||||||
|
} else if sym.kind == .int {
|
||||||
|
return '%d\\000'
|
||||||
} else if sym.kind == .u32 {
|
} else if sym.kind == .u32 {
|
||||||
return '%u\\000'
|
return '%u\\000'
|
||||||
} else if sym.kind == .u64 {
|
} else if sym.kind == .u64 {
|
||||||
|
@ -506,9 +520,11 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name stri
|
||||||
fnames2strfunc[field_styp]
|
fnames2strfunc[field_styp]
|
||||||
}
|
}
|
||||||
g.auto_str_funcs.write_string('indents, ')
|
g.auto_str_funcs.write_string('indents, ')
|
||||||
func := struct_auto_str_func(sym, field.typ, field_styp_fn_name, field.name)
|
mut func := struct_auto_str_func(sym, field.typ, field_styp_fn_name, field.name)
|
||||||
// reference types can be "nil"
|
// reference types can be "nil"
|
||||||
if field.typ.is_ptr() {
|
if field.typ.is_ptr() && !(field.typ in ast.charptr_types
|
||||||
|
|| field.typ in ast.byteptr_types
|
||||||
|
|| field.typ == ast.voidptr_type_idx) {
|
||||||
g.auto_str_funcs.write_string('isnil(it.${c_name(field.name)})')
|
g.auto_str_funcs.write_string('isnil(it.${c_name(field.name)})')
|
||||||
g.auto_str_funcs.write_string(' ? _SLIT("nil") : ')
|
g.auto_str_funcs.write_string(' ? _SLIT("nil") : ')
|
||||||
// struct, floats and ints have a special case through the _str function
|
// struct, floats and ints have a special case through the _str function
|
||||||
|
|
|
@ -7,7 +7,7 @@ import v.util
|
||||||
|
|
||||||
fn (mut g Gen) write_str_fn_definitions() {
|
fn (mut g Gen) write_str_fn_definitions() {
|
||||||
// _STR function can't be defined in vlib
|
// _STR function can't be defined in vlib
|
||||||
g.writeln("
|
g.writeln('
|
||||||
void _STR_PRINT_ARG(const char *fmt, char** refbufp, int *nbytes, int *memsize, int guess, ...) {
|
void _STR_PRINT_ARG(const char *fmt, char** refbufp, int *nbytes, int *memsize, int guess, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, guess);
|
va_start(args, guess);
|
||||||
|
@ -16,15 +16,16 @@ void _STR_PRINT_ARG(const char *fmt, char** refbufp, int *nbytes, int *memsize,
|
||||||
// *nbytes === already occupied bytes of buffer refbufp
|
// *nbytes === already occupied bytes of buffer refbufp
|
||||||
// guess === how many bytes were taken during the current vsnprintf run
|
// guess === how many bytes were taken during the current vsnprintf run
|
||||||
for(;;) {
|
for(;;) {
|
||||||
if (guess < *memsize - *nbytes) {
|
int remaining_space = *memsize - *nbytes;
|
||||||
|
if (guess < remaining_space) {
|
||||||
guess = vsnprintf(*refbufp + *nbytes, *memsize - *nbytes, fmt, args);
|
guess = vsnprintf(*refbufp + *nbytes, *memsize - *nbytes, fmt, args);
|
||||||
if (guess < *memsize - *nbytes) { // result did fit into buffer
|
if (guess < remaining_space) { // result did fit into buffer
|
||||||
*nbytes += guess;
|
*nbytes += guess;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// increase buffer (somewhat exponentially)
|
// increase buffer (somewhat exponentially)
|
||||||
*memsize += (*memsize + *memsize) / 3 + guess;
|
*memsize += guess + 3 * (*memsize) / 2;
|
||||||
#ifdef _VGCBOEHM
|
#ifdef _VGCBOEHM
|
||||||
*refbufp = (char*)GC_REALLOC((void*)*refbufp, *memsize);
|
*refbufp = (char*)GC_REALLOC((void*)*refbufp, *memsize);
|
||||||
#else
|
#else
|
||||||
|
@ -48,9 +49,9 @@ string _STR(const char *fmt, int nfmts, ...) {
|
||||||
int k = strlen(fmt);
|
int k = strlen(fmt);
|
||||||
bool is_fspec = false;
|
bool is_fspec = false;
|
||||||
for (int j=0; j<k; ++j) {
|
for (int j=0; j<k; ++j) {
|
||||||
if (fmt[j] == '%') {
|
if (fmt[j] == \'%\') {
|
||||||
j++;
|
j++;
|
||||||
if (fmt[j] != '%') {
|
if (fmt[j] != \'%\') {
|
||||||
is_fspec = true;
|
is_fspec = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -59,19 +60,31 @@ string _STR(const char *fmt, int nfmts, ...) {
|
||||||
if (is_fspec) {
|
if (is_fspec) {
|
||||||
char f = fmt[k-1];
|
char f = fmt[k-1];
|
||||||
char fup = f & 0xdf; // toupper
|
char fup = f & 0xdf; // toupper
|
||||||
bool l = fmt[k-2] == 'l';
|
bool l = fmt[k-2] == \'l\';
|
||||||
bool ll = l && fmt[k-3] == 'l';
|
bool ll = l && fmt[k-3] == \'l\';
|
||||||
if (f == 'u' || fup == 'X' || f == 'o' || f == 'd' || f == 'c') { // int...
|
if (f == \'u\' || fup == \'X\' || f == \'o\' || f == \'d\' || f == \'c\') { // int...
|
||||||
if (ll) _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+16, va_arg(argptr, long long));
|
if (ll) _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+16, va_arg(argptr, long long));
|
||||||
else if (l) _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+10, va_arg(argptr, long));
|
else if (l) _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+10, va_arg(argptr, long));
|
||||||
else _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+8, va_arg(argptr, int));
|
else _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+8, va_arg(argptr, int));
|
||||||
} else if (fup >= 'E' && fup <= 'G') { // floating point
|
} else if (fup >= \'E\' && fup <= \'G\') { // floating point
|
||||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+10, va_arg(argptr, double));
|
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+10, va_arg(argptr, double));
|
||||||
} else if (f == 'p') {
|
} else if (f == \'p\') {
|
||||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+14, va_arg(argptr, void*));
|
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+14, va_arg(argptr, void*));
|
||||||
} else if (f == 's') { // v string
|
} else if (f == \'C\') { // a C string
|
||||||
|
char* sptr = va_arg(argptr, char*);
|
||||||
|
char* fmt_no_c = (char*)v_malloc(k+4);
|
||||||
|
memcpy(fmt_no_c, fmt, k);
|
||||||
|
fmt_no_c[k-2]=\'C\';
|
||||||
|
fmt_no_c[k-1]=\'"\';
|
||||||
|
fmt_no_c[k]=\'%\';
|
||||||
|
fmt_no_c[k+1]=\'s\';
|
||||||
|
fmt_no_c[k+2]=\'"\';
|
||||||
|
fmt_no_c[k+3]=0;
|
||||||
|
_STR_PRINT_ARG(fmt_no_c, &buf, &nbytes, &memsize, k + 4 + 100, sptr);
|
||||||
|
v_free(fmt_no_c);
|
||||||
|
} else if (f == \'s\') { // v string
|
||||||
string s = va_arg(argptr, string);
|
string s = va_arg(argptr, string);
|
||||||
if (fmt[k-4] == '*') { // %*.*s
|
if (fmt[k-4] == \'*\') { // %*.*s
|
||||||
int fwidth = va_arg(argptr, int);
|
int fwidth = va_arg(argptr, int);
|
||||||
if (fwidth < 0)
|
if (fwidth < 0)
|
||||||
fwidth -= (s.len - utf8_str_visible_length(s));
|
fwidth -= (s.len - utf8_str_visible_length(s));
|
||||||
|
@ -82,7 +95,7 @@ string _STR(const char *fmt, int nfmts, ...) {
|
||||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+s.len-4, s.len, s.str);
|
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+s.len-4, s.len, s.str);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//v_panic(tos3('Invaid format specifier'));
|
//v_panic(tos3(\'Invaid format specifier\'));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k);
|
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k);
|
||||||
|
@ -92,14 +105,8 @@ string _STR(const char *fmt, int nfmts, ...) {
|
||||||
va_end(argptr);
|
va_end(argptr);
|
||||||
buf[nbytes] = 0;
|
buf[nbytes] = 0;
|
||||||
|
|
||||||
#ifdef _VGCBOEHM
|
|
||||||
buf = (char*)GC_REALLOC((void*)buf, nbytes+1);
|
|
||||||
#else
|
|
||||||
buf = (char*)realloc((void*)buf, nbytes+1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DEBUG_ALLOC
|
#ifdef DEBUG_ALLOC
|
||||||
//puts('_STR:');
|
//puts(\'_STR:\');
|
||||||
puts(buf);
|
puts(buf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -119,7 +126,7 @@ string _STR_TMP(const char *fmt, ...) {
|
||||||
va_end(argptr);
|
va_end(argptr);
|
||||||
|
|
||||||
#ifdef DEBUG_ALLOC
|
#ifdef DEBUG_ALLOC
|
||||||
//puts('_STR_TMP:');
|
//puts(\'_STR_TMP:\');
|
||||||
//puts(g_str_buf);
|
//puts(g_str_buf);
|
||||||
#endif
|
#endif
|
||||||
string res = tos(g_str_buf, len);
|
string res = tos(g_str_buf, len);
|
||||||
|
@ -128,7 +135,7 @@ string _STR_TMP(const char *fmt, ...) {
|
||||||
|
|
||||||
} // endof _STR_TMP
|
} // endof _STR_TMP
|
||||||
|
|
||||||
")
|
')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) string_literal(node ast.StringLiteral) {
|
fn (mut g Gen) string_literal(node ast.StringLiteral) {
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
struct Abc {
|
||||||
|
char *char_pointer_field;
|
||||||
|
};
|
|
@ -0,0 +1,26 @@
|
||||||
|
#include "@VROOT/cstruct.h"
|
||||||
|
|
||||||
|
const the_string = 'the string'
|
||||||
|
|
||||||
|
struct C.Abc {
|
||||||
|
char_pointer_field &char
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VStruct {
|
||||||
|
a_c_struct C.Abc
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_interpolation_of_v_structs_containing_c_structs() {
|
||||||
|
abc := C.Abc{
|
||||||
|
char_pointer_field: &char(the_string.str)
|
||||||
|
}
|
||||||
|
xxx := VStruct{
|
||||||
|
a_c_struct: abc
|
||||||
|
}
|
||||||
|
sxxx := xxx.str()
|
||||||
|
assert sxxx == 'VStruct{
|
||||||
|
a_c_struct: struct Abc{
|
||||||
|
char_pointer_field: &C"the string"
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
}
|
Loading…
Reference in New Issue