2021-01-18 13:20:06 +01:00
|
|
|
// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
|
2020-06-29 17:47:01 +02:00
|
|
|
// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
|
2021-02-02 15:41:51 +01:00
|
|
|
module c
|
2020-05-02 11:11:27 +02:00
|
|
|
|
2020-06-29 17:47:01 +02:00
|
|
|
import v.ast
|
2020-11-18 18:23:44 +01:00
|
|
|
import v.util
|
2020-06-29 17:47:01 +02:00
|
|
|
|
2020-05-02 11:11:27 +02:00
|
|
|
fn (mut g Gen) write_str_fn_definitions() {
|
2021-04-14 07:50:50 +02:00
|
|
|
g.writeln(c_str_fn_defs)
|
2020-05-02 11:11:27 +02:00
|
|
|
}
|
2020-06-29 17:47:01 +02:00
|
|
|
|
|
|
|
fn (mut g Gen) string_literal(node ast.StringLiteral) {
|
|
|
|
if node.is_raw {
|
2020-11-18 18:23:44 +01:00
|
|
|
escaped_val := util.smart_quote(node.val, true)
|
2020-12-03 16:02:48 +01:00
|
|
|
g.write('_SLIT("$escaped_val")')
|
2020-06-29 17:47:01 +02:00
|
|
|
return
|
|
|
|
}
|
2020-11-18 18:23:44 +01:00
|
|
|
escaped_val := util.smart_quote(node.val, false)
|
2020-06-29 17:47:01 +02:00
|
|
|
if g.is_c_call || node.language == .c {
|
|
|
|
// In C calls we have to generate C strings
|
|
|
|
// `C.printf("hi")` => `printf("hi");`
|
|
|
|
g.write('"$escaped_val"')
|
|
|
|
} else {
|
2020-12-03 16:02:48 +01:00
|
|
|
g.write('_SLIT("$escaped_val")')
|
2020-06-29 17:47:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-11 12:03:24 +02:00
|
|
|
// optimize string interpolation in string builders:
|
|
|
|
// `sb.writeln('a=$a')` =>
|
|
|
|
// `sb.writeln('a='); sb.writeln(a.str())`
|
|
|
|
fn (mut g Gen) string_inter_literal_sb_optimized(call_expr ast.CallExpr) {
|
|
|
|
node := call_expr.args[0].expr as ast.StringInterLiteral
|
|
|
|
// sb_name := g.cur_call_expr.left
|
|
|
|
// g.go_before_stmt(0)
|
|
|
|
g.writeln('// sb inter opt')
|
2020-07-13 18:59:39 +02:00
|
|
|
is_nl := call_expr.name == 'writeln'
|
|
|
|
// println('optimize sb $call_expr.name')
|
2020-07-11 12:03:24 +02:00
|
|
|
for i, val in node.vals {
|
2020-11-18 18:23:44 +01:00
|
|
|
escaped_val := util.smart_quote(val, false)
|
2020-07-11 12:03:24 +02:00
|
|
|
// if val == '' {
|
|
|
|
// break
|
|
|
|
// continue
|
|
|
|
// }
|
2021-02-22 12:18:11 +01:00
|
|
|
g.write('strings__Builder_write_string(&')
|
2020-07-11 12:03:24 +02:00
|
|
|
g.expr(call_expr.left)
|
2020-12-03 16:02:48 +01:00
|
|
|
g.write(', _SLIT("')
|
2020-07-11 12:03:24 +02:00
|
|
|
g.write(escaped_val)
|
|
|
|
g.writeln('"));')
|
|
|
|
//
|
|
|
|
if i >= node.exprs.len {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
// if node.expr_types.len <= i || node.exprs.len <= i {
|
|
|
|
// continue
|
|
|
|
// }
|
2020-07-13 18:59:39 +02:00
|
|
|
if is_nl && i == node.exprs.len - 1 {
|
|
|
|
g.write('strings__Builder_writeln(&')
|
|
|
|
} else {
|
2021-02-22 12:18:11 +01:00
|
|
|
g.write('strings__Builder_write_string(&')
|
2020-07-13 18:59:39 +02:00
|
|
|
}
|
2020-07-11 12:03:24 +02:00
|
|
|
g.expr(call_expr.left)
|
|
|
|
g.write(', ')
|
2020-07-13 18:59:39 +02:00
|
|
|
typ := node.expr_types[i]
|
2020-11-03 14:13:35 +01:00
|
|
|
g.write(g.typ(typ))
|
|
|
|
g.write('_str(')
|
2020-12-17 10:16:27 +01:00
|
|
|
sym := g.table.get_type_symbol(typ)
|
|
|
|
if sym.kind != .function {
|
|
|
|
g.expr(node.exprs[i])
|
|
|
|
}
|
2020-07-11 12:03:24 +02:00
|
|
|
g.writeln('));')
|
|
|
|
}
|
|
|
|
g.writeln('')
|
|
|
|
// println(node.vals)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-06-29 17:47:01 +02:00
|
|
|
fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
|
|
|
g.write('_STR("')
|
|
|
|
// Build the string with %
|
|
|
|
mut end_string := false
|
|
|
|
for i, val in node.vals {
|
2020-10-04 10:34:04 +02:00
|
|
|
mut escaped_val := val.replace_each(['%', '%%'])
|
2020-11-18 18:23:44 +01:00
|
|
|
escaped_val = util.smart_quote(escaped_val, false)
|
2020-06-29 17:47:01 +02:00
|
|
|
if i >= node.exprs.len {
|
|
|
|
if escaped_val.len > 0 {
|
|
|
|
end_string = true
|
|
|
|
g.write('\\000')
|
|
|
|
g.write(escaped_val)
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
g.write(escaped_val)
|
2021-03-09 12:25:31 +01:00
|
|
|
mut typ := g.unwrap_generic(node.expr_types[i])
|
|
|
|
sym := g.table.get_type_symbol(typ)
|
|
|
|
if sym.kind == .alias {
|
2021-04-02 00:57:09 +02:00
|
|
|
typ = (sym.info as ast.Alias).parent_type
|
2021-03-09 12:25:31 +01:00
|
|
|
}
|
2020-06-29 17:47:01 +02:00
|
|
|
// write correct format specifier to intermediate string
|
|
|
|
g.write('%')
|
|
|
|
fspec := node.fmts[i]
|
|
|
|
mut fmt := if node.pluss[i] { '+' } else { '' }
|
|
|
|
if node.fills[i] && node.fwidths[i] >= 0 {
|
|
|
|
fmt = '${fmt}0'
|
|
|
|
}
|
|
|
|
if node.fwidths[i] != 0 {
|
|
|
|
fmt = '$fmt${node.fwidths[i]}'
|
|
|
|
}
|
2020-10-16 16:28:11 +02:00
|
|
|
if node.precisions[i] != 987698 {
|
2020-06-29 17:47:01 +02:00
|
|
|
fmt = '${fmt}.${node.precisions[i]}'
|
|
|
|
}
|
|
|
|
if fspec == `s` {
|
|
|
|
if node.fwidths[i] == 0 {
|
|
|
|
g.write('.*s')
|
|
|
|
} else {
|
|
|
|
g.write('*.*s')
|
|
|
|
}
|
2020-10-31 18:43:06 +01:00
|
|
|
} else if typ.is_float() {
|
2020-06-29 17:47:01 +02:00
|
|
|
g.write('$fmt${fspec:c}')
|
2020-10-31 18:43:06 +01:00
|
|
|
} else if typ.is_pointer() {
|
2020-06-29 17:47:01 +02:00
|
|
|
if fspec == `p` {
|
|
|
|
g.write('${fmt}p')
|
|
|
|
} else {
|
|
|
|
g.write('$fmt"PRI${fspec:c}PTR"')
|
|
|
|
}
|
2020-10-31 18:43:06 +01:00
|
|
|
} else if typ.is_int() {
|
2020-06-29 17:47:01 +02:00
|
|
|
if fspec == `c` {
|
|
|
|
g.write('${fmt}c')
|
|
|
|
} else {
|
|
|
|
g.write('$fmt"PRI${fspec:c}')
|
2021-04-02 00:57:09 +02:00
|
|
|
if typ in [ast.i8_type, ast.byte_type] {
|
2020-06-29 17:47:01 +02:00
|
|
|
g.write('8')
|
2021-04-02 00:57:09 +02:00
|
|
|
} else if typ in [ast.i16_type, ast.u16_type] {
|
2020-06-29 17:47:01 +02:00
|
|
|
g.write('16')
|
2021-04-02 00:57:09 +02:00
|
|
|
} else if typ in [ast.i64_type, ast.u64_type] {
|
2020-06-29 17:47:01 +02:00
|
|
|
g.write('64')
|
|
|
|
} else {
|
|
|
|
g.write('32')
|
|
|
|
}
|
|
|
|
g.write('"')
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// TODO: better check this case
|
|
|
|
g.write('$fmt"PRId32"')
|
|
|
|
}
|
|
|
|
if i < node.exprs.len - 1 {
|
|
|
|
g.write('\\000')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
num_string_parts := if end_string { node.exprs.len + 1 } else { node.exprs.len }
|
|
|
|
g.write('", $num_string_parts, ')
|
|
|
|
// Build args
|
|
|
|
for i, expr in node.exprs {
|
2020-10-31 18:43:06 +01:00
|
|
|
typ := g.unwrap_generic(node.expr_types[i])
|
2021-04-02 00:57:09 +02:00
|
|
|
if typ == ast.string_type {
|
2020-06-29 17:47:01 +02:00
|
|
|
if g.inside_vweb_tmpl {
|
|
|
|
g.write('vweb__filter(')
|
2021-02-21 11:15:36 +01:00
|
|
|
if expr.is_auto_deref_var() {
|
2021-02-16 13:24:19 +01:00
|
|
|
g.write('*')
|
|
|
|
}
|
2020-06-29 17:47:01 +02:00
|
|
|
g.expr(expr)
|
|
|
|
g.write(')')
|
|
|
|
} else {
|
2021-02-21 11:15:36 +01:00
|
|
|
if expr.is_auto_deref_var() {
|
2021-02-16 13:24:19 +01:00
|
|
|
g.write('*')
|
|
|
|
}
|
2020-06-29 17:47:01 +02:00
|
|
|
g.expr(expr)
|
|
|
|
}
|
2020-12-01 16:09:03 +01:00
|
|
|
} else if node.fmts[i] == `s` || typ.has_flag(.variadic) {
|
2020-12-01 04:00:23 +01:00
|
|
|
g.gen_expr_to_string(expr, typ)
|
2020-10-31 18:43:06 +01:00
|
|
|
} else if typ.is_number() || typ.is_pointer() || node.fmts[i] == `d` {
|
|
|
|
if typ.is_signed() && node.fmts[i] in [`x`, `X`, `o`] {
|
2020-06-29 17:47:01 +02:00
|
|
|
// convert to unsigned first befors C's integer propagation strikes
|
2021-04-02 00:57:09 +02:00
|
|
|
if typ == ast.i8_type {
|
2020-06-29 17:47:01 +02:00
|
|
|
g.write('(byte)(')
|
2021-04-02 00:57:09 +02:00
|
|
|
} else if typ == ast.i16_type {
|
2020-06-29 17:47:01 +02:00
|
|
|
g.write('(u16)(')
|
2021-04-02 00:57:09 +02:00
|
|
|
} else if typ == ast.int_type {
|
2020-06-29 17:47:01 +02:00
|
|
|
g.write('(u32)(')
|
|
|
|
} else {
|
|
|
|
g.write('(u64)(')
|
|
|
|
}
|
2021-02-21 11:15:36 +01:00
|
|
|
if expr.is_auto_deref_var() {
|
2021-02-16 13:24:19 +01:00
|
|
|
g.write('*')
|
|
|
|
}
|
2020-06-29 17:47:01 +02:00
|
|
|
g.expr(expr)
|
|
|
|
g.write(')')
|
|
|
|
} else {
|
2021-02-21 11:15:36 +01:00
|
|
|
if expr.is_auto_deref_var() {
|
2021-02-16 13:24:19 +01:00
|
|
|
g.write('*')
|
|
|
|
}
|
2020-06-29 17:47:01 +02:00
|
|
|
g.expr(expr)
|
|
|
|
}
|
|
|
|
} else {
|
2021-02-21 11:15:36 +01:00
|
|
|
if expr.is_auto_deref_var() {
|
2021-02-16 13:24:19 +01:00
|
|
|
g.write('*')
|
|
|
|
}
|
2020-06-29 17:47:01 +02:00
|
|
|
g.expr(expr)
|
|
|
|
}
|
|
|
|
if node.fmts[i] == `s` && node.fwidths[i] != 0 {
|
|
|
|
g.write(', ${node.fwidths[i]}')
|
|
|
|
}
|
|
|
|
if i < node.exprs.len - 1 {
|
|
|
|
g.write(', ')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g.write(')')
|
|
|
|
}
|
2020-12-01 16:09:03 +01:00
|
|
|
|
2021-04-02 00:57:09 +02:00
|
|
|
fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
|
2021-02-16 12:40:13 +01:00
|
|
|
is_shared := etype.has_flag(.shared_f)
|
2020-12-01 16:09:03 +01:00
|
|
|
mut typ := etype
|
2021-02-16 12:40:13 +01:00
|
|
|
if is_shared {
|
|
|
|
typ = typ.clear_flag(.shared_f).set_nr_muls(0)
|
|
|
|
}
|
2020-12-01 16:09:03 +01:00
|
|
|
mut sym := g.table.get_type_symbol(typ)
|
|
|
|
// when type is alias, print the aliased value
|
2021-04-02 00:57:09 +02:00
|
|
|
if mut sym.info is ast.Alias {
|
2020-12-01 16:09:03 +01:00
|
|
|
parent_sym := g.table.get_type_symbol(sym.info.parent_type)
|
|
|
|
if parent_sym.has_method('str') {
|
|
|
|
typ = sym.info.parent_type
|
|
|
|
sym = parent_sym
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
|
|
|
if typ.has_flag(.variadic) {
|
|
|
|
str_fn_name := g.gen_str_for_type(typ)
|
|
|
|
g.write('${str_fn_name}(')
|
|
|
|
g.expr(expr)
|
|
|
|
g.write(')')
|
2021-04-02 00:57:09 +02:00
|
|
|
} else if typ == ast.string_type {
|
2020-12-01 16:09:03 +01:00
|
|
|
g.expr(expr)
|
2021-04-02 00:57:09 +02:00
|
|
|
} else if typ == ast.bool_type {
|
2020-12-01 16:09:03 +01:00
|
|
|
g.expr(expr)
|
|
|
|
g.write(' ? _SLIT("true") : _SLIT("false")')
|
|
|
|
} else if sym.kind == .none_ {
|
2021-01-29 14:50:48 +01:00
|
|
|
g.write('_SLIT("<none>")')
|
2020-12-01 16:09:03 +01:00
|
|
|
} else if sym.kind == .enum_ {
|
|
|
|
is_var := match expr {
|
|
|
|
ast.SelectorExpr, ast.Ident { true }
|
|
|
|
else { false }
|
|
|
|
}
|
|
|
|
if is_var {
|
|
|
|
str_fn_name := g.gen_str_for_type(typ)
|
|
|
|
g.write('${str_fn_name}(')
|
|
|
|
g.enum_expr(expr)
|
|
|
|
g.write(')')
|
|
|
|
} else {
|
|
|
|
g.write('_SLIT("')
|
|
|
|
g.enum_expr(expr)
|
|
|
|
g.write('")')
|
|
|
|
}
|
2021-01-23 09:33:22 +01:00
|
|
|
} else if sym_has_str_method
|
|
|
|
|| sym.kind in [.array, .array_fixed, .map, .struct_, .multi_return, .sum_type, .interface_] {
|
2020-12-01 16:09:03 +01:00
|
|
|
is_ptr := typ.is_ptr()
|
2021-02-21 11:15:36 +01:00
|
|
|
is_var_mut := expr.is_auto_deref_var()
|
2020-12-01 16:09:03 +01:00
|
|
|
str_fn_name := g.gen_str_for_type(typ)
|
2021-01-31 02:45:45 +01:00
|
|
|
if is_ptr && !is_var_mut {
|
2020-12-01 16:09:03 +01:00
|
|
|
g.write('_STR("&%.*s\\000", 2, ')
|
|
|
|
}
|
|
|
|
g.write('${str_fn_name}(')
|
|
|
|
if str_method_expects_ptr && !is_ptr {
|
|
|
|
g.write('&')
|
2021-02-16 12:40:13 +01:00
|
|
|
} else if (!str_method_expects_ptr && is_ptr && !is_shared) || is_var_mut {
|
2020-12-01 16:09:03 +01:00
|
|
|
g.write('*')
|
|
|
|
}
|
|
|
|
if expr is ast.ArrayInit {
|
|
|
|
if expr.is_fixed {
|
|
|
|
s := g.typ(expr.typ)
|
|
|
|
g.write('($s)')
|
|
|
|
}
|
|
|
|
}
|
2021-04-19 14:38:48 +02:00
|
|
|
g.expr_with_cast(expr, typ, typ)
|
2021-02-16 12:40:13 +01:00
|
|
|
if is_shared {
|
|
|
|
g.write('->val')
|
|
|
|
}
|
2020-12-01 16:09:03 +01:00
|
|
|
g.write(')')
|
2021-01-31 02:45:45 +01:00
|
|
|
if is_ptr && !is_var_mut {
|
2020-12-01 16:09:03 +01:00
|
|
|
g.write(')')
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
str_fn_name := g.gen_str_for_type(typ)
|
|
|
|
g.write('${str_fn_name}(')
|
2020-12-17 10:16:27 +01:00
|
|
|
if sym.kind != .function {
|
2021-04-19 14:38:48 +02:00
|
|
|
g.expr_with_cast(expr, typ, typ)
|
2020-12-17 10:16:27 +01:00
|
|
|
}
|
2020-12-01 16:09:03 +01:00
|
|
|
g.write(')')
|
|
|
|
}
|
|
|
|
}
|