v.gen.v #
V3 source formatter
The V3 formatter formats source syntax without type checking.
Standalone comments and blank lines separate struct, union, and enum fields into alignment groups. Each group aligns independently; trailing comments do not separate groups.
Anonymous aggregate indentation
Multiline anonymous struct and union bodies follow the surrounding field's indentation. Nested aggregate bodies add a level, and access sections align with their opening aggregate. Continuation text inside multiline literals and block comments keeps its original whitespace. Blank lines remain empty.
Formatting in-memory source
Use format_text to format a string without staging the input in a file or launching the formatter executable. It returns the formatted text, or a parser error with a main.v:line:column location. Comments and compile-time branches are preserved just as they are when formatting a file.
import v.gen.v as vgen
fn main() {
formatted := vgen.format_text('fn main(){println(1)}') or { panic(err) }
println(formatted)
}
format_text_with_options(src, options) accepts the same FormatOptions as format_with_options, including backend and is_new_int.
For callers that need the AST, parser.Parser.parse_text(name, src) parses an in-memory source and owns a copy of its bytes. Use a .v name, or .vsh for script mode. Inspect Parser.diagnostics for errors. Reusing the parser appends each file to the same AST and retains the diagnostics from earlier files, as parse_file does.
String literal spelling
Non-interpolated string literals retain their original source spelling for everything except the quote delimiter: escape sequences and the r, c, or js prefix are copied byte for byte. For example, 'x=\0' stays 'x=\0' and 'x=\x00' stays 'x=\x00'. Surrounding code is still formatted normally.
The formatter uses the original literal's source span rather than decoding and re-encoding it. This avoids collapsing hex or Unicode escapes into characters and keeps a NUL followed by digits distinct from an octal escape.
The delimiter is normalized: single quotes are preferred, unless the literal contains a ' but no ". So "text" becomes 'text', while "it's" keeps its double quotes. Only the quote escaping is rewritten along with the delimiter, so "say \"hi\"" becomes 'say "hi"' and 'it\'s' becomes "it's". This is the rule that interpolated literals and the legacy formatter already follow, so plain and interpolated literals are spelled the same way. A raw literal cannot escape a quote, so its delimiter decides what it can hold and is kept as written.
Literals without a usable source spelling, such as synthesized AST nodes, still use the existing escaping fallback. That fallback emits NUL as \x00 so that following octal digits cannot change the value.
The C-backend rewrite from a string literal's .str selector to a c literal retains the literal spelling and is stable on subsequent formatting passes.
This policy does not change attribute formatting or compiler/scanner escape semantics. Interpolated strings continue to use their existing formatting path so embedded expressions can be formatted.
fn format #
fn format(a &flat.FlatAst) string
format finds every trailing .file node in a and formats them in order, separated by a blank line. Useful when a single file was parsed on its own.
fn format_file #
fn format_file(a &flat.FlatAst, file_id flat.NodeId) string
format_file parses-independent convenience: format the file whose trailing .file node id is file_id within a.
fn format_text #
fn format_text(src string) !string
format_text formats V source text held in memory, without reading or writing any file. It parses src as if it were a file named main.v and returns the formatted source, or an error when the text has parser errors. Useful where no filesystem exists, like the Emscripten build.
fn format_text_with_options #
fn format_text_with_options(src string, options FormatOptions) !string
format_text_with_options formats in-memory V source with explicit options.
fn format_with_options #
fn format_with_options(a &flat.FlatAst, options FormatOptions) string
format_with_options formats every trailing file node in a with options.
fn Gen.new #
fn Gen.new() &Gen
Gen.new returns a fresh formatter.
struct FormatOptions #
struct FormatOptions {
pub:
is_debug bool
is_new_int bool
backend string = 'c'
}
FormatOptions controls optional formatter output.
struct Gen #
struct Gen {
mut:
a &flat.FlatAst = unsafe { nil }
out strings.Builder
indent int
on_newline bool
in_init bool
file_id int
source string
comments []flat.Comment
comment_i int
source_end int = -1
migrate_json2 bool
json_qualifier string
json_import_id int = -1
skip_decls map[int]bool
selective_json bool
implied_imports []string
in_array_init bool
is_debug bool
is_new_int bool
is_translated bool
in_c_function bool
backend string = 'c'
formatter_types map[string]FormatterTypeSource
array_breaks []bool
array_depth int
in_index bool
in_string_interp bool
// suppress_mut skips the `mut ` prefix on an assignment (used for C-style
// `for` loop init clauses, whose variable the parser always marks mutable).
suppress_mut bool
// suppress_trailing_comments defers comments that belong after a surrounding
// delimiter, such as the opening brace of a loop.
suppress_trailing_comments int
// trailing_comment_limit holds comments after a field's root default until its
// suffix is written, while allowing comments inside that default to be emitted.
trailing_comment_limit int = -1
// attrs maps a declaration node id to its `@[...]` attribute strings. The parser stores
// attributes on a separate floating `.directive` node rather than as a child, so they are
// collected up-front in collect_attrs. attr_sources retains formatter-only source groups.
attrs map[int][]string
attr_sources map[int]string
}
Gen holds the formatter state for one output buffer.
fn (Gen) reset #
fn (mut g Gen) reset()
reset clears the buffer so a Gen instance can be reused.
fn (Gen) gen_file #
fn (mut g Gen) gen_file(a &flat.FlatAst, file_id flat.NodeId) string
gen_file formats the top-level declarations of the given trailing file node.
fn (Gen) output_string #
fn (mut g Gen) output_string() string
output_string returns the generated V source code.