From 57dd511c9d2fca2a98d9e8b247ee1a04a5a0106a Mon Sep 17 00:00:00 2001 From: Lukas Neubert Date: Fri, 15 Jan 2021 10:26:33 +0100 Subject: [PATCH] fmt: move all exprs and stmts to their own methods (#8107) --- vlib/v/fmt/fmt.v | 1307 +++++++++++++++++++++++++--------------------- 1 file changed, 725 insertions(+), 582 deletions(-) diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index f034f531cc..0c70ff9ce8 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -189,11 +189,87 @@ fn (mut f Fmt) adjust_complete_line() { } } +pub fn (mut f Fmt) wrap_long_line(penalty_idx int, add_indent bool) bool { + if f.line_len <= max_len[penalty_idx] { + return false + } + if f.out.buf[f.out.buf.len - 1] == ` ` { + f.out.go_back(1) + } + f.write('\n') + if add_indent { + f.indent++ + } + f.write_indent() + if add_indent { + f.indent-- + } + f.line_len = 0 + return true +} + +pub fn (mut f Fmt) remove_new_line() { + mut i := 0 + for i = f.out.len - 1; i >= 0; i-- { + if !f.out.buf[i].is_space() { // != `\n` { + break + } + } + f.out.go_back(f.out.len - i - 1) + f.empty_line = false + // f.writeln('sdf') +} + pub fn (mut f Fmt) set_current_module_name(cmodname string) { f.cur_mod = cmodname f.table.cmod_prefix = cmodname + '.' } +fn (f Fmt) get_modname_prefix(mname string) (string, string) { + // ./tests/proto_module_importing_vproto_keep.vv to know, why here is checked for ']' and '&' + if !mname.contains(']') && !mname.contains('&') { + return mname, '' + } + after_rbc := mname.all_after_last(']') + after_ref := mname.all_after_last('&') + modname := if after_rbc.len < after_ref.len { after_rbc } else { after_ref } + return modname, mname.trim_suffix(modname) +} + +pub fn (mut f Fmt) no_cur_mod(typename string) string { + return util.no_cur_mod(typename, f.cur_mod) +} + +// foo.bar.fn() => bar.fn() +pub fn (mut f Fmt) short_module(name string) string { + if !name.contains('.') { + return name + } + if name in f.mod2alias { + return f.mod2alias[name] + } + if name.ends_with('>') { + x := name.trim_suffix('>').split('<') + if x.len == 2 { + main := f.short_module(x[0]) + genlist := x[1].split(',') + genshorts := genlist.map(f.short_module(it)).join(',') + return '$main<$genshorts>' + } + } + vals := name.split('.') + if vals.len < 2 { + return name + } + mname, tprefix := f.get_modname_prefix(vals[vals.len - 2]) + symname := vals[vals.len - 1] + aname := f.mod2alias[mname] + if aname == '' { + return symname + } + return '$tprefix${aname}.$symname' +} + pub fn (mut f Fmt) mod(mod ast.Module) { f.set_current_module_name(mod.name) if mod.is_skipped { @@ -203,6 +279,25 @@ pub fn (mut f Fmt) mod(mod ast.Module) { f.writeln('module $mod.name\n') } +pub fn (mut f Fmt) mark_types_import_as_used(typ table.Type) { + sym := f.table.get_type_symbol(typ) + f.mark_import_as_used(sym.name) +} + +// `name` is a function (`foo.bar()`) or type (`foo.Bar{}`) +pub fn (mut f Fmt) mark_import_as_used(name string) { + if !name.contains('.') { + return + } + pos := name.last_index('.') or { 0 } + mod := name[..pos] + if mod in f.used_imports { + return + } + f.used_imports << mod + // println('marking module $mod as used') +} + pub fn (mut f Fmt) imports(imports []ast.Import) { if f.did_imports || imports.len == 0 { return @@ -267,163 +362,49 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) { } match node { ast.AssignStmt { - f.comments(node.comments, {}) - for i, left in node.left { - if left is ast.Ident { - var_info := left.var_info() - if var_info.is_static { - f.write('static ') - } - f.expr(left) - } else { - f.expr(left) - } - if i < node.left.len - 1 { - f.write(', ') - } - } - f.is_assign = true - f.write(' $node.op.str() ') - for i, val in node.right { - f.prefix_expr_cast_expr(val) - if i < node.right.len - 1 { - f.write(', ') - } - } - f.comments(node.end_comments, has_nl: false, inline: true, level: .keep) - if !f.single_line_if { - f.writeln('') - } - f.is_assign = false + f.assign_stmt(node) } ast.AssertStmt { - f.write('assert ') - f.expr(node.expr) - f.writeln('') + f.assert_stmt(node) } ast.Block { - if node.is_unsafe { - f.write('unsafe ') - } - f.write('{') - if node.stmts.len > 0 || node.pos.line_nr < node.pos.last_line { - f.writeln('') - f.stmts(node.stmts) - } - f.writeln('}') + f.block(node) } ast.BranchStmt { f.writeln(node.str()) } ast.CompFor { - typ := f.no_cur_mod(f.table.type_to_str(node.typ)) - f.write('\$for $node.val_var in ${typ}.$node.kind.str() {') - if node.stmts.len > 0 || node.pos.line_nr < node.pos.last_line { - f.writeln('') - f.stmts(node.stmts) - } - f.writeln('}') + f.comp_for(node) } ast.ConstDecl { f.const_decl(node) } ast.DeferStmt { - f.write('defer {') - if node.stmts.len > 0 || node.pos.line_nr < node.pos.last_line { - f.writeln('') - f.stmts(node.stmts) - } - f.writeln('}') + f.defer_stmt(node) } ast.EnumDecl { f.enum_decl(node) } ast.ExprStmt { - f.comments(node.comments, {}) - f.expr(node.expr) - if !f.single_line_if { - f.writeln('') - } + f.expr_stmt(node) } ast.FnDecl { f.fn_decl(node) } ast.ForCStmt { - if node.label.len > 0 { - f.write('$node.label: ') - } - f.write('for ') - if node.has_init { - f.single_line_if = true // to keep all for ;; exprs on the same line - f.stmt(node.init) - f.single_line_if = false - } - f.write('; ') - f.expr(node.cond) - f.write('; ') - f.stmt(node.inc) - f.remove_new_line() - f.write(' {') - if node.stmts.len > 0 || node.pos.line_nr < node.pos.last_line { - f.writeln('') - f.stmts(node.stmts) - } - f.writeln('}') + f.for_c_stmt(node) } ast.ForInStmt { - if node.label.len > 0 { - f.write('$node.label: ') - } - f.write('for ') - if node.key_var != '' { - f.write(node.key_var) - } - if node.val_var != '' { - if node.key_var != '' { - f.write(', ') - } - if node.val_is_mut { - f.write('mut ') - } - f.write(node.val_var) - } - f.write(' in ') - f.expr(node.cond) - if node.is_range { - f.write(' .. ') - f.expr(node.high) - } - f.write(' {') - if node.stmts.len > 0 || node.pos.line_nr < node.pos.last_line { - f.writeln('') - f.stmts(node.stmts) - } - f.writeln('}') + f.for_in_stmt(node) } ast.ForStmt { - if node.label.len > 0 { - f.write('$node.label: ') - } - f.write('for ') - f.expr(node.cond) - if node.is_inf { - f.write('{') - } else { - f.write(' {') - } - if node.stmts.len > 0 || node.pos.line_nr < node.pos.last_line { - f.writeln('') - f.stmts(node.stmts) - } - f.writeln('}') + f.for_stmt(node) } ast.GlobalDecl { f.global_decl(node) } ast.GoStmt { - f.write('go ') - f.expr(node.call_expr) - f.writeln('') + f.go_stmt(node) } ast.GotoLabel { f.writeln('$node.name:') @@ -445,55 +426,10 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) { f.mod(node) } ast.Return { - f.comments(node.comments, {}) - f.write('return') - if node.exprs.len > 1 { - // multiple returns - f.write(' ') - for i, expr in node.exprs { - f.expr(expr) - if i < node.exprs.len - 1 { - f.write(', ') - } - } - } else if node.exprs.len == 1 { - // normal return - f.write(' ') - f.expr(node.exprs[0]) - } - f.writeln('') + f.return_stmt(node) } ast.SqlStmt { - f.write('sql ') - f.expr(node.db_expr) - f.writeln(' {') - match node.kind { - .insert { - f.writeln('\tinsert $node.object_var_name into ${util.strip_mod_name(node.table_name)}') - } - .update { - f.write('\tupdate ${util.strip_mod_name(node.table_name)} set ') - for i, col in node.updated_columns { - f.write('$col = ') - f.expr(node.update_exprs[i]) - if i < node.updated_columns.len - 1 { - f.write(', ') - } else { - f.write(' ') - } - f.wrap_long_line(2, true) - } - f.write('where ') - f.expr(node.where_expr) - f.writeln('') - } - .delete { - f.write('\tdelete from ${util.strip_mod_name(node.table_name)} where ') - f.expr(node.where_expr) - f.writeln('') - } - } - f.writeln('}') + f.sql_stmt(node) } ast.StructDecl { f.struct_decl(node) @@ -505,6 +441,15 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) { } } +fn stmt_is_single_line(stmt ast.Stmt) bool { + match stmt { + ast.ExprStmt { return expr_is_single_line(stmt.expr) } + ast.Return { return true } + ast.AssignStmt { return true } + else { return false } + } +} + pub fn (mut f Fmt) type_decl(node ast.TypeDecl) { mut comments := []ast.Comment{} match node { @@ -902,35 +847,16 @@ pub fn (mut f Fmt) expr(node ast.Expr) { f.array_init(node) } ast.AsCast { - type_str := f.table.type_to_str(node.typ) - f.expr(node.expr) - f.write(' as $type_str') + f.as_cast(node) } ast.Assoc { - f.writeln('{') - // f.indent++ - f.writeln('\t$node.var_name |') - // TODO StructInit copy pasta - for i, field in node.fields { - f.write('\t$field: ') - f.expr(node.exprs[i]) - f.writeln('') - } - // f.indent-- - f.write('}') + f.assoc(node) } ast.BoolLiteral { f.write(node.val.str()) } ast.CastExpr { - node.typname = f.table.get_type_symbol(node.typ).name - f.write(f.table.type_to_str(node.typ) + '(') - f.expr(node.expr) - if node.has_arg { - f.write(', ') - f.expr(node.arg) - } - f.write(')') + f.cast_expr(node) } ast.AtExpr { f.at_expr(node) @@ -952,40 +878,16 @@ pub fn (mut f Fmt) expr(node ast.Expr) { } } ast.ComptimeCall { - if node.is_vweb { - if node.method_name == 'html' { - f.write('\$vweb.html()') - } else { - f.write("\$tmpl('$node.args_var')") - } - } else { - if node.is_embed { - f.write("\$embed_file('$node.embed_file.rpath')") - } else { - method_expr := if node.has_parens { - '(${node.method_name}($node.args_var))' - } else { - '${node.method_name}($node.args_var)' - } - f.write('${node.left}.$$method_expr') - } - } + f.comptime_call(node) } ast.ComptimeSelector { - field_expr := if node.has_parens { '($node.field_expr)' } else { node.field_expr.str() } - f.write('${node.left}.$$field_expr') + f.comptime_selector(node) } ast.ConcatExpr { - for i, val in node.vals { - if i != 0 { - f.write(', ') - } - f.expr(val) - } + f.concat_expr(node) } ast.EnumVal { - name := f.short_module(node.enum_name) - f.write(name + '.' + node.val) + f.enum_val(node) } ast.FloatLiteral { f.write(node.val) @@ -994,37 +896,16 @@ pub fn (mut f Fmt) expr(node ast.Expr) { f.if_expr(node) } ast.Ident { - if mut node.info is ast.IdentVar { - if node.info.is_mut { - f.write(node.info.share.str() + ' ') - } - } - f.write_language_prefix(node.language) - if node.name == 'it' && f.it_name != '' && !f.inside_lambda { // allow `it` in lambdas - f.write(f.it_name) - } else if node.kind == .blank_ident { - f.write('_') - } else { - name := f.short_module(node.name) - // f.write('<$it.name => $name>') - f.write(name) - if name.contains('.') { - f.mark_module_as_used(name) - } - } + f.ident(node) } ast.IfGuardExpr { - f.write(node.var_name + ' := ') - f.expr(node.expr) + f.if_guard_expr(node) } ast.InfixExpr { f.infix_expr(node) } ast.IndexExpr { - f.expr(node.left) - f.write('[') - f.expr(node.index) - f.write(']') + f.index_expr(node) } ast.IntegerLiteral { f.write(node.val) @@ -1042,196 +923,38 @@ pub fn (mut f Fmt) expr(node ast.Expr) { f.write('none') } ast.OrExpr { - // shouldn't happen, an or expression - // is always linked to a call expr + // shouldn't happen, an or expression is always linked to a call expr panic('fmt: OrExpr should be linked to CallExpr') } ast.ParExpr { - f.write('(') - f.par_level++ - f.expr(node.expr) - f.par_level-- - f.write(')') + f.par_expr(node) } ast.PostfixExpr { - f.expr(node.expr) - // `$if foo ?` - if node.op == .question { - f.write(' ?') - } else { - f.write('$node.op') - } + f.postfix_expr(node) } ast.PrefixExpr { - f.write(node.op.str()) - f.prefix_expr_cast_expr(node.right) + f.prefix_expr(node) } ast.RangeExpr { - f.expr(node.low) - if f.is_mbranch_expr { - f.write('...') - } else { - f.write('..') - } - f.expr(node.high) + f.range_expr(node) } ast.SelectExpr { - f.writeln('select {') - f.indent++ - for branch in node.branches { - if branch.comment.text != '' { - f.comment(branch.comment, inline: true) - f.writeln('') - } - if branch.is_else { - f.write('else {') - } else { - if branch.is_timeout { - f.write('> ') - } - f.single_line_if = true - match branch.stmt { - ast.ExprStmt { f.expr(branch.stmt.expr) } - else { f.stmt(branch.stmt) } - } - f.single_line_if = false - f.write(' {') - } - if branch.stmts.len > 0 { - f.writeln('') - f.stmts(branch.stmts) - } - f.writeln('}') - if branch.post_comments.len > 0 { - f.comments(branch.post_comments, inline: true) - } - } - f.indent-- - f.write('}') + f.select_expr(node) } ast.SelectorExpr { - f.expr(node.expr) - f.write('.') - f.write(node.field_name) + f.selector_expr(node) } ast.SizeOf { - f.write('sizeof(') - if node.is_type { - sym := f.table.get_type_symbol(node.typ) - if sym.name != '' { - if f.is_external_name(sym.name) { - f.write(sym.name) - } else { - f.write(f.short_module(sym.name)) - } - } else { - f.write(f.table.type_to_str(node.typ)) - } - } else { - f.expr(node.expr) - } - f.write(')') + f.size_of(node) } ast.SqlExpr { - // sql app.db { select from Contributor where repo == id && user == 0 } - f.write('sql ') - f.expr(node.db_expr) - f.writeln(' {') - f.write('\t') - f.write('select ') - esym := f.table.get_type_symbol(node.table_type) - node.table_name = esym.name - if node.is_count { - f.write('count ') - } else { - if node.fields.len > 0 { - for tfi, tf in node.fields { - f.write(tf.name) - if tfi < node.fields.len - 1 { - f.write(', ') - } - } - f.write(' ') - } - } - f.write('from ${util.strip_mod_name(node.table_name)}') - if node.has_where { - f.write(' where ') - f.expr(node.where_expr) - } - if node.has_order { - f.write(' order by ') - f.expr(node.order_expr) - if node.has_desc { - f.write(' desc') - } - } - if node.has_limit { - f.write(' limit ') - f.expr(node.limit_expr) - } - if node.has_offset { - f.write(' offset ') - f.expr(node.offset_expr) - } - f.writeln('') - f.write('}') + f.sql_expr(node) } ast.StringLiteral { - use_double_quote := node.val.contains("'") && !node.val.contains('"') - if node.is_raw { - f.write('r') - } else if node.language == table.Language.c { - f.write('c') - } - if node.is_raw { - if use_double_quote { - f.write('"$node.val"') - } else { - f.write("'$node.val'") - } - } else { - unescaped_val := node.val.replace('$bs$bs', '\x01').replace_each(["$bs'", "'", - '$bs"', '"']) - if use_double_quote { - s := unescaped_val.replace_each(['\x01', '$bs$bs', '"', '$bs"']) - f.write('"$s"') - } else { - s := unescaped_val.replace_each(['\x01', '$bs$bs', "'", "$bs'"]) - f.write("'$s'") - } - } + f.string_literal(node) } ast.StringInterLiteral { - // TODO: this code is very similar to ast.Expr.str() - mut quote := "'" - for val in node.vals { - if val.contains("'") { - quote = '"' - } - if val.contains('"') { - quote = "'" - break - } - } - f.write(quote) - for i, val in node.vals { - f.write(val) - if i >= node.exprs.len { - break - } - f.write('$') - fspec_str, needs_braces := node.get_fspec_braces(i) - if needs_braces { - f.write('{') - f.expr(node.exprs[i]) - f.write(fspec_str) - f.write('}') - } else { - f.expr(node.exprs[i]) - } - } - f.write(quote) + f.string_inter_literal(node) } ast.StructInit { f.struct_init(node) @@ -1240,82 +963,51 @@ pub fn (mut f Fmt) expr(node ast.Expr) { f.write(f.table.type_to_str(node.typ)) } ast.TypeOf { - f.write('typeof(') - f.expr(node.expr) - f.write(')') + f.type_of(node) } ast.Likely { - if node.is_likely { - f.write('_likely_') - } else { - f.write('_unlikely_') - } - f.write('(') - f.expr(node.expr) - f.write(')') + f.likely(node) } ast.UnsafeExpr { - single_line := node.pos.line_nr >= node.pos.last_line - f.write('unsafe {') - if single_line { - f.write(' ') - } else { - f.writeln('') - f.indent++ - f.empty_line = true - } - f.expr(node.expr) - if single_line { - f.write(' ') - } else { - f.writeln('') - f.indent-- - } - f.write('}') + f.unsafe_expr(node) } ast.ArrayDecompose { - f.write('...') - f.expr(node.expr) + f.array_decompose(node) } } } -pub fn (mut f Fmt) wrap_long_line(penalty_idx int, add_indent bool) bool { - if f.line_len <= max_len[penalty_idx] { - return false +fn expr_is_single_line(expr ast.Expr) bool { + match expr { + ast.AnonFn { + if !expr.decl.no_body { + return false + } + } + ast.IfExpr { + return false + } + ast.Comment { + return false + } + ast.MatchExpr { + return false + } + ast.StructInit { + if !expr.is_short && (expr.fields.len > 0 || expr.pre_comments.len > 0) { + return false + } + } + ast.CallExpr { + if expr.or_block.stmts.len > 1 { + return false + } + } + else {} } - if f.out.buf[f.out.buf.len - 1] == ` ` { - f.out.go_back(1) - } - f.write('\n') - if add_indent { - f.indent++ - } - f.write_indent() - if add_indent { - f.indent-- - } - f.line_len = 0 return true } -pub fn (mut f Fmt) call_args(args []ast.CallArg) { - f.single_line_fields = true - for i, arg in args { - if arg.is_mut { - f.write(arg.share.str() + ' ') - } - if i > 0 { - f.wrap_long_line(2, true) - } - f.expr(arg.expr) - if i < args.len - 1 { - f.write(', ') - } - } - f.single_line_fields = false -} - pub fn (mut f Fmt) or_expr(or_block ast.OrExpr) { match or_block.kind { .absent {} @@ -1404,43 +1096,352 @@ pub fn (mut f Fmt) fn_decl(node ast.FnDecl) { } // Mark all function's used type so that they are not removed from imports for arg in node.params { - f.mark_types_module_as_used(arg.typ) + f.mark_types_import_as_used(arg.typ) } - f.mark_types_module_as_used(node.return_type) + f.mark_types_import_as_used(node.return_type) } -pub fn (mut f Fmt) no_cur_mod(typename string) string { - return util.no_cur_mod(typename, f.cur_mod) +pub fn (mut f Fmt) as_cast(node ast.AsCast) { + type_str := f.table.type_to_str(node.typ) + f.expr(node.expr) + f.write(' as $type_str') } -// foo.bar.fn() => bar.fn() -pub fn (mut f Fmt) short_module(name string) string { - if !name.contains('.') { - return name +pub fn (mut f Fmt) cast_expr(node ast.CastExpr) { + f.write(f.table.type_to_str(node.typ) + '(') + f.expr(node.expr) + if node.has_arg { + f.write(', ') + f.expr(node.arg) } - if name in f.mod2alias { - return f.mod2alias[name] + f.write(')') +} + +pub fn (mut f Fmt) assoc(node ast.Assoc) { + f.writeln('{') + // f.indent++ + f.writeln('\t$node.var_name |') + // TODO StructInit copy pasta + for i, field in node.fields { + f.write('\t$field: ') + f.expr(node.exprs[i]) + f.writeln('') } - if name.ends_with('>') { - x := name.trim_suffix('>').split('<') - if x.len == 2 { - main := f.short_module(x[0]) - genlist := x[1].split(',') - genshorts := genlist.map(f.short_module(it)).join(',') - return '$main<$genshorts>' + // f.indent-- + f.write('}') +} + +pub fn (mut f Fmt) comptime_call(node ast.ComptimeCall) { + if node.is_vweb { + if node.method_name == 'html' { + f.write('\$vweb.html()') + } else { + f.write("\$tmpl('$node.args_var')") + } + } else { + if node.is_embed { + f.write("\$embed_file('$node.embed_file.rpath')") + } else { + method_expr := if node.has_parens { + '(${node.method_name}($node.args_var))' + } else { + '${node.method_name}($node.args_var)' + } + f.write('${node.left}.$$method_expr') } } - vals := name.split('.') - if vals.len < 2 { - return name +} + +pub fn (mut f Fmt) comptime_selector(node ast.ComptimeSelector) { + field_expr := if node.has_parens { '($node.field_expr)' } else { node.field_expr.str() } + f.write('${node.left}.$$field_expr') +} + +pub fn (mut f Fmt) concat_expr(node ast.ConcatExpr) { + for i, val in node.vals { + if i != 0 { + f.write(', ') + } + f.expr(val) } - mname, tprefix := f.get_modname_prefix(vals[vals.len - 2]) - symname := vals[vals.len - 1] - aname := f.mod2alias[mname] - if aname == '' { - return symname +} + +pub fn (mut f Fmt) enum_val(node ast.EnumVal) { + name := f.short_module(node.enum_name) + f.write(name + '.' + node.val) +} + +pub fn (mut f Fmt) ident(node ast.Ident) { + if mut node.info is ast.IdentVar { + if node.info.is_mut { + f.write(node.info.share.str() + ' ') + } } - return '$tprefix${aname}.$symname' + f.write_language_prefix(node.language) + if node.name == 'it' && f.it_name != '' && !f.inside_lambda { // allow `it` in lambdas + f.write(f.it_name) + } else if node.kind == .blank_ident { + f.write('_') + } else { + name := f.short_module(node.name) + // f.write('<$it.name => $name>') + f.write(name) + if name.contains('.') { + f.mark_import_as_used(name) + } + } +} + +pub fn (mut f Fmt) if_guard_expr(node ast.IfGuardExpr) { + f.write(node.var_name + ' := ') + f.expr(node.expr) +} + +pub fn (mut f Fmt) index_expr(node ast.IndexExpr) { + f.expr(node.left) + f.write('[') + f.expr(node.index) + f.write(']') +} + +pub fn (mut f Fmt) par_expr(node ast.ParExpr) { + f.write('(') + f.par_level++ + f.expr(node.expr) + f.par_level-- + f.write(')') +} + +pub fn (mut f Fmt) postfix_expr(node ast.PostfixExpr) { + f.expr(node.expr) + // `$if foo ?` + if node.op == .question { + f.write(' ?') + } else { + f.write('$node.op') + } +} + +pub fn (mut f Fmt) prefix_expr(node ast.PrefixExpr) { + f.write(node.op.str()) + f.prefix_expr_cast_expr(node.right) +} + +pub fn (mut f Fmt) range_expr(node ast.RangeExpr) { + f.expr(node.low) + if f.is_mbranch_expr { + f.write('...') + } else { + f.write('..') + } + f.expr(node.high) +} + +pub fn (mut f Fmt) select_expr(node ast.SelectExpr) { + f.writeln('select {') + f.indent++ + for branch in node.branches { + if branch.comment.text != '' { + f.comment(branch.comment, inline: true) + f.writeln('') + } + if branch.is_else { + f.write('else {') + } else { + if branch.is_timeout { + f.write('> ') + } + f.single_line_if = true + match branch.stmt { + ast.ExprStmt { f.expr(branch.stmt.expr) } + else { f.stmt(branch.stmt) } + } + f.single_line_if = false + f.write(' {') + } + if branch.stmts.len > 0 { + f.writeln('') + f.stmts(branch.stmts) + } + f.writeln('}') + if branch.post_comments.len > 0 { + f.comments(branch.post_comments, inline: true) + } + } + f.indent-- + f.write('}') +} + +pub fn (mut f Fmt) selector_expr(node ast.SelectorExpr) { + f.expr(node.expr) + f.write('.') + f.write(node.field_name) +} + +pub fn (mut f Fmt) size_of(node ast.SizeOf) { + f.write('sizeof(') + if node.is_type { + sym := f.table.get_type_symbol(node.typ) + if sym.name != '' { + if f.is_external_name(sym.name) { + f.write(sym.name) + } else { + f.write(f.short_module(sym.name)) + } + } else { + f.write(f.table.type_to_str(node.typ)) + } + } else { + f.expr(node.expr) + } + f.write(')') +} + +pub fn (mut f Fmt) sql_expr(node ast.SqlExpr) { + // sql app.db { select from Contributor where repo == id && user == 0 } + f.write('sql ') + f.expr(node.db_expr) + f.writeln(' {') + f.write('\t') + f.write('select ') + esym := f.table.get_type_symbol(node.table_type) + table_name := esym.name + if node.is_count { + f.write('count ') + } else { + if node.fields.len > 0 { + for tfi, tf in node.fields { + f.write(tf.name) + if tfi < node.fields.len - 1 { + f.write(', ') + } + } + f.write(' ') + } + } + f.write('from ${util.strip_mod_name(table_name)}') + if node.has_where { + f.write(' where ') + f.expr(node.where_expr) + } + if node.has_order { + f.write(' order by ') + f.expr(node.order_expr) + if node.has_desc { + f.write(' desc') + } + } + if node.has_limit { + f.write(' limit ') + f.expr(node.limit_expr) + } + if node.has_offset { + f.write(' offset ') + f.expr(node.offset_expr) + } + f.writeln('') + f.write('}') +} + +pub fn (mut f Fmt) string_literal(node ast.StringLiteral) { + use_double_quote := node.val.contains("'") && !node.val.contains('"') + if node.is_raw { + f.write('r') + } else if node.language == table.Language.c { + f.write('c') + } + if node.is_raw { + if use_double_quote { + f.write('"$node.val"') + } else { + f.write("'$node.val'") + } + } else { + unescaped_val := node.val.replace('$bs$bs', '\x01').replace_each(["$bs'", "'", '$bs"', + '"', + ]) + if use_double_quote { + s := unescaped_val.replace_each(['\x01', '$bs$bs', '"', '$bs"']) + f.write('"$s"') + } else { + s := unescaped_val.replace_each(['\x01', '$bs$bs', "'", "$bs'"]) + f.write("'$s'") + } + } +} + +pub fn (mut f Fmt) string_inter_literal(node ast.StringInterLiteral) { + // TODO: this code is very similar to ast.Expr.str() + mut quote := "'" + for val in node.vals { + if val.contains("'") { + quote = '"' + } + if val.contains('"') { + quote = "'" + break + } + } + f.write(quote) + for i, val in node.vals { + f.write(val) + if i >= node.exprs.len { + break + } + f.write('$') + fspec_str, needs_braces := node.get_fspec_braces(i) + if needs_braces { + f.write('{') + f.expr(node.exprs[i]) + f.write(fspec_str) + f.write('}') + } else { + f.expr(node.exprs[i]) + } + } + f.write(quote) +} + +pub fn (mut f Fmt) type_of(node ast.TypeOf) { + f.write('typeof(') + f.expr(node.expr) + f.write(')') +} + +pub fn (mut f Fmt) likely(node ast.Likely) { + if node.is_likely { + f.write('_likely_') + } else { + f.write('_unlikely_') + } + f.write('(') + f.expr(node.expr) + f.write(')') +} + +pub fn (mut f Fmt) unsafe_expr(node ast.UnsafeExpr) { + single_line := node.pos.line_nr >= node.pos.last_line + f.write('unsafe {') + if single_line { + f.write(' ') + } else { + f.writeln('') + f.indent++ + f.empty_line = true + } + f.expr(node.expr) + if single_line { + f.write(' ') + } else { + f.writeln('') + f.indent-- + } + f.write('}') +} + +pub fn (mut f Fmt) array_decompose(node ast.ArrayDecompose) { + f.write('...') + f.expr(node.expr) } pub fn (mut f Fmt) lock_expr(lex ast.LockExpr) { @@ -1602,6 +1603,23 @@ fn (mut f Fmt) write_generic_if_require(node ast.CallExpr) { } } +pub fn (mut f Fmt) call_args(args []ast.CallArg) { + f.single_line_fields = true + for i, arg in args { + if arg.is_mut { + f.write(arg.share.str() + ' ') + } + if i > 0 { + f.wrap_long_line(2, true) + } + f.expr(arg.expr) + if i < args.len - 1 { + f.write(', ') + } + } + f.single_line_fields = false +} + pub fn (mut f Fmt) call_expr(node ast.CallExpr) { old_short_arg_state := f.use_short_fn_args f.use_short_fn_args = false @@ -1671,7 +1689,7 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) { f.write('${node.name.after_char(`.`)}') } else { mut name := f.short_module(node.name) - f.mark_module_as_used(name) + f.mark_import_as_used(name) if node.name in f.mod2alias { name = f.mod2alias[node.name] } @@ -1759,37 +1777,6 @@ pub fn (mut f Fmt) match_expr(it ast.MatchExpr) { f.it_name = '' } -pub fn (mut f Fmt) remove_new_line() { - mut i := 0 - for i = f.out.len - 1; i >= 0; i-- { - if !f.out.buf[i].is_space() { // != `\n` { - break - } - } - f.out.go_back(f.out.len - i - 1) - f.empty_line = false - // f.writeln('sdf') -} - -pub fn (mut f Fmt) mark_types_module_as_used(typ table.Type) { - sym := f.table.get_type_symbol(typ) - f.mark_module_as_used(sym.name) -} - -// `name` is a function (`foo.bar()`) or type (`foo.Bar{}`) -pub fn (mut f Fmt) mark_module_as_used(name string) { - if !name.contains('.') { - return - } - pos := name.last_index('.') or { 0 } - mod := name[..pos] - if mod in f.used_imports { - return - } - f.used_imports << mod - // println('marking module $mod as used') -} - fn (mut f Fmt) write_language_prefix(lang table.Language) { match lang { .c { f.write('C.') } @@ -1798,46 +1785,6 @@ fn (mut f Fmt) write_language_prefix(lang table.Language) { } } -fn stmt_is_single_line(stmt ast.Stmt) bool { - match stmt { - ast.ExprStmt { return expr_is_single_line(stmt.expr) } - ast.Return { return true } - ast.AssignStmt { return true } - else { return false } - } -} - -fn expr_is_single_line(expr ast.Expr) bool { - match expr { - ast.AnonFn { - if !expr.decl.no_body { - return false - } - } - ast.IfExpr { - return false - } - ast.Comment { - return false - } - ast.MatchExpr { - return false - } - ast.StructInit { - if !expr.is_short && (expr.fields.len > 0 || expr.pre_comments.len > 0) { - return false - } - } - ast.CallExpr { - if expr.or_block.stmts.len > 1 { - return false - } - } - else {} - } - return true -} - pub fn (mut f Fmt) chan_init(mut it ast.ChanInit) { info := f.table.get_type_symbol(it.typ).chan_info() if it.elem_type == 0 && it.typ > 0 { @@ -2196,13 +2143,209 @@ fn (mut f Fmt) is_external_name(name string) bool { return false } -fn (f Fmt) get_modname_prefix(mname string) (string, string) { - // ./tests/proto_module_importing_vproto_keep.vv to know, why here is checked for ']' and '&' - if !mname.contains(']') && !mname.contains('&') { - return mname, '' +pub fn (mut f Fmt) assign_stmt(node ast.AssignStmt) { + f.comments(node.comments, {}) + for i, left in node.left { + if left is ast.Ident { + var_info := left.var_info() + if var_info.is_static { + f.write('static ') + } + f.expr(left) + } else { + f.expr(left) + } + if i < node.left.len - 1 { + f.write(', ') + } } - after_rbc := mname.all_after_last(']') - after_ref := mname.all_after_last('&') - modname := if after_rbc.len < after_ref.len { after_rbc } else { after_ref } - return modname, mname.trim_suffix(modname) + f.is_assign = true + f.write(' $node.op.str() ') + for i, val in node.right { + f.prefix_expr_cast_expr(val) + if i < node.right.len - 1 { + f.write(', ') + } + } + f.comments(node.end_comments, has_nl: false, inline: true, level: .keep) + if !f.single_line_if { + f.writeln('') + } + f.is_assign = false +} + +pub fn (mut f Fmt) assert_stmt(node ast.AssertStmt) { + f.write('assert ') + f.expr(node.expr) + f.writeln('') +} + +pub fn (mut f Fmt) block(node ast.Block) { + if node.is_unsafe { + f.write('unsafe ') + } + f.write('{') + if node.stmts.len > 0 || node.pos.line_nr < node.pos.last_line { + f.writeln('') + f.stmts(node.stmts) + } + f.writeln('}') +} + +pub fn (mut f Fmt) comp_for(node ast.CompFor) { + typ := f.no_cur_mod(f.table.type_to_str(node.typ)) + f.write('\$for $node.val_var in ${typ}.$node.kind.str() {') + if node.stmts.len > 0 || node.pos.line_nr < node.pos.last_line { + f.writeln('') + f.stmts(node.stmts) + } + f.writeln('}') +} + +pub fn (mut f Fmt) defer_stmt(node ast.DeferStmt) { + f.write('defer {') + if node.stmts.len > 0 || node.pos.line_nr < node.pos.last_line { + f.writeln('') + f.stmts(node.stmts) + } + f.writeln('}') +} + +pub fn (mut f Fmt) expr_stmt(node ast.ExprStmt) { + f.comments(node.comments, {}) + f.expr(node.expr) + if !f.single_line_if { + f.writeln('') + } +} + +pub fn (mut f Fmt) for_c_stmt(node ast.ForCStmt) { + if node.label.len > 0 { + f.write('$node.label: ') + } + f.write('for ') + if node.has_init { + f.single_line_if = true // to keep all for ;; exprs on the same line + f.stmt(node.init) + f.single_line_if = false + } + f.write('; ') + f.expr(node.cond) + f.write('; ') + f.stmt(node.inc) + f.remove_new_line() + f.write(' {') + if node.stmts.len > 0 || node.pos.line_nr < node.pos.last_line { + f.writeln('') + f.stmts(node.stmts) + } + f.writeln('}') +} + +pub fn (mut f Fmt) for_in_stmt(node ast.ForInStmt) { + if node.label.len > 0 { + f.write('$node.label: ') + } + f.write('for ') + if node.key_var != '' { + f.write(node.key_var) + } + if node.val_var != '' { + if node.key_var != '' { + f.write(', ') + } + if node.val_is_mut { + f.write('mut ') + } + f.write(node.val_var) + } + f.write(' in ') + f.expr(node.cond) + if node.is_range { + f.write(' .. ') + f.expr(node.high) + } + f.write(' {') + if node.stmts.len > 0 || node.pos.line_nr < node.pos.last_line { + f.writeln('') + f.stmts(node.stmts) + } + f.writeln('}') +} + +pub fn (mut f Fmt) for_stmt(node ast.ForStmt) { + if node.label.len > 0 { + f.write('$node.label: ') + } + f.write('for ') + f.expr(node.cond) + if node.is_inf { + f.write('{') + } else { + f.write(' {') + } + if node.stmts.len > 0 || node.pos.line_nr < node.pos.last_line { + f.writeln('') + f.stmts(node.stmts) + } + f.writeln('}') +} + +pub fn (mut f Fmt) go_stmt(node ast.GoStmt) { + f.write('go ') + f.expr(node.call_expr) + f.writeln('') +} + +pub fn (mut f Fmt) return_stmt(node ast.Return) { + f.comments(node.comments, {}) + f.write('return') + if node.exprs.len > 1 { + // multiple returns + f.write(' ') + for i, expr in node.exprs { + f.expr(expr) + if i < node.exprs.len - 1 { + f.write(', ') + } + } + } else if node.exprs.len == 1 { + // normal return + f.write(' ') + f.expr(node.exprs[0]) + } + f.writeln('') +} + +pub fn (mut f Fmt) sql_stmt(node ast.SqlStmt) { + f.write('sql ') + f.expr(node.db_expr) + f.writeln(' {') + match node.kind { + .insert { + f.writeln('\tinsert $node.object_var_name into ${util.strip_mod_name(node.table_name)}') + } + .update { + f.write('\tupdate ${util.strip_mod_name(node.table_name)} set ') + for i, col in node.updated_columns { + f.write('$col = ') + f.expr(node.update_exprs[i]) + if i < node.updated_columns.len - 1 { + f.write(', ') + } else { + f.write(' ') + } + f.wrap_long_line(2, true) + } + f.write('where ') + f.expr(node.where_expr) + f.writeln('') + } + .delete { + f.write('\tdelete from ${util.strip_mod_name(node.table_name)} where ') + f.expr(node.where_expr) + f.writeln('') + } + } + f.writeln('}') }