mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
gen: basic initial work on the Go backend
This commit is contained in:
parent
28068e8ecf
commit
a4eb5b6356
7
cmd/tools/builders/golang_builder.v
Normal file
7
cmd/tools/builders/golang_builder.v
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
module main
|
||||||
|
|
||||||
|
import v.builder.golangbuilder
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
golangbuilder.start()
|
||||||
|
}
|
@ -176,5 +176,9 @@ fn rebuild(prefs &pref.Preferences) {
|
|||||||
.interpret {
|
.interpret {
|
||||||
util.launch_tool(prefs.is_verbose, 'builders/interpret_builder', os.args[1..])
|
util.launch_tool(prefs.is_verbose, 'builders/interpret_builder', os.args[1..])
|
||||||
}
|
}
|
||||||
|
.golang {
|
||||||
|
println('using Go WIP backend...')
|
||||||
|
util.launch_tool(prefs.is_verbose, 'builders/golang_builder', os.args[1..])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
41
vlib/v/builder/golangbuilder/golangbuilder.v
Normal file
41
vlib/v/builder/golangbuilder/golangbuilder.v
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
module golangbuilder
|
||||||
|
|
||||||
|
import os
|
||||||
|
import v.pref
|
||||||
|
import v.util
|
||||||
|
import v.builder
|
||||||
|
import v.gen.golang
|
||||||
|
|
||||||
|
pub fn start() {
|
||||||
|
mut args_and_flags := util.join_env_vflags_and_os_args()[1..]
|
||||||
|
prefs, _ := pref.parse_args([], args_and_flags)
|
||||||
|
builder.compile('build', prefs, compile_golang)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile_golang(mut b builder.Builder) {
|
||||||
|
// v.files << v.v_files_from_dir(os.join_path(v.pref.vlib_path,'builtin','bare'))
|
||||||
|
files := [b.pref.path]
|
||||||
|
b.set_module_lookup_paths()
|
||||||
|
build_golang(mut b, files, b.pref.out_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_golang(mut b builder.Builder, v_files []string, out_file string) {
|
||||||
|
if b.pref.os == .windows {
|
||||||
|
if !b.pref.is_shared && b.pref.build_mode != .build_module
|
||||||
|
&& !b.pref.out_name.ends_with('.exe') {
|
||||||
|
b.pref.out_name += '.exe'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mut nvf := []string{}
|
||||||
|
for vf in v_files {
|
||||||
|
if os.is_dir(vf) {
|
||||||
|
nvf << b.v_files_from_dir(vf)
|
||||||
|
} else {
|
||||||
|
nvf << vf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.front_and_middle_stages(nvf) or { return }
|
||||||
|
util.timing_start('Golang GEN')
|
||||||
|
b.stats_lines, b.stats_bytes = golang.gen(b.parsed_files, b.table, out_file, b.pref)
|
||||||
|
util.timing_measure('Golang GEN')
|
||||||
|
}
|
@ -1765,12 +1765,12 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
|
|||||||
if c.ct_cond_stack.len > 0 {
|
if c.ct_cond_stack.len > 0 {
|
||||||
node.ct_conds = c.ct_cond_stack.clone()
|
node.ct_conds = c.ct_cond_stack.clone()
|
||||||
}
|
}
|
||||||
if c.pref.backend.is_js() {
|
if c.pref.backend.is_js() || c.pref.backend == .golang {
|
||||||
if !c.file.path.ends_with('.js.v') {
|
if !c.file.path.ends_with('.js.v') && !c.file.path.ends_with('.go.v') {
|
||||||
c.error('hash statements are only allowed in backend specific files such "x.js.v"',
|
c.error('hash statements are only allowed in backend specific files such "x.js.v" and "x.go.v"',
|
||||||
node.pos)
|
node.pos)
|
||||||
}
|
}
|
||||||
if c.mod == 'main' {
|
if c.mod == 'main' && c.pref.backend != .golang {
|
||||||
c.error('hash statements are not allowed in the main module. Place them in a separate module.',
|
c.error('hash statements are not allowed in the main module. Place them in a separate module.',
|
||||||
node.pos)
|
node.pos)
|
||||||
}
|
}
|
||||||
|
59
vlib/v/gen/golang/align.v
Normal file
59
vlib/v/gen/golang/align.v
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// Copyright (c) 2019-2022 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 golang
|
||||||
|
|
||||||
|
import v.mathutil
|
||||||
|
|
||||||
|
const struct_field_align_threshold = 8
|
||||||
|
|
||||||
|
struct AlignInfo {
|
||||||
|
mut:
|
||||||
|
line_nr int
|
||||||
|
max_len int
|
||||||
|
max_type_len int
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
[params]
|
||||||
|
struct AddInfoConfig {
|
||||||
|
use_threshold bool
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut infos []AlignInfo) add_new_info(len int, type_len int, line int) {
|
||||||
|
infos << AlignInfo{
|
||||||
|
line_nr: line
|
||||||
|
max_len: len
|
||||||
|
max_type_len: type_len
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[direct_array_access]
|
||||||
|
fn (mut infos []AlignInfo) add_info(len int, type_len int, line int, cfg AddInfoConfig) {
|
||||||
|
if infos.len == 0 {
|
||||||
|
infos.add_new_info(len, type_len, line)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i := infos.len - 1
|
||||||
|
if line - infos[i].line_nr > 1 {
|
||||||
|
infos.add_new_info(len, type_len, line)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cfg.use_threshold {
|
||||||
|
len_diff := mathutil.abs(infos[i].max_len - len) +
|
||||||
|
mathutil.abs(infos[i].max_type_len - type_len)
|
||||||
|
|
||||||
|
if len_diff >= fmt.struct_field_align_threshold {
|
||||||
|
infos.add_new_info(len, type_len, line)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
infos[i].line_nr = line
|
||||||
|
if len > infos[i].max_len {
|
||||||
|
infos[i].max_len = len
|
||||||
|
}
|
||||||
|
if type_len > infos[i].max_type_len {
|
||||||
|
infos[i].max_type_len = type_len
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
64
vlib/v/gen/golang/attrs.v
Normal file
64
vlib/v/gen/golang/attrs.v
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (c) 2019-2022 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 golang
|
||||||
|
|
||||||
|
import v.ast
|
||||||
|
|
||||||
|
pub fn (mut f Gen) attrs(attrs []ast.Attr) {
|
||||||
|
mut sorted_attrs := attrs.clone()
|
||||||
|
// Sort the attributes. The ones with arguments come first
|
||||||
|
sorted_attrs.sort_with_compare(fn (a &ast.Attr, b &ast.Attr) int {
|
||||||
|
d := b.arg.len - a.arg.len
|
||||||
|
return if d != 0 { d } else { compare_strings(b.arg, a.arg) }
|
||||||
|
})
|
||||||
|
for i, attr in sorted_attrs {
|
||||||
|
if attr.arg.len == 0 {
|
||||||
|
f.single_line_attrs(sorted_attrs[i..])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
f.writeln('[$attr]')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[params]
|
||||||
|
pub struct AttrsOptions {
|
||||||
|
inline bool
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut f Gen) single_line_attrs(attrs []ast.Attr, options AttrsOptions) {
|
||||||
|
if attrs.len == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mut sorted_attrs := attrs.clone()
|
||||||
|
sorted_attrs.sort(a.name < b.name)
|
||||||
|
if options.inline {
|
||||||
|
f.write(' ')
|
||||||
|
}
|
||||||
|
f.write('[')
|
||||||
|
for i, attr in sorted_attrs {
|
||||||
|
if i > 0 {
|
||||||
|
f.write('; ')
|
||||||
|
}
|
||||||
|
f.write('$attr')
|
||||||
|
}
|
||||||
|
f.write(']')
|
||||||
|
if !options.inline {
|
||||||
|
f.writeln('')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inline_attrs_len(attrs []ast.Attr) int {
|
||||||
|
if attrs.len == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
mut n := 2 // ' ['.len
|
||||||
|
for i, attr in attrs {
|
||||||
|
if i > 0 {
|
||||||
|
n += 2 // '; '.len
|
||||||
|
}
|
||||||
|
n += '$attr'.len
|
||||||
|
}
|
||||||
|
n++ // ']'.len
|
||||||
|
return n
|
||||||
|
}
|
142
vlib/v/gen/golang/comments.v
Normal file
142
vlib/v/gen/golang/comments.v
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
// Copyright (c) 2019-2022 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 golang
|
||||||
|
|
||||||
|
import v.ast
|
||||||
|
|
||||||
|
pub enum CommentsLevel {
|
||||||
|
keep
|
||||||
|
indent
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommentsOptions defines the way comments are going to be written
|
||||||
|
// - has_nl: adds an newline at the end of a list of comments
|
||||||
|
// - inline: line comments will be on the same line as the last statement
|
||||||
|
// - level: either .keep (don't indent), or .indent (increment indentation)
|
||||||
|
// - iembed: a /* ... */ block comment used inside expressions; // comments the whole line
|
||||||
|
// - prev_line: the line number of the previous token to save linebreaks
|
||||||
|
[minify; params]
|
||||||
|
pub struct CommentsOptions {
|
||||||
|
has_nl bool = true
|
||||||
|
inline bool
|
||||||
|
level CommentsLevel
|
||||||
|
iembed bool
|
||||||
|
prev_line int = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut f Gen) comment(node ast.Comment, options CommentsOptions) {
|
||||||
|
// Shebang in .vsh files
|
||||||
|
if node.text.starts_with('#!') {
|
||||||
|
f.writeln(node.text)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if options.level == .indent {
|
||||||
|
f.indent++
|
||||||
|
}
|
||||||
|
if options.iembed {
|
||||||
|
x := node.text.trim_left('\x01').trim_space()
|
||||||
|
if x.contains('\n') {
|
||||||
|
f.writeln('/*')
|
||||||
|
f.writeln(x)
|
||||||
|
f.write('*/')
|
||||||
|
} else {
|
||||||
|
f.write('/* $x */')
|
||||||
|
}
|
||||||
|
} else if !node.text.contains('\n') {
|
||||||
|
is_separate_line := !options.inline || node.text.starts_with('\x01')
|
||||||
|
mut s := node.text.trim_left('\x01').trim_right(' ')
|
||||||
|
mut out_s := '//'
|
||||||
|
if s != '' {
|
||||||
|
if is_char_alphanumeric(s[0]) {
|
||||||
|
out_s += ' '
|
||||||
|
}
|
||||||
|
out_s += s
|
||||||
|
}
|
||||||
|
if !is_separate_line && f.indent > 0 {
|
||||||
|
f.remove_new_line() // delete the generated \n
|
||||||
|
f.write(' ')
|
||||||
|
}
|
||||||
|
f.write(out_s)
|
||||||
|
} else {
|
||||||
|
lines := node.text.trim_space().split_into_lines()
|
||||||
|
start_break := is_char_alphanumeric(node.text[0]) || node.text[0].is_space()
|
||||||
|
end_break := is_char_alphanumeric(node.text.trim('\t').bytes().last())
|
||||||
|
|| node.text.bytes().last().is_space()
|
||||||
|
f.write('/*')
|
||||||
|
if start_break {
|
||||||
|
f.writeln('')
|
||||||
|
}
|
||||||
|
for line in lines {
|
||||||
|
f.writeln(line.trim_right(' '))
|
||||||
|
f.empty_line = false
|
||||||
|
}
|
||||||
|
if end_break {
|
||||||
|
f.empty_line = true
|
||||||
|
} else {
|
||||||
|
f.remove_new_line()
|
||||||
|
}
|
||||||
|
f.write('*/')
|
||||||
|
}
|
||||||
|
if options.level == .indent {
|
||||||
|
f.indent--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut f Gen) comments(comments []ast.Comment, options CommentsOptions) {
|
||||||
|
mut prev_line := options.prev_line
|
||||||
|
for i, c in comments {
|
||||||
|
if options.prev_line > -1 && ((c.pos.line_nr > prev_line && f.out.last_n(1) != '\n')
|
||||||
|
|| (c.pos.line_nr > prev_line + 1 && f.out.last_n(2) != '\n\n')) {
|
||||||
|
f.writeln('')
|
||||||
|
}
|
||||||
|
if !f.out.last_n(1)[0].is_space() {
|
||||||
|
f.write(' ')
|
||||||
|
}
|
||||||
|
f.comment(c, options)
|
||||||
|
if !options.iembed && (i < comments.len - 1 || options.has_nl) {
|
||||||
|
f.writeln('')
|
||||||
|
}
|
||||||
|
prev_line = c.pos.last_line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut f Gen) comments_before_field(comments []ast.Comment) {
|
||||||
|
// They behave the same as comments after the last field. This alias is just for clarity.
|
||||||
|
f.comments_after_last_field(comments)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut f Gen) comments_after_last_field(comments []ast.Comment) {
|
||||||
|
for comment in comments {
|
||||||
|
f.indent++
|
||||||
|
f.empty_line = true
|
||||||
|
f.comment(comment, inline: true)
|
||||||
|
f.writeln('')
|
||||||
|
f.indent--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut f Gen) import_comments(comments []ast.Comment, options CommentsOptions) {
|
||||||
|
if comments.len == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if options.inline {
|
||||||
|
f.remove_new_line(imports_buffer: true)
|
||||||
|
}
|
||||||
|
for c in comments {
|
||||||
|
ctext := c.text.trim_left('\x01')
|
||||||
|
if ctext == '' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
mut out_s := if options.inline { ' ' } else { '' } + '//'
|
||||||
|
if is_char_alphanumeric(ctext[0]) {
|
||||||
|
out_s += ' '
|
||||||
|
}
|
||||||
|
out_s += ctext
|
||||||
|
f.out_imports.writeln(out_s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_char_alphanumeric(c u8) bool {
|
||||||
|
return c.is_letter() || c.is_digit()
|
||||||
|
}
|
2361
vlib/v/gen/golang/golang.v
Normal file
2361
vlib/v/gen/golang/golang.v
Normal file
File diff suppressed because it is too large
Load Diff
283
vlib/v/gen/golang/struct.v
Normal file
283
vlib/v/gen/golang/struct.v
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
// Copyright (c) 2019-2022 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 golang
|
||||||
|
|
||||||
|
import strings
|
||||||
|
import v.ast
|
||||||
|
import v.mathutil as mu
|
||||||
|
|
||||||
|
pub fn (mut f Gen) struct_decl(node ast.StructDecl) {
|
||||||
|
f.attrs(node.attrs)
|
||||||
|
f.write('type ')
|
||||||
|
if node.is_pub {
|
||||||
|
f.write('pub ')
|
||||||
|
}
|
||||||
|
f.write_language_prefix(node.language)
|
||||||
|
name := node.name.after('.') // strip prepended module
|
||||||
|
f.write(name)
|
||||||
|
if node.is_union {
|
||||||
|
f.write('union ')
|
||||||
|
} else {
|
||||||
|
f.write(' struct ')
|
||||||
|
}
|
||||||
|
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 field_aligns := []AlignInfo{}
|
||||||
|
mut comment_aligns := []AlignInfo{}
|
||||||
|
mut default_expr_aligns := []AlignInfo{}
|
||||||
|
mut field_types := []string{cap: node.fields.len}
|
||||||
|
for i, field in node.fields {
|
||||||
|
ft := f.no_cur_mod(f.table.type_to_str_using_aliases(field.typ, f.mod2alias))
|
||||||
|
field_types << ft
|
||||||
|
attrs_len := inline_attrs_len(field.attrs)
|
||||||
|
end_pos := field.pos.pos + field.pos.len
|
||||||
|
mut comments_len := 0 // Length of comments between field name and type
|
||||||
|
// field_aligns.add_info(comments_len + field.name.len, ft.len, field.pos.line_nr)
|
||||||
|
if field.has_default_expr {
|
||||||
|
// default_expr_aligns.add_info(attrs_len, field_types[i].len, field.pos.line_nr,
|
||||||
|
// use_threshold: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.writeln(' {')
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mut field_align_i := 0
|
||||||
|
mut comment_align_i := 0
|
||||||
|
mut default_expr_align_i := 0
|
||||||
|
mut inc_indent := false // for correct indents with multi line default exprs
|
||||||
|
for i, field in node.fields {
|
||||||
|
if i == node.mut_pos {
|
||||||
|
f.writeln('mut:')
|
||||||
|
} else if i == node.pub_pos {
|
||||||
|
f.writeln('pub:')
|
||||||
|
} else if i == node.pub_mut_pos {
|
||||||
|
f.writeln('pub mut:')
|
||||||
|
} else if i == node.global_pos {
|
||||||
|
f.writeln('__global:')
|
||||||
|
} else if i == node.module_pos {
|
||||||
|
f.writeln('module:')
|
||||||
|
} else if i > 0 {
|
||||||
|
// keep one empty line between fields (exclude one after mut:, pub:, ...)
|
||||||
|
mut before_last_line := node.fields[i - 1].pos.line_nr
|
||||||
|
if node.fields[i - 1].comments.len > 0 {
|
||||||
|
before_last_line = mu.max(before_last_line, node.fields[i - 1].comments.last().pos.last_line)
|
||||||
|
}
|
||||||
|
if node.fields[i - 1].has_default_expr {
|
||||||
|
before_last_line = mu.max(before_last_line, node.fields[i - 1].default_expr.pos().last_line)
|
||||||
|
}
|
||||||
|
|
||||||
|
mut next_first_line := field.pos.line_nr
|
||||||
|
if field.comments.len > 0 {
|
||||||
|
next_first_line = mu.min(next_first_line, field.comments[0].pos.line_nr)
|
||||||
|
}
|
||||||
|
if next_first_line - before_last_line > 1 {
|
||||||
|
f.writeln('')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end_pos := field.pos.pos + field.pos.len
|
||||||
|
before_comments := field.comments.filter(it.pos.pos < field.pos.pos)
|
||||||
|
between_comments := field.comments[before_comments.len..].filter(it.pos.pos < end_pos)
|
||||||
|
after_type_comments := field.comments[(before_comments.len + between_comments.len)..]
|
||||||
|
// Handle comments before the field
|
||||||
|
f.comments_before_field(before_comments)
|
||||||
|
volatile_prefix := if field.is_volatile { 'volatile ' } else { '' }
|
||||||
|
f.write('\t$volatile_prefix$field.name ')
|
||||||
|
// Handle comments between field name and type
|
||||||
|
before_len := f.line_len
|
||||||
|
f.comments(between_comments, iembed: true, has_nl: false)
|
||||||
|
comments_len := f.line_len - before_len
|
||||||
|
// mut field_align := field_aligns[field_align_i]
|
||||||
|
// if field_align.line_nr < field.pos.line_nr {
|
||||||
|
// field_align_i++
|
||||||
|
// field_align = field_aligns[field_align_i]
|
||||||
|
//}
|
||||||
|
// f.write(strings.repeat(` `, field_align.max_len - field.name.len - comments_len))
|
||||||
|
f.write(field_types[i])
|
||||||
|
f.mark_types_import_as_used(field.typ)
|
||||||
|
attrs_len := inline_attrs_len(field.attrs)
|
||||||
|
has_attrs := field.attrs.len > 0
|
||||||
|
if has_attrs {
|
||||||
|
// f.write(strings.repeat(` `, field_align.max_type_len - field_types[i].len))
|
||||||
|
f.single_line_attrs(field.attrs, inline: true)
|
||||||
|
}
|
||||||
|
if field.has_default_expr {
|
||||||
|
mut align := default_expr_aligns[default_expr_align_i]
|
||||||
|
if align.line_nr < field.pos.line_nr {
|
||||||
|
default_expr_align_i++
|
||||||
|
align = default_expr_aligns[default_expr_align_i]
|
||||||
|
}
|
||||||
|
pad_len := align.max_len - attrs_len + align.max_type_len - field_types[i].len
|
||||||
|
f.write(strings.repeat(` `, pad_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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Handle comments after field type
|
||||||
|
if after_type_comments.len > 0 {
|
||||||
|
if after_type_comments[0].pos.line_nr > field.pos.line_nr {
|
||||||
|
f.writeln('')
|
||||||
|
} else {
|
||||||
|
if !field.has_default_expr {
|
||||||
|
mut align := comment_aligns[comment_align_i]
|
||||||
|
if align.line_nr < field.pos.line_nr {
|
||||||
|
comment_align_i++
|
||||||
|
align = comment_aligns[comment_align_i]
|
||||||
|
}
|
||||||
|
pad_len := align.max_len - attrs_len + align.max_type_len - field_types[i].len
|
||||||
|
f.write(strings.repeat(` `, pad_len))
|
||||||
|
}
|
||||||
|
f.write(' ')
|
||||||
|
}
|
||||||
|
f.comments(after_type_comments, level: .indent)
|
||||||
|
} else {
|
||||||
|
f.writeln('')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.comments_after_last_field(node.end_comments)
|
||||||
|
f.writeln('}\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut f Gen) 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
|
||||||
|
}
|
||||||
|
|
||||||
|
type_sym := f.table.sym(node.typ)
|
||||||
|
// f.write('<old name: $type_sym.name>')
|
||||||
|
mut name := type_sym.name
|
||||||
|
if !name.starts_with('C.') && !name.starts_with('JS.') {
|
||||||
|
name = f.no_cur_mod(f.short_module(type_sym.name)) // TODO f.type_to_str?
|
||||||
|
}
|
||||||
|
if name == 'void' {
|
||||||
|
name = ''
|
||||||
|
}
|
||||||
|
if node.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, inline: true, has_nl: true, level: .indent)
|
||||||
|
f.write('}')
|
||||||
|
}
|
||||||
|
f.mark_import_as_used(name)
|
||||||
|
} else if node.is_short {
|
||||||
|
// `Foo{1,2,3}` (short syntax )
|
||||||
|
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, field in node.fields {
|
||||||
|
f.expr(field.expr)
|
||||||
|
if i < node.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 {
|
||||||
|
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[f.out.len - 1] == ` ` {
|
||||||
|
// 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, inline: true, has_nl: true, level: .keep)
|
||||||
|
if node.has_update_expr {
|
||||||
|
f.write('...')
|
||||||
|
f.expr(node.update_expr)
|
||||||
|
if single_line_fields {
|
||||||
|
if node.fields.len > 0 {
|
||||||
|
f.write(', ')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
f.writeln('')
|
||||||
|
}
|
||||||
|
f.comments(node.update_expr_comments, inline: true, has_nl: true, level: .keep)
|
||||||
|
}
|
||||||
|
for i, field in node.fields {
|
||||||
|
f.write('$field.name: ')
|
||||||
|
f.expr(field.expr)
|
||||||
|
f.comments(field.comments, inline: true, has_nl: false, level: .indent)
|
||||||
|
if single_line_fields {
|
||||||
|
if i < node.fields.len - 1 {
|
||||||
|
f.write(', ')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
f.writeln('')
|
||||||
|
}
|
||||||
|
f.comments(field.next_comments, inline: false, has_nl: true, level: .keep)
|
||||||
|
if single_line_fields && (field.comments.len > 0
|
||||||
|
|| field.next_comments.len > 0
|
||||||
|
|| !expr_is_single_line(field.expr)
|
||||||
|
|| f.line_len > max_len.last()) {
|
||||||
|
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 {
|
||||||
|
if single_line_fields {
|
||||||
|
f.write(' ')
|
||||||
|
}
|
||||||
|
f.write('}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
vlib/v/gen/golang/tests/simple.vv
Normal file
43
vlib/v/gen/golang/tests/simple.vv
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
module main
|
||||||
|
|
||||||
|
#import "fmt"
|
||||||
|
|
||||||
|
//fn println(x any){
|
||||||
|
fn println(x string){
|
||||||
|
#fmt.Println(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
x int
|
||||||
|
s string
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_prime(x int) bool {
|
||||||
|
for i := 2; i <= x/2; i++ {
|
||||||
|
if x % i == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
x := 10
|
||||||
|
if x % 2 == 0 {
|
||||||
|
println('even')
|
||||||
|
}
|
||||||
|
//println(x.str())
|
||||||
|
println('hello world!')
|
||||||
|
|
||||||
|
foo := Foo{}
|
||||||
|
q := foo.x
|
||||||
|
_ = q
|
||||||
|
w := q>2 && 3<q
|
||||||
|
_ = w
|
||||||
|
|
||||||
|
numbers := [1,2,3]
|
||||||
|
for number in numbers {
|
||||||
|
_ = number
|
||||||
|
}
|
||||||
|
}
|
2
vlib/v/gen/golang/tests/simple.vv.out
Normal file
2
vlib/v/gen/golang/tests/simple.vv.out
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
even
|
||||||
|
hello world!
|
@ -51,6 +51,7 @@ pub enum Backend {
|
|||||||
js_freestanding // The JavaScript freestanding backend
|
js_freestanding // The JavaScript freestanding backend
|
||||||
native // The Native backend
|
native // The Native backend
|
||||||
interpret // Interpret the ast
|
interpret // Interpret the ast
|
||||||
|
golang // Go backend
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (b Backend) is_js() bool {
|
pub fn (b Backend) is_js() bool {
|
||||||
@ -921,6 +922,7 @@ pub fn backend_from_string(s string) ?Backend {
|
|||||||
match s {
|
match s {
|
||||||
'c' { return .c }
|
'c' { return .c }
|
||||||
'js' { return .js_node }
|
'js' { return .js_node }
|
||||||
|
'go' { return .golang }
|
||||||
'js_node' { return .js_node }
|
'js_node' { return .js_node }
|
||||||
'js_browser' { return .js_browser }
|
'js_browser' { return .js_browser }
|
||||||
'js_freestanding' { return .js_freestanding }
|
'js_freestanding' { return .js_freestanding }
|
||||||
|
Loading…
Reference in New Issue
Block a user