cgen: allow printing of C.Structs containing &char/charptr fields

pull/9700/head
Delyan Angelov 2021-04-11 22:53:58 +03:00
parent 273655ecc8
commit 79fa15ec3a
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
6 changed files with 80 additions and 25 deletions

View File

@ -414,6 +414,8 @@ pub const (
int_literal_type = new_type(int_literal_type_idx)
thread_type = new_type(thread_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 (

View File

@ -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 {
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)
if typ.is_ptr() && (typ.is_int_valptr() || typ.is_float_valptr()) {
return '%.*s\\000'
@ -51,6 +63,8 @@ fn (g &Gen) type_to_fmt(typ ast.Type) string {
return "'%.*s\\000'"
} else if sym.kind in [.f32, .f64] {
return '%g\\000' // g removes trailing zeros unlike %f
} else if sym.kind == .int {
return '%d\\000'
} else if sym.kind == .u32 {
return '%u\\000'
} 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]
}
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"
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(' ? _SLIT("nil") : ')
// struct, floats and ints have a special case through the _str function

View File

@ -7,7 +7,7 @@ import v.util
fn (mut g Gen) write_str_fn_definitions() {
// _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, ...) {
va_list args;
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
// guess === how many bytes were taken during the current vsnprintf run
for(;;) {
if (guess < *memsize - *nbytes) {
int remaining_space = *memsize - *nbytes;
if (guess < remaining_space) {
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;
break;
}
}
// increase buffer (somewhat exponentially)
*memsize += (*memsize + *memsize) / 3 + guess;
*memsize += guess + 3 * (*memsize) / 2;
#ifdef _VGCBOEHM
*refbufp = (char*)GC_REALLOC((void*)*refbufp, *memsize);
#else
@ -48,9 +49,9 @@ string _STR(const char *fmt, int nfmts, ...) {
int k = strlen(fmt);
bool is_fspec = false;
for (int j=0; j<k; ++j) {
if (fmt[j] == '%') {
if (fmt[j] == \'%\') {
j++;
if (fmt[j] != '%') {
if (fmt[j] != \'%\') {
is_fspec = true;
break;
}
@ -59,19 +60,31 @@ string _STR(const char *fmt, int nfmts, ...) {
if (is_fspec) {
char f = fmt[k-1];
char fup = f & 0xdf; // toupper
bool l = fmt[k-2] == 'l';
bool ll = l && fmt[k-3] == 'l';
if (f == 'u' || fup == 'X' || f == 'o' || f == 'd' || f == 'c') { // int...
bool l = fmt[k-2] == \'l\';
bool ll = l && fmt[k-3] == \'l\';
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));
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 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));
} else if (f == 'p') {
} else if (f == \'p\') {
_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);
if (fmt[k-4] == '*') { // %*.*s
if (fmt[k-4] == \'*\') { // %*.*s
int fwidth = va_arg(argptr, int);
if (fwidth < 0)
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);
}
} else {
//v_panic(tos3('Invaid format specifier'));
//v_panic(tos3(\'Invaid format specifier\'));
}
} else {
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k);
@ -92,14 +105,8 @@ string _STR(const char *fmt, int nfmts, ...) {
va_end(argptr);
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
//puts('_STR:');
//puts(\'_STR:\');
puts(buf);
#endif
@ -119,7 +126,7 @@ string _STR_TMP(const char *fmt, ...) {
va_end(argptr);
#ifdef DEBUG_ALLOC
//puts('_STR_TMP:');
//puts(\'_STR_TMP:\');
//puts(g_str_buf);
#endif
string res = tos(g_str_buf, len);
@ -128,7 +135,7 @@ string _STR_TMP(const char *fmt, ...) {
} // endof _STR_TMP
")
')
}
fn (mut g Gen) string_literal(node ast.StringLiteral) {

View File

@ -0,0 +1,4 @@
struct Abc {
char *char_pointer_field;
};

View File

@ -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"
}
}'
}