|
|
@ -4,6 +4,7 @@
|
|
|
|
module gen
|
|
|
|
module gen
|
|
|
|
|
|
|
|
|
|
|
|
import strings
|
|
|
|
import strings
|
|
|
|
|
|
|
|
import strconv
|
|
|
|
import v.ast
|
|
|
|
import v.ast
|
|
|
|
import v.table
|
|
|
|
import v.table
|
|
|
|
import v.pref
|
|
|
|
import v.pref
|
|
|
@ -211,7 +212,8 @@ pub fn (mut g Gen) init() {
|
|
|
|
g.cheaders.writeln('#include <inttypes.h>') // int64_t etc
|
|
|
|
g.cheaders.writeln('#include <inttypes.h>') // int64_t etc
|
|
|
|
g.cheaders.writeln(c_builtin_types)
|
|
|
|
g.cheaders.writeln(c_builtin_types)
|
|
|
|
g.cheaders.writeln(c_headers)
|
|
|
|
g.cheaders.writeln(c_headers)
|
|
|
|
g.definitions.writeln('\nstring _STR(const char*, ...);\n')
|
|
|
|
g.definitions.writeln('\nvoid _STR_PRINT_ARG(const char*, char**, int*, int*, int, ...);\n')
|
|
|
|
|
|
|
|
g.definitions.writeln('\nstring _STR(const char*, int, ...);\n')
|
|
|
|
g.definitions.writeln('\nstring _STR_TMP(const char*, ...);\n')
|
|
|
|
g.definitions.writeln('\nstring _STR_TMP(const char*, ...);\n')
|
|
|
|
g.write_builtin_types()
|
|
|
|
g.write_builtin_types()
|
|
|
|
g.write_typedef_types()
|
|
|
|
g.write_typedef_types()
|
|
|
@ -2173,15 +2175,76 @@ fn (mut g Gen) write_init_function() {
|
|
|
|
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('
|
|
|
|
string _STR(const char *fmt, ...) {
|
|
|
|
void _STR_PRINT_ARG(const char *fmt, char** refbufp, int *nbytes, int *memsize, int guess, ...) {
|
|
|
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start(args, guess);
|
|
|
|
|
|
|
|
for(;;) {
|
|
|
|
|
|
|
|
if (guess < *memsize - *nbytes) {
|
|
|
|
|
|
|
|
guess = vsnprintf(*refbufp + *nbytes, *memsize - *nbytes, fmt, args);
|
|
|
|
|
|
|
|
if (guess < *memsize - *nbytes) { // result did fit into buffer
|
|
|
|
|
|
|
|
*nbytes += guess;
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// increase buffer (somewhat exponentially)
|
|
|
|
|
|
|
|
*memsize += (*memsize + *memsize) / 3 + guess;
|
|
|
|
|
|
|
|
*refbufp = realloc(*refbufp, *memsize);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string _STR(const char *fmt, int nfmts, ...) {
|
|
|
|
va_list argptr;
|
|
|
|
va_list argptr;
|
|
|
|
va_start(argptr, fmt);
|
|
|
|
int memsize = 128;
|
|
|
|
size_t len = vsnprintf(0, 0, fmt, argptr) + 1;
|
|
|
|
int nbytes = 0;
|
|
|
|
va_end(argptr);
|
|
|
|
char* buf = malloc(memsize);
|
|
|
|
byte* buf = malloc(len);
|
|
|
|
va_start(argptr, nfmts);
|
|
|
|
va_start(argptr, fmt);
|
|
|
|
for (int i=0; i<nfmts; i++) {
|
|
|
|
vsprintf((char *)buf, fmt, argptr);
|
|
|
|
int k = strlen(fmt);
|
|
|
|
|
|
|
|
bool is_fspec = false;
|
|
|
|
|
|
|
|
for (int j=0; j<k; j++) {
|
|
|
|
|
|
|
|
if (fmt[j] == '+"'%'"+') {
|
|
|
|
|
|
|
|
j++;
|
|
|
|
|
|
|
|
if(fmt[j] != '+"'%'"+') {
|
|
|
|
|
|
|
|
is_fspec = true;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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...
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+10, va_arg(argptr, double));
|
|
|
|
|
|
|
|
} else if (f == '+"'s'"+') { // v string
|
|
|
|
|
|
|
|
string s = va_arg(argptr, string);
|
|
|
|
|
|
|
|
if (fmt[k-4] == '+"'*'"+') { // %*.*s
|
|
|
|
|
|
|
|
int fwidth = va_arg(argptr, int);
|
|
|
|
|
|
|
|
if (fwidth < 0)
|
|
|
|
|
|
|
|
fwidth -= (s.len - utf8_str_len(s));
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
fwidth += (s.len - utf8_str_len(s));
|
|
|
|
|
|
|
|
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+fwidth-4, fwidth, s.len, s.str);
|
|
|
|
|
|
|
|
} else { // %.*s
|
|
|
|
|
|
|
|
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+s.len-4, s.len, s.str);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
v_panic(tos3("Invaid format specifier"));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if (k)
|
|
|
|
|
|
|
|
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt += k+1;
|
|
|
|
|
|
|
|
}
|
|
|
|
va_end(argptr);
|
|
|
|
va_end(argptr);
|
|
|
|
|
|
|
|
buf[nbytes] = 0;
|
|
|
|
|
|
|
|
buf = realloc(buf, nbytes+1);
|
|
|
|
#ifdef DEBUG_ALLOC
|
|
|
|
#ifdef DEBUG_ALLOC
|
|
|
|
puts("_STR:");
|
|
|
|
puts("_STR:");
|
|
|
|
puts(buf);
|
|
|
|
puts(buf);
|
|
|
@ -2362,89 +2425,128 @@ fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
|
|
|
|
fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
|
|
|
fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
|
|
|
g.write('_STR("')
|
|
|
|
g.write('_STR("')
|
|
|
|
// Build the string with %
|
|
|
|
// Build the string with %
|
|
|
|
|
|
|
|
mut fieldwidths := []int{}
|
|
|
|
|
|
|
|
mut specs := []byte{}
|
|
|
|
|
|
|
|
mut num_fmts := 1
|
|
|
|
for i, val in node.vals {
|
|
|
|
for i, val in node.vals {
|
|
|
|
escaped_val := val.replace_each(['"', '\\"', '\r\n', '\\n', '\n', '\\n', '%', '%%'])
|
|
|
|
escaped_val := val.replace_each(['"', '\\"', '\r\n', '\\n', '\n', '\\n', '%', '%%'])
|
|
|
|
g.write(escaped_val)
|
|
|
|
g.write(escaped_val)
|
|
|
|
if i >= node.exprs.len {
|
|
|
|
if i >= node.exprs.len {
|
|
|
|
|
|
|
|
fieldwidths << 0
|
|
|
|
|
|
|
|
specs << `_`
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// TODO: fix match, sum type false positive
|
|
|
|
num_fmts++
|
|
|
|
// match node.expr_types[i] {
|
|
|
|
|
|
|
|
// table.string_type {
|
|
|
|
|
|
|
|
// g.write('%.*s')
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// table.int_type {
|
|
|
|
|
|
|
|
// g.write('%d')
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// else {}
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
sym := g.table.get_type_symbol(node.expr_types[i])
|
|
|
|
sym := g.table.get_type_symbol(node.expr_types[i])
|
|
|
|
sfmt := node.expr_fmts[i]
|
|
|
|
sfmt := node.expr_fmts[i]
|
|
|
|
|
|
|
|
mut fspec := `_` // placeholder
|
|
|
|
|
|
|
|
mut fmt := '' // field width and precision
|
|
|
|
if sfmt.len > 0 {
|
|
|
|
if sfmt.len > 0 {
|
|
|
|
fspec := sfmt[sfmt.len - 1]
|
|
|
|
// analyze and validate format specifier
|
|
|
|
if fspec == `s` && node.expr_types[i] != table.string_type {
|
|
|
|
if sfmt[sfmt.len - 1] in [`E`, `F`, `G`, `e`, `f`, `g`, `e`,
|
|
|
|
verror('only V strings can be formatted with a ${sfmt} format')
|
|
|
|
`d`, `u`, `x`, `X`, `o`, `c`, `s`] {
|
|
|
|
|
|
|
|
fspec = sfmt[sfmt.len - 1]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt = if fspec == `_` {
|
|
|
|
|
|
|
|
sfmt[1..sfmt.len]
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
sfmt[1..sfmt.len - 1]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g.write('%' + sfmt[1..])
|
|
|
|
|
|
|
|
} else if node.expr_types[i] in [table.string_type, table.bool_type] || sym.kind in
|
|
|
|
|
|
|
|
[.enum_, .array, .array_fixed] {
|
|
|
|
|
|
|
|
g.write('%.*s')
|
|
|
|
|
|
|
|
} else if node.expr_types[i] in [table.f32_type, table.f64_type] {
|
|
|
|
|
|
|
|
g.write('%g')
|
|
|
|
|
|
|
|
} else if sym.kind in [.struct_, .map] && !sym.has_method('str') {
|
|
|
|
|
|
|
|
g.write('%.*s')
|
|
|
|
|
|
|
|
} else if node.expr_types[i] == table.i16_type {
|
|
|
|
|
|
|
|
g.write('%"PRId16"')
|
|
|
|
|
|
|
|
} else if node.expr_types[i] == table.u16_type {
|
|
|
|
|
|
|
|
g.write('%"PRIu16"')
|
|
|
|
|
|
|
|
} else if node.expr_types[i] == table.u32_type {
|
|
|
|
|
|
|
|
g.write('%"PRIu32"')
|
|
|
|
|
|
|
|
} else if node.expr_types[i] == table.i64_type {
|
|
|
|
|
|
|
|
g.write('%"PRId64"')
|
|
|
|
|
|
|
|
} else if node.expr_types[i] == table.u64_type {
|
|
|
|
|
|
|
|
g.write('%"PRIu64"')
|
|
|
|
|
|
|
|
} else if g.typ(node.expr_types[i]).starts_with('Option') {
|
|
|
|
|
|
|
|
g.write('%.*s')
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
g.write('%"PRId32"')
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if fspec == `_` { // set default representation for type if still missing
|
|
|
|
|
|
|
|
if node.expr_types[i].is_float() {
|
|
|
|
|
|
|
|
fspec = `g`
|
|
|
|
|
|
|
|
} else if node.expr_types[i].is_signed() {
|
|
|
|
|
|
|
|
fspec = `d`
|
|
|
|
|
|
|
|
} else if node.expr_types[i].is_unsigned() {
|
|
|
|
|
|
|
|
fspec = `u`
|
|
|
|
|
|
|
|
} else if node.expr_types[i] in [table.string_type, table.bool_type] ||
|
|
|
|
|
|
|
|
sym.kind in [.enum_, .array, .array_fixed, .struct_, .map] ||
|
|
|
|
|
|
|
|
g.typ(node.expr_types[i]).starts_with('Option') ||
|
|
|
|
|
|
|
|
sym.has_method('str') {
|
|
|
|
|
|
|
|
fspec = `s`
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// default to int - TODO: should better be checked
|
|
|
|
|
|
|
|
fspec = `d`
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
fields := fmt.split('.')
|
|
|
|
|
|
|
|
// validate format
|
|
|
|
|
|
|
|
// only floats should have precision specifier
|
|
|
|
|
|
|
|
if fields.len > 2 || fields.len == 2 && !(node.expr_types[i].is_float()) ||
|
|
|
|
|
|
|
|
node.expr_types[i].is_signed() && !(fspec in [`d`, `c`, `x`, `X`, `o`]) ||
|
|
|
|
|
|
|
|
node.expr_types[i].is_unsigned() && !(fspec in [`u`, `x`, `X`, `o`, `c`]) ||
|
|
|
|
|
|
|
|
node.expr_types[i].is_float() && !(fspec in [`E`, `F`, `G`, `e`, `f`, `g`, `e`]) {
|
|
|
|
|
|
|
|
verror('illegal format specifier ${fspec:c} for type ${g.table.get_type_name(node.expr_types[i])}')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure that format paramters are valid numbers
|
|
|
|
|
|
|
|
for j, f in fields {
|
|
|
|
|
|
|
|
for k, c in f {
|
|
|
|
|
|
|
|
if (c < `0` || c > `9`) &&
|
|
|
|
|
|
|
|
!(j == 0 && k == 0 && (node.expr_types[i].is_number() && c == `+` || c == `-`)) {
|
|
|
|
|
|
|
|
verror('illegal character ${c:c} in format specifier ${fmt}')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
specs << fspec
|
|
|
|
|
|
|
|
fieldwidths << if fields.len == 0 {
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
strconv.atoi(fields[0])
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// write correct format specifier to intermediate string
|
|
|
|
|
|
|
|
g.write('%')
|
|
|
|
|
|
|
|
if fspec == `s` {
|
|
|
|
|
|
|
|
if fields.len == 0 || strconv.atoi(fields[0]) == 0 {
|
|
|
|
|
|
|
|
g.write('.*s')
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
g.write('*.*s')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if node.expr_types[i].is_float() {
|
|
|
|
|
|
|
|
g.write('$fmt${fspec:c}')
|
|
|
|
|
|
|
|
} else if node.expr_types[i].is_int() {
|
|
|
|
|
|
|
|
if fspec == `c` {
|
|
|
|
|
|
|
|
if node.expr_types[i].idx() in [table.i64_type_idx table.f64_type_idx] {
|
|
|
|
|
|
|
|
verror("64 bit integer types cannot be interpolated as character")
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
g.write('${fmt}c')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
g.write('${fmt}"PRI${fspec:c}')
|
|
|
|
|
|
|
|
if node.expr_types[i] in [table.i8_type, table.byte_type] {
|
|
|
|
|
|
|
|
g.write('8')
|
|
|
|
|
|
|
|
} else if node.expr_types[i] in [table.i16_type, table.u16_type] {
|
|
|
|
|
|
|
|
g.write('16')
|
|
|
|
|
|
|
|
} else if node.expr_types[i] in [table.i64_type, table.u64_type] {
|
|
|
|
|
|
|
|
g.write('64')
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
g.write('32')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
g.write('"')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// TODO: better check this case
|
|
|
|
|
|
|
|
g.write('${fmt}"PRId32"')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
g.write('\\000')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g.write('", ')
|
|
|
|
g.write('", $num_fmts, ')
|
|
|
|
// Build args
|
|
|
|
// Build args
|
|
|
|
for i, expr in node.exprs {
|
|
|
|
for i, expr in node.exprs {
|
|
|
|
sfmt := node.expr_fmts[i]
|
|
|
|
if node.expr_types[i] == table.string_type {
|
|
|
|
if sfmt.len > 0 {
|
|
|
|
|
|
|
|
fspec := sfmt[sfmt.len - 1]
|
|
|
|
|
|
|
|
if fspec == `s` && node.expr_types[i] == table.string_type {
|
|
|
|
|
|
|
|
g.expr(expr)
|
|
|
|
|
|
|
|
g.write('.str')
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
g.expr(expr)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if node.expr_types[i] == table.string_type {
|
|
|
|
|
|
|
|
// `name.str, name.len,`
|
|
|
|
|
|
|
|
g.expr(expr)
|
|
|
|
g.expr(expr)
|
|
|
|
g.write('.len, ')
|
|
|
|
|
|
|
|
g.expr(expr)
|
|
|
|
|
|
|
|
g.write('.str')
|
|
|
|
|
|
|
|
} else if node.expr_types[i] == table.bool_type {
|
|
|
|
} else if node.expr_types[i] == table.bool_type {
|
|
|
|
g.expr(expr)
|
|
|
|
g.expr(expr)
|
|
|
|
g.write(' ? 4 : 5, ')
|
|
|
|
g.write(' ? _SLIT("true") : _SLIT("false")')
|
|
|
|
|
|
|
|
} else if node.expr_types[i].is_number() || specs[i] == `d` {
|
|
|
|
g.expr(expr)
|
|
|
|
g.expr(expr)
|
|
|
|
g.write(' ? "true" : "false"')
|
|
|
|
} else if specs[i] == `s` {
|
|
|
|
} else if node.expr_types[i] in [table.f32_type, table.f64_type] {
|
|
|
|
|
|
|
|
g.expr(expr)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
sym := g.table.get_type_symbol(node.expr_types[i])
|
|
|
|
sym := g.table.get_type_symbol(node.expr_types[i])
|
|
|
|
if node.expr_types[i].flag_is(.variadic) {
|
|
|
|
if node.expr_types[i].flag_is(.variadic) {
|
|
|
|
str_fn_name := g.gen_str_for_type(node.expr_types[i])
|
|
|
|
str_fn_name := g.gen_str_for_type(node.expr_types[i])
|
|
|
|
g.write('${str_fn_name}(')
|
|
|
|
g.write('${str_fn_name}(')
|
|
|
|
g.expr(expr)
|
|
|
|
g.expr(expr)
|
|
|
|
g.write(')')
|
|
|
|
g.write(')')
|
|
|
|
g.write('.len, ')
|
|
|
|
|
|
|
|
g.write('${str_fn_name}(')
|
|
|
|
|
|
|
|
g.expr(expr)
|
|
|
|
|
|
|
|
g.write(').str')
|
|
|
|
|
|
|
|
} else if sym.kind == .enum_ {
|
|
|
|
} else if sym.kind == .enum_ {
|
|
|
|
is_var := match node.exprs[i] {
|
|
|
|
is_var := match node.exprs[i] {
|
|
|
|
ast.SelectorExpr { true }
|
|
|
|
ast.SelectorExpr { true }
|
|
|
@ -2456,58 +2558,51 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
|
|
|
g.write('${str_fn_name}(')
|
|
|
|
g.write('${str_fn_name}(')
|
|
|
|
g.enum_expr(expr)
|
|
|
|
g.enum_expr(expr)
|
|
|
|
g.write(')')
|
|
|
|
g.write(')')
|
|
|
|
g.write('.len, ')
|
|
|
|
|
|
|
|
g.write('${str_fn_name}(')
|
|
|
|
|
|
|
|
g.enum_expr(expr)
|
|
|
|
|
|
|
|
g.write(').str')
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
g.write('tos3("')
|
|
|
|
g.write('tos3("')
|
|
|
|
g.enum_expr(expr)
|
|
|
|
g.enum_expr(expr)
|
|
|
|
g.write('")')
|
|
|
|
g.write('")')
|
|
|
|
g.write('.len, ')
|
|
|
|
|
|
|
|
g.write('"')
|
|
|
|
|
|
|
|
g.enum_expr(expr)
|
|
|
|
|
|
|
|
g.write('"')
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if sym.kind in [.array, .array_fixed] {
|
|
|
|
} else if sym.has_method('str') || sym.kind in [.array, .array_fixed, .map, .struct_] {
|
|
|
|
str_fn_name := g.gen_str_for_type(node.expr_types[i])
|
|
|
|
is_p := node.expr_types[i].is_ptr()
|
|
|
|
g.write('${str_fn_name}(')
|
|
|
|
val_type := if is_p {
|
|
|
|
|
|
|
|
node.expr_types[i].deref()
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
node.expr_types[i]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
str_fn_name := g.gen_str_for_type(val_type)
|
|
|
|
|
|
|
|
if is_p {
|
|
|
|
|
|
|
|
g.write('string_add(_SLIT("&"), ${str_fn_name}(*(')
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
g.write('${str_fn_name}(')
|
|
|
|
|
|
|
|
}
|
|
|
|
g.expr(expr)
|
|
|
|
g.expr(expr)
|
|
|
|
g.write(')')
|
|
|
|
if sym.kind == .struct_ && !sym.has_method('str') {
|
|
|
|
g.write('.len, ')
|
|
|
|
if is_p {
|
|
|
|
g.write('${str_fn_name}(')
|
|
|
|
g.write('),0))')
|
|
|
|
g.expr(expr)
|
|
|
|
} else {
|
|
|
|
g.write(').str')
|
|
|
|
g.write(',0)')
|
|
|
|
} else if sym.kind == .map && !sym.has_method('str') {
|
|
|
|
}
|
|
|
|
str_fn_name := g.gen_str_for_type(node.expr_types[i])
|
|
|
|
} else {
|
|
|
|
g.write('${str_fn_name}(')
|
|
|
|
if is_p {
|
|
|
|
g.expr(expr)
|
|
|
|
g.write(')))')
|
|
|
|
g.write(')')
|
|
|
|
} else {
|
|
|
|
g.write('.len, ')
|
|
|
|
g.write(')')
|
|
|
|
g.write('${str_fn_name}(')
|
|
|
|
}
|
|
|
|
g.expr(expr)
|
|
|
|
}
|
|
|
|
g.write(').str')
|
|
|
|
|
|
|
|
} else if sym.kind == .struct_ && !sym.has_method('str') {
|
|
|
|
|
|
|
|
str_fn_name := g.gen_str_for_type(node.expr_types[i])
|
|
|
|
|
|
|
|
g.write('${str_fn_name}(')
|
|
|
|
|
|
|
|
g.expr(expr)
|
|
|
|
|
|
|
|
g.write(',0)')
|
|
|
|
|
|
|
|
g.write('.len, ')
|
|
|
|
|
|
|
|
g.write('${str_fn_name}(')
|
|
|
|
|
|
|
|
g.expr(expr)
|
|
|
|
|
|
|
|
g.write(',0).str')
|
|
|
|
|
|
|
|
} else if g.typ(node.expr_types[i]).starts_with('Option') {
|
|
|
|
} else if g.typ(node.expr_types[i]).starts_with('Option') {
|
|
|
|
str_fn_name := 'Option_str'
|
|
|
|
str_fn_name := 'Option_str'
|
|
|
|
g.write('${str_fn_name}(*(Option*)&')
|
|
|
|
g.write('${str_fn_name}(*(Option*)&')
|
|
|
|
g.expr(expr)
|
|
|
|
g.expr(expr)
|
|
|
|
g.write(')')
|
|
|
|
g.write(')')
|
|
|
|
g.write('.len, ')
|
|
|
|
|
|
|
|
g.write('${str_fn_name}(*(Option*)&')
|
|
|
|
|
|
|
|
g.expr(expr)
|
|
|
|
|
|
|
|
g.write(').str')
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
g.expr(expr)
|
|
|
|
verror('cannot convert to string')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
g.expr(expr)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if specs[i] == `s` && fieldwidths[i] != 0 {
|
|
|
|
|
|
|
|
g.write(', ${fieldwidths[i]}')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if i < node.exprs.len - 1 {
|
|
|
|
if i < node.exprs.len - 1 {
|
|
|
|
g.write(', ')
|
|
|
|
g.write(', ')
|
|
|
@ -3191,9 +3286,9 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp, str_fn_name string) {
|
|
|
|
g.auto_str_funcs.writeln('\treturn _STR("${clean_struct_v_type_name} {\\n"')
|
|
|
|
g.auto_str_funcs.writeln('\treturn _STR("${clean_struct_v_type_name} {\\n"')
|
|
|
|
for field in info.fields {
|
|
|
|
for field in info.fields {
|
|
|
|
fmt := g.type_to_fmt(field.typ)
|
|
|
|
fmt := g.type_to_fmt(field.typ)
|
|
|
|
g.auto_str_funcs.writeln('\t\t"%.*s ' + '$field.name: $fmt\\n"')
|
|
|
|
g.auto_str_funcs.writeln('\t\t"%.*s\\000 ' + '$field.name: $fmt\\n"')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g.auto_str_funcs.write('\t\t"%.*s}"')
|
|
|
|
g.auto_str_funcs.write('\t\t"%.*s\\000}", ${2*(info.fields.len+1)}')
|
|
|
|
if info.fields.len > 0 {
|
|
|
|
if info.fields.len > 0 {
|
|
|
|
g.auto_str_funcs.write(',\n\t\t')
|
|
|
|
g.auto_str_funcs.write(',\n\t\t')
|
|
|
|
for i, field in info.fields {
|
|
|
|
for i, field in info.fields {
|
|
|
@ -3203,23 +3298,18 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp, str_fn_name string) {
|
|
|
|
field_styp := g.typ(field.typ)
|
|
|
|
field_styp := g.typ(field.typ)
|
|
|
|
field_styp_fn_name := if has_custom_str { '${field_styp}_str' } else { fnames2strfunc[field_styp] }
|
|
|
|
field_styp_fn_name := if has_custom_str { '${field_styp}_str' } else { fnames2strfunc[field_styp] }
|
|
|
|
if sym.kind == .enum_ {
|
|
|
|
if sym.kind == .enum_ {
|
|
|
|
g.auto_str_funcs.write('indents.len, indents.str, ')
|
|
|
|
g.auto_str_funcs.write('indents, ')
|
|
|
|
g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name} ).len, ')
|
|
|
|
g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name} ) ')
|
|
|
|
g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name} ).str ')
|
|
|
|
|
|
|
|
} else if sym.kind == .struct_ {
|
|
|
|
} else if sym.kind == .struct_ {
|
|
|
|
g.auto_str_funcs.write('indents.len, indents.str, ')
|
|
|
|
g.auto_str_funcs.write('indents, ')
|
|
|
|
g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name}${second_str_param} ).len, ')
|
|
|
|
g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name}${second_str_param} ) ')
|
|
|
|
g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name}${second_str_param} ).str ')
|
|
|
|
|
|
|
|
} else if sym.kind in [.array, .array_fixed] {
|
|
|
|
} else if sym.kind in [.array, .array_fixed] {
|
|
|
|
g.auto_str_funcs.write('indents.len, indents.str, ')
|
|
|
|
g.auto_str_funcs.write('indents, ')
|
|
|
|
g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name}).len, ')
|
|
|
|
g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name}) ')
|
|
|
|
g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name}).str ')
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
g.auto_str_funcs.write('indents.len, indents.str, it->${field.name}')
|
|
|
|
g.auto_str_funcs.write('indents, it->${field.name}')
|
|
|
|
if field.typ == table.string_type {
|
|
|
|
if field.typ == table.bool_type {
|
|
|
|
g.auto_str_funcs.write('.len, it->${field.name}.str')
|
|
|
|
g.auto_str_funcs.write(' ? _SLIT("true") : _SLIT("false")')
|
|
|
|
} else if field.typ == table.bool_type {
|
|
|
|
|
|
|
|
g.auto_str_funcs.write(' ? 4 : 5, it->${field.name} ? "true" : "false"')
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if i < info.fields.len - 1 {
|
|
|
|
if i < info.fields.len - 1 {
|
|
|
@ -3228,7 +3318,7 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp, str_fn_name string) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g.auto_str_funcs.writeln(',')
|
|
|
|
g.auto_str_funcs.writeln(',')
|
|
|
|
g.auto_str_funcs.writeln('\t\tindents.len, indents.str);')
|
|
|
|
g.auto_str_funcs.writeln('\t\tindents);')
|
|
|
|
g.auto_str_funcs.writeln('}')
|
|
|
|
g.auto_str_funcs.writeln('}')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -3247,7 +3337,7 @@ fn (mut g Gen) gen_str_for_array(info table.Array, styp, str_fn_name string) {
|
|
|
|
if sym.kind == .struct_ && !sym.has_method('str') {
|
|
|
|
if sym.kind == .struct_ && !sym.has_method('str') {
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${field_styp}_str(it,0));')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${field_styp}_str(it,0));')
|
|
|
|
} else if sym.kind in [.f32, .f64] {
|
|
|
|
} else if sym.kind in [.f32, .f64] {
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("%g", it));')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("%g", 1, it));')
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${field_styp}_str(it));')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${field_styp}_str(it));')
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -3274,9 +3364,9 @@ fn (mut g Gen) gen_str_for_array_fixed(info table.ArrayFixed, styp, str_fn_name
|
|
|
|
if sym.kind == .struct_ && !sym.has_method('str') {
|
|
|
|
if sym.kind == .struct_ && !sym.has_method('str') {
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${field_styp}_str(a[i],0));')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${field_styp}_str(a[i],0));')
|
|
|
|
} else if sym.kind in [.f32, .f64] {
|
|
|
|
} else if sym.kind in [.f32, .f64] {
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("%g", a[i]));')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("%g", 1, a[i]));')
|
|
|
|
} else if sym.kind == .string {
|
|
|
|
} else if sym.kind == .string {
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("\'%.*s\'", a[i].len, a[i].str));')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("\'%.*s\\000\'", 2, a[i]));')
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${field_styp}_str(a[i]));')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${field_styp}_str(a[i]));')
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -3307,18 +3397,18 @@ fn (mut g Gen) gen_str_for_map(info table.Map, styp, str_fn_name string) {
|
|
|
|
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, tos3("{"));')
|
|
|
|
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, tos3("{"));')
|
|
|
|
g.auto_str_funcs.writeln('\tfor (unsigned int i = 0; i < m.key_values.size; i++) {')
|
|
|
|
g.auto_str_funcs.writeln('\tfor (unsigned int i = 0; i < m.key_values.size; i++) {')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstring key = (*(string*)DenseArray_get(m.key_values, i));')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstring key = (*(string*)DenseArray_get(m.key_values, i));')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("\'%.*s\'", key.len, key.str));')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("\'%.*s\\000\'", 2, key));')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, tos3(": "));')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, tos3(": "));')
|
|
|
|
g.auto_str_funcs.write('\t$val_styp it = (*($val_styp*)map_get3(')
|
|
|
|
g.auto_str_funcs.write('\t$val_styp it = (*($val_styp*)map_get3(')
|
|
|
|
g.auto_str_funcs.write('m, (*(string*)DenseArray_get(m.key_values, i))')
|
|
|
|
g.auto_str_funcs.write('m, (*(string*)DenseArray_get(m.key_values, i))')
|
|
|
|
g.auto_str_funcs.write(', ')
|
|
|
|
g.auto_str_funcs.write(', ')
|
|
|
|
g.auto_str_funcs.writeln(' &($val_styp[]) { $zero }));')
|
|
|
|
g.auto_str_funcs.writeln(' &($val_styp[]) { $zero }));')
|
|
|
|
if val_sym.kind == .string {
|
|
|
|
if val_sym.kind == .string {
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("\'%.*s\'", it.len, it.str));')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("\'%.*s\\000\'", 2, it));')
|
|
|
|
} else if val_sym.kind == .struct_ && !val_sym.has_method('str') {
|
|
|
|
} else if val_sym.kind == .struct_ && !val_sym.has_method('str') {
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${val_styp}_str(it,0));')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${val_styp}_str(it,0));')
|
|
|
|
} else if val_sym.kind in [.f32, .f64] {
|
|
|
|
} else if val_sym.kind in [.f32, .f64] {
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("%g", it));')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("%g", 1, it));')
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${val_styp}_str(it));')
|
|
|
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${val_styp}_str(it));')
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -3350,17 +3440,17 @@ fn (mut g Gen) gen_str_for_varg(styp, str_fn_name string) {
|
|
|
|
fn (g Gen) type_to_fmt(typ table.Type) string {
|
|
|
|
fn (g Gen) type_to_fmt(typ table.Type) string {
|
|
|
|
sym := g.table.get_type_symbol(typ)
|
|
|
|
sym := g.table.get_type_symbol(typ)
|
|
|
|
if sym.kind in [.struct_, .array, .array_fixed, .map] {
|
|
|
|
if sym.kind in [.struct_, .array, .array_fixed, .map] {
|
|
|
|
return '%.*s'
|
|
|
|
return '%.*s\\000'
|
|
|
|
} else if typ == table.string_type {
|
|
|
|
} else if typ == table.string_type {
|
|
|
|
return "\'%.*s\'"
|
|
|
|
return "\'%.*s\\000\'"
|
|
|
|
} else if typ == table.bool_type {
|
|
|
|
} else if typ == table.bool_type {
|
|
|
|
return '%.*s'
|
|
|
|
return '%.*s\\000'
|
|
|
|
} else if sym.kind == .enum_ {
|
|
|
|
} else if sym.kind == .enum_ {
|
|
|
|
return '%.*s'
|
|
|
|
return '%.*s\\000'
|
|
|
|
} else if typ in [table.f32_type, table.f64_type] {
|
|
|
|
} else if typ in [table.f32_type, table.f64_type] {
|
|
|
|
return '%g' // g removes trailing zeros unlike %f
|
|
|
|
return '%g\\000' // g removes trailing zeros unlike %f
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return '%d'
|
|
|
|
return '%d\\000'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Generates interface table and interface indexes
|
|
|
|
// Generates interface table and interface indexes
|
|
|
|