diff --git a/vlib/strings/builder.v b/vlib/strings/builder.v index 610c933515..a70d30bb53 100644 --- a/vlib/strings/builder.v +++ b/vlib/strings/builder.v @@ -32,6 +32,7 @@ pub fn (mut b Builder) write_b(data byte) { b.len++ } +[inline] pub fn (mut b Builder) write(s string) { if s == '' { return @@ -77,6 +78,7 @@ pub fn (mut b Builder) go_back_to(pos int) { b.len = pos } +[inline] pub fn (mut b Builder) writeln(s string) { // for c in s { // b.buf << c diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index ae4a8d74fc..07ce6b467c 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -3599,9 +3599,8 @@ fn (mut g Gen) write_expr_to_string(expr ast.Expr) string { return g.out.cut_last(g.out.buf.len - pos) } -fn (mut g Gen) start_tmp() { -} - +// fn (mut g Gen) start_tmp() { +// } // If user is accessing the return value eg. in assigment, pass the variable name. // If the user is not using the optional return value. We need to pass a temp var // to access its fields (`.ok`, `.error` etc) diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index f2b83d0810..a4bf180a30 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -28,7 +28,7 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) { g.cur_generic_type = 0 return } - //g.cur_fn = it + // g.cur_fn = it fn_start_pos := g.out.len msvc_attrs := g.write_fn_attrs() // Live @@ -270,7 +270,13 @@ fn (mut g Gen) call_expr(node ast.CallExpr) { g.write('$styp $tmp_opt = ') } if node.is_method { - g.method_call(node) + if node.name == 'writeln' && g.pref.show_cc && + node.args.len > 0 && node.args[0].expr is ast.StringInterLiteral && + g.table.get_type_symbol(node.receiver_type).name == 'strings.Builder' { + g.string_inter_literal_sb_optimized(node) + } else { + g.method_call(node) + } } else { g.fn_call(node) } diff --git a/vlib/v/gen/str.v b/vlib/v/gen/str.v index e49bcf7f82..93b81906b9 100644 --- a/vlib/v/gen/str.v +++ b/vlib/v/gen/str.v @@ -138,13 +138,61 @@ fn (mut g Gen) string_literal(node ast.StringLiteral) { } } +// 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') + write := 'writeln' + /* + if node.vals.len != node.exprs.len { + println('NOPE') + println(node.vals) + println('==========') + println(node.exprs) + } + */ + for i, val in node.vals { + escaped_val := val.replace_each(['"', '\\"', '\r\n', '\\n', '\n', '\\n', '%', '%%']) + // if val == '' { + // break + // continue + // } + g.write('strings__Builder_${write}(&') + g.expr(call_expr.left) + g.write(', tos_lit("') + g.write(escaped_val) + g.writeln('"));') + // + if i >= node.exprs.len { + break + } + // if node.expr_types.len <= i || node.exprs.len <= i { + // continue + // } + g.write('strings__Builder_${write}(&') + g.expr(call_expr.left) + g.write(', ') + g.write(g.typ(node.expr_types[i])) + g.write('_str(') + g.expr(node.exprs[i]) + g.writeln('));') + } + g.writeln('') + // println(node.vals) + return +} + fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) { mut cur_line := '' mut tmp := '' free := g.pref.autofree && g.inside_call && !g.inside_return && - g.inside_ternary == 0 && !g.inside_const - //&& g.cur_fn != 0 && - //g.cur_fn.name != '' + g.inside_ternary == 0 && !g.inside_const + // && g.cur_fn != 0 && + // g.cur_fn.name != '' if free { // Save the string expr in a temporary variable, so that it can be removed after the call. tmp = g.new_tmp_var()