mirror of
https://github.com/vlang/v.git
synced 2025-09-13 22:42:26 +03:00
326 lines
9 KiB
V
326 lines
9 KiB
V
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
|
|
// Use of this source code is governed by an MIT license
|
|
// that can be found in the LICENSE file.
|
|
module fmt
|
|
|
|
import strings
|
|
import v.ast
|
|
|
|
pub fn (mut f Fmt) struct_decl(node ast.StructDecl, is_anon bool) {
|
|
f.attrs(node.attrs)
|
|
if node.is_pub && !is_anon {
|
|
f.write('pub ')
|
|
}
|
|
if node.is_union {
|
|
f.write('union')
|
|
} else {
|
|
f.write('struct')
|
|
}
|
|
name := node.name.after('.') // strip prepended module
|
|
if !is_anon {
|
|
f.write(' ')
|
|
f.write_language_prefix(node.language)
|
|
f.write(name)
|
|
}
|
|
f.write_generic_types(node.generic_types)
|
|
if node.fields.len == 0 && node.embeds.len == 0 && node.pos.line_nr == node.pos.last_line {
|
|
f.writeln(' {}')
|
|
return
|
|
}
|
|
mut type_aligns := FieldAlign{}
|
|
mut default_expr_aligns := FieldAlign{}
|
|
mut attr_aligns := FieldAlign{}
|
|
mut comment_aligns := FieldAlign{}
|
|
mut field_types := []string{cap: node.fields.len}
|
|
// Calculate the alignments first
|
|
f.calculate_alignment(node.fields, mut type_aligns, mut comment_aligns, mut default_expr_aligns, mut
|
|
attr_aligns, mut field_types)
|
|
f.writeln(' {')
|
|
if node.pre_comments.len > 0 {
|
|
f.comments_before_field(node.pre_comments)
|
|
}
|
|
for embed in node.embeds {
|
|
f.mark_types_import_as_used(embed.typ)
|
|
styp := f.table.type_to_str_using_aliases(embed.typ, f.mod2alias)
|
|
|
|
pre_comments := embed.comments.filter(it.pos.pos < embed.pos.pos)
|
|
comments := embed.comments[pre_comments.len..]
|
|
|
|
f.comments_before_field(pre_comments)
|
|
if comments.len == 0 {
|
|
f.writeln('\t${styp}')
|
|
} else {
|
|
f.write('\t${styp}')
|
|
f.comments(comments, level: .indent)
|
|
}
|
|
}
|
|
// Now handle each field
|
|
mut inc_indent := false // for correct indents with multi line default exprs
|
|
for i, field in node.fields {
|
|
match true {
|
|
i == node.mut_pos {
|
|
f.writeln('mut:')
|
|
}
|
|
i == node.pub_pos {
|
|
f.writeln('pub:')
|
|
}
|
|
i == node.pub_mut_pos {
|
|
f.writeln('pub mut:')
|
|
}
|
|
i == node.global_pos {
|
|
f.writeln('__global:')
|
|
}
|
|
i == node.module_pos {
|
|
f.writeln('module:')
|
|
}
|
|
i > 0 && field.has_prev_newline {
|
|
f.writeln('')
|
|
}
|
|
else {}
|
|
}
|
|
mut pre_cmts, mut end_cmts, mut next_line_cmts := []ast.Comment{}, []ast.Comment{}, []ast.Comment{}
|
|
for cmt in field.comments {
|
|
match true {
|
|
cmt.pos.pos < field.pos.pos { pre_cmts << cmt }
|
|
cmt.pos.line_nr > field.pos.last_line { next_line_cmts << cmt }
|
|
else { end_cmts << cmt }
|
|
}
|
|
}
|
|
// Handle comments before the field
|
|
f.comments_before_field(pre_cmts)
|
|
volatile_prefix := if field.is_volatile { 'volatile ' } else { '' }
|
|
f.write('\t${volatile_prefix}${field.name} ')
|
|
f.write(strings.repeat(` `, type_aligns.max_len(field.pos.line_nr) - field.name.len))
|
|
// Handle anon structs recursively
|
|
if !f.write_anon_struct_field_decl(field.typ, field.anon_struct_decl) {
|
|
f.write(field_types[i])
|
|
}
|
|
f.mark_types_import_as_used(field.typ)
|
|
attrs_len := inline_attrs_len(field.attrs)
|
|
if field.has_default_expr {
|
|
f.write(strings.repeat(` `, default_expr_aligns.max_len(field.pos.line_nr) - field_types[i].len))
|
|
f.write(' = ')
|
|
if !expr_is_single_line(field.default_expr) {
|
|
f.indent++
|
|
inc_indent = true
|
|
}
|
|
f.expr(field.default_expr)
|
|
if inc_indent {
|
|
f.indent--
|
|
inc_indent = false
|
|
}
|
|
}
|
|
if field.attrs.len > 0 {
|
|
f.write(strings.repeat(` `, attr_aligns.max_len(field.pos.line_nr) - field_types[i].len))
|
|
f.single_line_attrs(field.attrs, same_line: true)
|
|
}
|
|
// Handle comments at the end of the line
|
|
if end_cmts.len > 0 {
|
|
if field.has_default_expr {
|
|
f.write(strings.repeat(` `, comment_aligns.max_len(field.pos.line_nr) - field.default_expr.str().len - 2))
|
|
} else if field.attrs.len > 0 {
|
|
f.write(strings.repeat(` `, comment_aligns.max_len(field.pos.line_nr) - attrs_len))
|
|
} else {
|
|
f.write(strings.repeat(` `, comment_aligns.max_len(field.pos.line_nr) - field_types[i].len))
|
|
}
|
|
f.write(' ')
|
|
f.comments(end_cmts, level: .indent)
|
|
} else {
|
|
f.writeln('')
|
|
}
|
|
// Handle comments on the next lines
|
|
if next_line_cmts.len > 0 {
|
|
f.comments(next_line_cmts, level: .indent)
|
|
}
|
|
}
|
|
if is_anon || node.end_comments.len > 0 {
|
|
f.write('}')
|
|
} else {
|
|
f.writeln('}')
|
|
}
|
|
if node.end_comments.len > 0 {
|
|
f.comments(node.end_comments, same_line: true)
|
|
}
|
|
}
|
|
|
|
fn (mut f Fmt) write_anon_struct_field_decl(field_typ ast.Type, field_anon_decl ast.StructDecl) bool {
|
|
sym := f.table.sym(field_typ)
|
|
match sym.kind {
|
|
.struct_ {
|
|
info := sym.info as ast.Struct
|
|
if info.is_anon {
|
|
f.indent++
|
|
f.struct_decl(field_anon_decl, true)
|
|
f.indent--
|
|
return true
|
|
}
|
|
}
|
|
.array {
|
|
if sym.info is ast.Array {
|
|
elem_sym := f.table.sym(sym.info.elem_type)
|
|
if elem_sym.info is ast.Struct {
|
|
if elem_sym.info.is_anon {
|
|
f.write('[]'.repeat(sym.info.nr_dims))
|
|
f.write_anon_struct_field_decl(sym.info.elem_type, field_anon_decl)
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.array_fixed {
|
|
if sym.info is ast.ArrayFixed {
|
|
elem_sym := f.table.sym(sym.info.elem_type)
|
|
if elem_sym.info is ast.Struct {
|
|
if elem_sym.info.is_anon {
|
|
f.write('[${sym.info.size}]')
|
|
f.write_anon_struct_field_decl(sym.info.elem_type, field_anon_decl)
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {}
|
|
}
|
|
return false
|
|
}
|
|
|
|
pub fn (mut f Fmt) struct_init(node ast.StructInit) {
|
|
struct_init_save := f.is_struct_init
|
|
f.is_struct_init = true
|
|
defer {
|
|
f.is_struct_init = struct_init_save
|
|
}
|
|
f.mark_types_import_as_used(node.typ)
|
|
sym_name := f.table.sym(node.typ).name
|
|
// f.write('<old name: $type_sym.name>')
|
|
mut name := if !sym_name.starts_with('C.') && !sym_name.starts_with('JS.') {
|
|
f.no_cur_mod(f.short_module(sym_name)) // TODO: f.type_to_str?
|
|
} else {
|
|
sym_name
|
|
}
|
|
if name == 'void' {
|
|
name = ''
|
|
}
|
|
if node.typ.has_flag(.option) {
|
|
f.write('?')
|
|
}
|
|
if node.is_anon {
|
|
f.write('struct ')
|
|
}
|
|
if node.init_fields.len == 0 && !node.has_update_expr {
|
|
// `Foo{}` on one line if there are no fields or comments
|
|
if node.pre_comments.len == 0 {
|
|
f.write('${name}{}')
|
|
} else {
|
|
f.writeln('${name}{')
|
|
f.comments(node.pre_comments, same_line: true, has_nl: true, level: .indent)
|
|
f.write('}')
|
|
}
|
|
f.mark_import_as_used(name)
|
|
} else if node.no_keys {
|
|
// `Foo{1,2,3}` (short syntax, no keys)
|
|
f.write('${name}{')
|
|
f.mark_import_as_used(name)
|
|
if node.has_update_expr {
|
|
f.write('...')
|
|
f.expr(node.update_expr)
|
|
f.write(', ')
|
|
}
|
|
for i, init_field in node.init_fields {
|
|
f.expr(init_field.expr)
|
|
if i < node.init_fields.len - 1 {
|
|
f.write(', ')
|
|
}
|
|
}
|
|
f.write('}')
|
|
} else {
|
|
use_short_args := f.use_short_fn_args && !node.has_update_expr
|
|
f.use_short_fn_args = false
|
|
mut single_line_fields := f.single_line_fields
|
|
f.single_line_fields = false
|
|
if node.pos.line_nr < node.pos.last_line || node.pre_comments.len > 0 {
|
|
single_line_fields = false
|
|
}
|
|
if !use_short_args || node.is_anon {
|
|
f.write('${name}{')
|
|
f.mark_import_as_used(name)
|
|
if single_line_fields {
|
|
f.write(' ')
|
|
}
|
|
}
|
|
fields_start := f.out.len
|
|
fields_loop: for {
|
|
if !single_line_fields {
|
|
if use_short_args && f.out.last() == ` ` {
|
|
// v Remove space at tail of line
|
|
// f(a, b, c, \n
|
|
// f1: 0\n
|
|
// f2: 1\n
|
|
// )
|
|
f.out.go_back(1)
|
|
}
|
|
f.writeln('')
|
|
f.indent++
|
|
}
|
|
f.comments(node.pre_comments, same_line: true, has_nl: true, level: .keep)
|
|
if node.has_update_expr {
|
|
f.write('...')
|
|
f.expr(node.update_expr)
|
|
if single_line_fields {
|
|
if node.init_fields.len > 0 {
|
|
f.write(', ')
|
|
}
|
|
} else {
|
|
f.writeln('')
|
|
}
|
|
f.comments(node.update_expr_comments, same_line: true, has_nl: true, level: .keep)
|
|
}
|
|
mut value_aligns := FieldAlign{}
|
|
mut comment_aligns := FieldAlign{}
|
|
for init_field in node.init_fields {
|
|
value_aligns.add_info(init_field.name.len, init_field.pos.line_nr)
|
|
if init_field.comments.len > 0 {
|
|
comment_aligns.add_info(init_field.expr.str().len + 1, init_field.pos.line_nr)
|
|
}
|
|
}
|
|
for i, init_field in node.init_fields {
|
|
f.write('${init_field.name}: ')
|
|
if !single_line_fields {
|
|
f.write(strings.repeat(` `, value_aligns.max_len(init_field.pos.line_nr) - init_field.name.len))
|
|
}
|
|
f.expr(init_field.expr)
|
|
if init_field.comments.len > 0 {
|
|
f.write(strings.repeat(` `, comment_aligns.max_len(init_field.pos.line_nr) - init_field.expr.str().len))
|
|
f.comments(init_field.comments, same_line: true, has_nl: false, level: .indent)
|
|
}
|
|
if single_line_fields {
|
|
if i < node.init_fields.len - 1 {
|
|
f.write(', ')
|
|
}
|
|
} else {
|
|
f.writeln('')
|
|
}
|
|
f.comments(init_field.next_comments, has_nl: true, level: .keep)
|
|
if single_line_fields && (init_field.comments.len > 0
|
|
|| init_field.next_comments.len > 0
|
|
|| !expr_is_single_line(init_field.expr) || f.line_len > max_len) {
|
|
single_line_fields = false
|
|
f.out.go_back_to(fields_start)
|
|
f.line_len = fields_start
|
|
f.remove_new_line()
|
|
continue fields_loop
|
|
}
|
|
}
|
|
break
|
|
}
|
|
if !single_line_fields {
|
|
f.indent--
|
|
}
|
|
if !use_short_args || node.is_anon {
|
|
if single_line_fields {
|
|
f.write(' ')
|
|
}
|
|
f.write('}')
|
|
}
|
|
}
|
|
}
|