fmt: fix multiple things and format most of the compiler (#6631)

Format expressions inside string interpolation like the rest (it used to be a+b instead of a + b, not too sure why)
Fix formatting some match branches when there were only one statement inside (it was inlined)
Fix parsing and formatting some comments edge case on struct field init. You should check out this test because the result is a bit different from before. I personally find it more logical but I would understand if the former format was to stay
Fix formatting of void-returning function signature
pull/6621/head^2
Enzo 2020-10-15 22:12:59 +02:00 committed by GitHub
parent 23644d92a9
commit b083f4014b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 414 additions and 456 deletions

View File

@ -18,37 +18,42 @@ jobs:
./v vet vlib/v
- name: v fmt -verify
run: |
./v fmt -verify vlib/v/scanner/scanner.v
./v fmt -verify vlib/v/parser/parser.v
./v fmt -verify vlib/v/parser/fn.v
./v fmt -verify vlib/v/checker/checker.v
./v fmt -verify vlib/v/gen/cgen.v
./v fmt -verify vlib/v/gen/fn.v
./v fmt -verify vlib/v/gen/x64/gen.v
./v fmt -verify vlib/v/table/table.v
./v fmt -verify vlib/v/fmt/fmt.v
./v fmt -verify vlib/builtin/array.v
./v fmt -verify vlib/os/file.v
./v fmt -verify vlib/v/util/errors.v
./v fmt -verify vlib/v/util/suggestions.v
./v fmt -verify vlib/v/util/util.v
./v fmt -verify vlib/v/builder/builder.v
./v fmt -verify vlib/v/builder/cc.v
./v fmt -verify vlib/v/builder/compile.v
./v fmt -verify vlib/v/builder/msvc.v
./v fmt -verify vlib/math/bits/bits.v
./v fmt -verify vlib/time/time.v
./v fmt -verify vlib/term/colors.v
./v fmt -verify vlib/term/term.v
./v fmt -verify vlib/v/ast/scope.v
./v fmt -verify vlib/v/checker/check_types.v
./v fmt -verify vlib/v/table/atypes.v
./v fmt -verify vlib/v/cflag/cflags.v
./v fmt -verify vlib/v/table/cflags.v
./v fmt -verify vlib/v/ast/
./v fmt -verify vlib/v/builder/
./v fmt -verify vlib/v/cflag/
./v fmt -verify vlib/v/checker/
./v fmt -verify vlib/v/depgraph/
./v fmt -verify vlib/v/doc/
./v fmt -verify vlib/v/errors/
./v fmt -verify vlib/v/eval/
./v fmt -verify vlib/v/fmt/
./v fmt -verify vlib/v/gen/auto_str_methods.v
./v fmt -verify vlib/v/parser/parse_type.v
./v fmt -verify vlib/v/gen/cgen.v
./v fmt -verify vlib/v/gen/cgen_test.v
./v fmt -verify vlib/v/gen/cmain.v
./v fmt -verify vlib/v/gen/comptime.v
./v fmt -verify vlib/v/gen/fn.v
./v fmt -verify vlib/v/gen/json.v
./v fmt -verify vlib/v/gen/live.v
./v fmt -verify vlib/v/gen/profile.v
./v fmt -verify vlib/v/gen/sql.v
./v fmt -verify vlib/v/gen/str.v
./v fmt -verify vlib/v/gen/x64/elf.v
./v fmt -verify vlib/v/gen/x64/elf_obj.v
./v fmt -verify vlib/v/gen/x64/gen.v
./v fmt -verify vlib/v/parser/
./v fmt -verify vlib/v/pref/
./v fmt -verify vlib/v/scanner/
./v fmt -verify vlib/v/table/
./v fmt -verify vlib/v/util/
./v fmt -verify vlib/v/vet/
./v fmt -verify vlib/v/vmod/
- name: v test-fmt
run: ./v -silent test-fmt

View File

@ -602,8 +602,8 @@ pub:
stmts []Stmt
pos token.Position
val_is_mut bool // `for mut val in vals {` means that modifying `val` will modify the array
pub mut:
// and the array cannot be indexed inside the loop
pub mut:
key_type table.Type
val_type table.Type
cond_type table.Type

View File

@ -58,7 +58,9 @@ pub fn (mut b Builder) compile_c() {
// println(files)
}
$if windows {
b.find_win_cc() or { verror(no_compiler_error) }
b.find_win_cc() or {
verror(no_compiler_error)
}
// TODO Probably extend this to other OS's?
}
// v1 compiler files
@ -83,7 +85,8 @@ pub fn (mut b Builder) compile_c() {
bundle_id := if b.pref.bundle_id != '' { b.pref.bundle_id } else { 'app.vlang.$bundle_name' }
display_name := if b.pref.display_name != '' { b.pref.display_name } else { bundle_name }
os.mkdir('$display_name\.app')
os.write_file('$display_name\.app/Info.plist', make_ios_plist(display_name, bundle_id, bundle_name, 1))
os.write_file('$display_name\.app/Info.plist', make_ios_plist(display_name, bundle_id,
bundle_name, 1))
}
b.cc()
}

View File

@ -1168,8 +1168,8 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
}
}
if got_arg_typ != table.void_type {
c.error('cannot use type `$got_arg_sym.source_name` as type `$exp_arg_sym.source_name` in argument ${i+1} to `${left_type_sym.source_name}.$method_name`',
call_expr.pos)
c.error('cannot use type `$got_arg_sym.source_name` as type `$exp_arg_sym.source_name` in argument ${i +
1} to `${left_type_sym.source_name}.$method_name`', call_expr.pos)
}
}
param := if method.is_variadic && i >= method.params.len - 1 { method.params[method.params.len -
@ -1186,8 +1186,8 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
} else {
if param.is_mut && (!arg.is_mut || param.typ.share() != arg.share) {
tok := arg.share.str()
c.error('`$call_expr.name` parameter `$param.name` is `$tok`, you need to provide `$tok` e.g. `$tok arg${i+1}`',
arg.expr.position())
c.error('`$call_expr.name` parameter `$param.name` is `$tok`, you need to provide `$tok` e.g. `$tok arg${i +
1}`', arg.expr.position())
}
}
}
@ -1460,8 +1460,8 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
} else {
if arg.is_mut && (!call_arg.is_mut || arg.typ.share() != call_arg.share) {
tok := call_arg.share.str()
c.error('`$call_expr.name` parameter `$arg.name` is `$tok`, you need to provide `$tok` e.g. `$tok arg${i+1}`',
call_arg.expr.position())
c.error('`$call_expr.name` parameter `$arg.name` is `$tok`, you need to provide `$tok` e.g. `$tok arg${i +
1}`', call_arg.expr.position())
}
}
// Handle expected interface
@ -1492,11 +1492,11 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
}
if typ_sym.kind == .function && arg_typ_sym.kind == .function {
candidate_fn_name := if typ_sym.source_name.starts_with('anon_') { 'anonymous function' } else { 'fn `$typ_sym.source_name`' }
c.error('cannot use $candidate_fn_name as function type `$arg_typ_sym.str()` in argument ${i+1} to `$fn_name`',
call_expr.pos)
c.error('cannot use $candidate_fn_name as function type `$arg_typ_sym.str()` in argument ${i +
1} to `$fn_name`', call_expr.pos)
} else {
c.error('cannot use type `$typ_sym.source_name` as type `$arg_typ_sym.source_name` in argument ${i+1} to `$fn_name`',
call_expr.pos)
c.error('cannot use type `$typ_sym.source_name` as type `$arg_typ_sym.source_name` in argument ${i +
1} to `$fn_name`', call_expr.pos)
}
}
}
@ -3197,21 +3197,27 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
mut is_exhaustive := true
mut unhandled := []string{}
match type_sym.info as info {
table.SumType { for v in info.variants {
table.SumType {
for v in info.variants {
v_str := c.table.type_to_str(v)
if v_str !in branch_exprs {
is_exhaustive = false
unhandled << '`$v_str`'
}
} }
}
}
//
table.Enum { for v in info.vals {
table.Enum {
for v in info.vals {
if v !in branch_exprs {
is_exhaustive = false
unhandled << '`.$v`'
}
} }
else { is_exhaustive = false }
}
}
else {
is_exhaustive = false
}
}
mut else_branch := node.branches[node.branches.len - 1]
mut has_else := else_branch.is_else

View File

@ -1,6 +1,6 @@
vlib/v/checker/tests/modules/overload_return_type/main.v:8:11: error: cannot assign to `two`: expected `Point`, not `int`
6 | one := Point {x:1, y:2}
7 | mut two := Point {x:5, y:1}
8 | two = one + two
vlib/v/checker/tests/modules/overload_return_type/main.v:14:8: error: cannot assign to `two`: expected `Point`, not `int`
12 | y: 1
13 | }
14 | two = one + two
| ~~~~~~~~~
9 | }
15 | }

View File

@ -3,7 +3,13 @@ module main
import point { Point }
fn main() {
one := Point {x:1, y:2}
mut two := Point {x:5, y:1}
one := Point{
x: 1
y: 2
}
mut two := Point{
x: 5
y: 1
}
two = one + two
}

View File

@ -35,8 +35,8 @@ pub fn (mut o OrderedDepMap) add(name string, deps []string) {
for dep in deps {
if dep !in d {
d << dep
} else {
}
else{}
}
o.set(name, d)
}
@ -135,7 +135,7 @@ pub fn (graph &DepGraph) display() string {
}
pub fn (graph &DepGraph) display_cycles() string {
mut node_names := map[string]DepGraphNode
mut node_names := map[string]DepGraphNode{}
for node in graph.nodes {
node_names[node.name] = node
}

View File

@ -56,7 +56,7 @@ pub mut:
pub fn merge_comments(comments []ast.Comment) string {
mut res := []string{}
for comment in comments {
res << comment.text.trim_left('|')
res << comment.text.trim_left('\x01')
}
return res.join('\n')
}
@ -74,7 +74,7 @@ pub fn get_comment_block_right_before(comments []ast.Comment) string {
// located right above the top level statement.
// break
}
mut cmt_content := cmt.text.trim_left('|')
mut cmt_content := cmt.text.trim_left('\x01')
if cmt_content.len == cmt.text.len || cmt.is_multi {
// ignore /* */ style comments for now
continue

View File

@ -1,7 +1,6 @@
// import v.table
// import v.doc
// import v.pref
// fn test_vdoc() {
// mut prefs := &pref.Preferences{}
// prefs.fill_with_defaults()

View File

@ -34,14 +34,14 @@ pub fn (mut e Eval) eval(file ast.File, table &table.Table) string {
fn print_object(o Object) {
match o {
int { println(it) }
int { println(o) }
else { println('unknown object') }
}
}
pub fn (o Object) str() string {
match o {
int { return it.str() }
int { return o.str() }
else { println('unknown object') }
}
return ''
@ -53,7 +53,7 @@ fn (mut e Eval) stmt(node ast.Stmt) string {
// TODO; replaced VarDecl
}
ast.ExprStmt {
o := e.expr(it.expr)
o := e.expr(node.expr)
print('out: ')
print_object(o)
return o.str()
@ -74,20 +74,20 @@ fn (mut e Eval) stmt(node ast.Stmt) string {
fn (mut e Eval) expr(node ast.Expr) Object {
match node {
ast.IntegerLiteral {
return it.val
return node.val
}
ast.Ident {
print_object(it.value)
print_object(node.value)
// Find the variable
v := e.vars[it.name]
v := e.vars[node.name]
return v.value
}
ast.InfixExpr {
e.checker.infix_expr(mut it)
e.checker.infix_expr(mut node)
// println('bin $it.op')
left := e.expr(it.left) as int
right := e.expr(it.right) as int
match it.op {
left := e.expr(node.left) as int
right := e.expr(node.right) as int
match node.op {
.plus { return left + right }
.mul { return left * right }
else {}

View File

@ -38,7 +38,6 @@ pub mut:
file ast.File
did_imports bool
is_assign bool
is_inside_interp bool
auto_imports []string // automatically inserted imports that the user forgot to specify
import_pos int // position of the imports in the resulting string for later autoimports insertion
used_imports []string // to remove unused imports
@ -609,9 +608,26 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
}
end_pos := field.pos.pos + field.pos.len
comments := field.comments
if comments.len == 0 {
// Handle comments before field
mut comm_idx := 0
for comm_idx < comments.len && comments[comm_idx].pos.pos < field.pos.pos {
f.indent++
f.empty_line = true
f.comment(comments[comm_idx], {})
f.writeln('')
f.indent--
comm_idx++
}
f.write('\t$field.name ')
f.write(strings.repeat(` `, max - field.name.len))
// Handle comments between field name and type
mut comments_len := 0
for comm_idx < comments.len && comments[comm_idx].pos.pos < end_pos {
comment_text := '/* ${comments[comm_idx].text} */ ' // TODO handle in a function
comments_len += comment_text.len
f.write(comment_text)
comm_idx++
}
f.write(strings.repeat(` `, max - field.name.len - comments_len))
f.write(field_types[i])
if field.attrs.len > 0 && field.attrs[0].name != 'ref_only' { // TODO a bug with [ref_only] attr being added to fields, fix it
f.write(strings.repeat(` `, max_type - field_types[i].len))
@ -621,43 +637,19 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
f.write(' = ')
f.prefix_expr_cast_expr(field.default_expr)
}
f.write('\n')
continue
}
// Handle comments before field
mut j := 0
for j < comments.len && comments[j].pos.pos < field.pos.pos {
f.indent++
f.empty_line = true
f.comment(comments[j], {
inline: true
})
f.writeln('')
f.indent--
j++
}
f.write('\t$field.name ')
// Handle comments between field name and type
mut comments_len := 0
for j < comments.len && comments[j].pos.pos < end_pos {
comment := '/* ${comments[j].text} */ ' // TODO: handle in a function
comments_len += comment.len
f.write(comment)
j++
}
f.write(strings.repeat(` `, max - field.name.len - comments_len))
f.write(field_types[i])
f.inline_attrs(field.attrs)
if field.has_default_expr {
f.write(' = ')
f.prefix_expr_cast_expr(field.default_expr)
}
// Handle comments after field type (same line)
for j < comments.len && field.pos.line_nr == comments[j].pos.line_nr {
f.write(' // ${comments[j].text}') // TODO: handle in a function
j++
if comm_idx < comments.len {
if comments[comm_idx].pos.line_nr > field.pos.line_nr {
f.writeln('')
} else {
f.write(' ')
}
f.comments(comments[comm_idx..], {
level: .indent
})
} else {
f.writeln('')
}
f.write('\n')
}
f.comments_after_last_field(node.end_comments)
f.writeln('}\n')
@ -1011,7 +1003,6 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
} else {
f.write("'")
}
f.is_inside_interp = true
for i, val in node.vals {
f.write(val)
if i >= node.exprs.len {
@ -1028,7 +1019,6 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
f.expr(node.exprs[i])
}
}
f.is_inside_interp = false
if contains_single_quote {
f.write('"')
} else {
@ -1093,11 +1083,7 @@ pub fn (mut f Fmt) call_args(args []ast.CallArg) {
}
f.expr(arg.expr)
if i < args.len - 1 {
if f.is_inside_interp {
f.write(', ')
} else {
f.write(', ')
}
}
}
}
@ -1145,16 +1131,20 @@ enum CommentsLevel {
indent
}
// CommentsOptions defines the way comments are going to be written
// - has_nl: adds an newline at the end of the list of comments
// - inline: single-line comments will be on the same line as the last statement
// - level: either .keep (don't indent), or .indent (increment indentation)
struct CommentsOptions {
has_nl bool = true
inline bool
level CommentsLevel = .keep
level CommentsLevel
}
pub fn (mut f Fmt) comment(node ast.Comment, options CommentsOptions) {
if !node.text.contains('\n') {
is_separate_line := !options.inline || node.text.starts_with('|')
mut s := if node.text.starts_with('|') { node.text[1..] } else { node.text }
is_separate_line := !options.inline || node.text.starts_with('\x01')
mut s := if node.text.starts_with('\x01') { node.text[1..] } else { node.text }
if s == '' {
s = '//'
} else {
@ -1258,11 +1248,6 @@ pub fn (mut f Fmt) lock_expr(lex ast.LockExpr) {
}
pub fn (mut f Fmt) infix_expr(node ast.InfixExpr) {
if f.is_inside_interp {
f.expr(node.left)
f.write('$node.op.str()')
f.expr(node.right)
} else {
buffering_save := f.buffering
if !f.buffering {
f.out_save = f.out
@ -1326,7 +1311,6 @@ pub fn (mut f Fmt) infix_expr(node ast.InfixExpr) {
f.precedences = []int{}
}
}
}
pub fn (mut f Fmt) if_expr(it ast.IfExpr) {
dollar := if it.is_comptime { '$' } else { '' }
@ -1499,15 +1483,11 @@ pub fn (mut f Fmt) match_expr(it ast.MatchExpr) {
if branch.stmts.len == 0 {
continue
}
stmt := branch.stmts[0]
if stmt is ast.ExprStmt {
// If expressions inside match branches can't be one a single line
if !expr_is_single_line(stmt.expr) {
if !stmt_is_single_line(branch.stmts[0]) {
single_line = false
break
}
}
}
for branch in it.branches {
for cmnt in branch.comments {
f.comment(cmnt, {
@ -1595,6 +1575,15 @@ 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.IfExpr { return false }

View File

@ -47,12 +47,12 @@ fn test_fmt() {
opath := ipath
expected_ocontent := os.read_file(opath) or {
fmt_bench.fail()
eprintln(fmt_bench.step_message_fail('cannot read from ${vrelpath}'))
eprintln(fmt_bench.step_message_fail('cannot read from $vrelpath'))
continue
}
table := table.new_table()
file_ast := parser.parse_file(ipath, table, .parse_comments, &pref.Preferences{
is_fmt: true,
is_fmt: true
ccompiler: 'gcc'
}, &ast.Scope{
parent: 0
@ -60,18 +60,18 @@ fn test_fmt() {
result_ocontent := fmt.fmt(file_ast, table, false)
if expected_ocontent != result_ocontent {
fmt_bench.fail()
eprintln(fmt_bench.step_message_fail('file ${vrelpath} after formatting, does not look as expected.'))
eprintln(fmt_bench.step_message_fail('file $vrelpath after formatting, does not look as expected.'))
if diff_cmd == '' {
eprintln('>> sorry, but no working "diff" CLI command can be found')
continue
}
vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_${ifilename}')
vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_$ifilename')
os.write_file(vfmt_result_file, result_ocontent)
eprintln(util.color_compare_files(diff_cmd, opath, vfmt_result_file))
continue
}
fmt_bench.ok()
eprintln(fmt_bench.step_message_ok('${vrelpath}'))
eprintln(fmt_bench.step_message_ok('$vrelpath'))
}
fmt_bench.stop()
eprintln(term.h_divider('-'))

View File

@ -23,7 +23,9 @@ fn test_fmt() {
}
vroot := os.dir(vexe)
tmpfolder := os.temp_dir()
diff_cmd := util.find_working_diff_command() or { '' }
diff_cmd := util.find_working_diff_command() or {
''
}
mut fmt_bench := benchmark.new_benchmark()
// Lookup the existing test _input.vv files:
input_files := os.walk_ext('$vroot/vlib/v/fmt/tests', '_input.vv')
@ -35,12 +37,12 @@ fn test_fmt() {
opath := ipath.replace('_input.vv', '_expected.vv')
if !os.exists(opath) {
fmt_bench.fail()
eprintln(fmt_bench.step_message_fail('missing file ${opath}'))
eprintln(fmt_bench.step_message_fail('missing file $opath'))
continue
}
expected_ocontent := os.read_file(opath) or {
fmt_bench.fail()
eprintln(fmt_bench.step_message_fail('cannot read from ${opath}'))
eprintln(fmt_bench.step_message_fail('cannot read from $opath'))
continue
}
table := table.new_table()
@ -52,18 +54,18 @@ fn test_fmt() {
result_ocontent := fmt.fmt(file_ast, table, false)
if expected_ocontent != result_ocontent {
fmt_bench.fail()
eprintln(fmt_bench.step_message_fail('file ${ipath} after formatting, does not look as expected.'))
eprintln(fmt_bench.step_message_fail('file $ipath after formatting, does not look as expected.'))
if diff_cmd == '' {
eprintln('>> sorry, but no working "diff" CLI command can be found')
continue
}
vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_${ifilename}')
vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_$ifilename')
os.write_file(vfmt_result_file, result_ocontent)
eprintln(util.color_compare_files(diff_cmd, opath, vfmt_result_file))
continue
}
fmt_bench.ok()
eprintln(fmt_bench.step_message_ok('${ipath}'))
eprintln(fmt_bench.step_message_ok('$ipath'))
}
fmt_bench.stop()
eprintln(term.h_divider('-'))

View File

@ -40,7 +40,7 @@ fn test_vlib_fmt() {
opath := ipath
expected_ocontent := os.read_file(opath) or {
fmt_bench.fail()
eprintln(fmt_bench.step_message_fail('cannot read from ${opath}'))
eprintln(fmt_bench.step_message_fail('cannot read from $opath'))
continue
}
table := table.new_table()
@ -52,18 +52,18 @@ fn test_vlib_fmt() {
result_ocontent := fmt.fmt(file_ast, table, false)
if expected_ocontent != result_ocontent {
fmt_bench.fail()
eprintln(fmt_bench.step_message_fail('file ${ipath} after formatting, does not look as expected.'))
eprintln(fmt_bench.step_message_fail('file $ipath after formatting, does not look as expected.'))
if diff_cmd == '' {
eprintln('>> sorry, but no working "diff" CLI command can be found')
continue
}
vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_${ifilename}')
vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_$ifilename')
os.write_file(vfmt_result_file, result_ocontent)
eprintln(util.color_compare_files(diff_cmd, opath, vfmt_result_file))
continue
}
fmt_bench.ok()
eprintln(fmt_bench.step_message_ok('${ipath}'))
eprintln(fmt_bench.step_message_ok('$ipath'))
}
fmt_bench.stop()
eprintln(term.h_divider('-'))

View File

@ -1,3 +1,7 @@
pub fn (a []int) reduce(iter fn (int, int) int, accum_start int) int {
iter(accum_start)
}
pub fn test_anon_fn_void(func fn ()) int {
return 0
}

View File

@ -28,7 +28,9 @@ mut:
// 1
// 2
// 3
somefield /* 4 */ /* 5 */ int // 6 // 7 // 8
somefield /* 4 */ /* 5 */ int // 6
// 7
// 8
/*
9
10

View File

@ -32,14 +32,14 @@ fn test_c_files() {
res = res[..pos] + res[end + 15..]
}
if compare_texts(res, ctext, path) {
println('${term_ok} ${i}')
println('$term_ok $i')
} else {
assert false
}
}
}
fn compare_texts(a, b, path string) bool {
fn compare_texts(a string, b string, path string) bool {
lines_a_ := a.trim_space().split_into_lines()
lines_b_ := b.trim_space().split_into_lines()
lines_a := lines_a_.filter(it != '')
@ -60,8 +60,8 @@ fn compare_texts(a, b, path string) bool {
}
line_b := lines_b[i]
if line_a.trim_space() != line_b.trim_space() {
println('${path}: Got\n$a')
println('${path}:${i}: ${term_fail}')
println('$path: Got\n$a')
println('$path:$i: $term_fail')
println(term.bold(term.bright_yellow('actual : ')) + line_a)
println(term.green('expected: ') + line_b)
println(lines_b[i + 1])
@ -72,8 +72,3 @@ fn compare_texts(a, b, path string) bool {
}
return true
}
fn test_nested_if() {
a := if true { if true { 'a' } else { 'b' } } else { 'c' }
assert a == 'a'
}

View File

@ -35,7 +35,7 @@ fn (mut g Gen) gen_vlines_reset() {
g.vlines_path = util.vlines_escape_path(g.pref.out_name_c, g.pref.ccompiler)
g.writeln('')
g.writeln('\n// Reset the file/line numbers')
g.writeln('\n#line $lines_so_far "${g.vlines_path}"')
g.writeln('\n#line $lines_so_far "$g.vlines_path"')
g.writeln('')
}
}
@ -111,7 +111,6 @@ void (_vsokol_cleanup_userdata_cb)(void* user_data) {
}
')
}
g.writeln('// The sokol_main entry point on Android
sapp_desc sokol_main(int argc, char* argv[]) {
(void)argc; (void)argv;

View File

@ -106,7 +106,9 @@ fn (mut g Gen) comp_if(node ast.IfExpr) {
stmt_str := g.go_before_stmt(0)
g.write(tabs[g.indent])
stmt_str.trim_space()
} else { '' }
} else {
''
}
for i, branch in node.branches {
start_pos := g.out.len
if i == node.branches.len - 1 && node.has_else {
@ -146,13 +148,21 @@ fn (mut g Gen) comp_if(node ast.IfExpr) {
} else {
// Only wrap the contents in {} if we're inside a function, not on the top level scope
should_create_scope := g.fn_decl != 0
if should_create_scope { g.writeln('{') }
if should_create_scope {
g.writeln('{')
}
g.stmts(branch.stmts)
if should_create_scope { g.writeln('}') }
if should_create_scope {
g.writeln('}')
}
}
g.defer_ifdef = ''
}
if node.is_expr { g.write('#endif') } else { g.writeln('#endif') }
if node.is_expr {
g.write('#endif')
} else {
g.writeln('#endif')
}
}
fn (mut g Gen) comp_if_expr(cond ast.Expr) {
@ -161,13 +171,16 @@ fn (mut g Gen) comp_if_expr(cond ast.Expr) {
g.write('(')
g.comp_if_expr(cond.expr)
g.write(')')
} ast.PrefixExpr {
}
ast.PrefixExpr {
g.write(cond.op.str())
g.comp_if_expr(cond.right)
} ast.PostfixExpr {
}
ast.PostfixExpr {
ifdef := g.comp_if_to_ifdef((cond.expr as ast.Ident).name, true)
g.write('defined($ifdef)')
} ast.InfixExpr {
}
ast.InfixExpr {
match cond.op {
.and, .logical_or {
g.comp_if_expr(cond.left)
@ -180,14 +193,18 @@ fn (mut g Gen) comp_if_expr(cond ast.Expr) {
exp_type := g.comptime_var_type_map[name]
got_type := (cond.right as ast.Type).typ
g.write('$exp_type == $got_type')
} .eq, .ne {
// TODO Implement `$if method.args.len == 1`
} else {}
}
} ast.Ident {
.eq, .ne {
// TODO Implement `$if method.args.len == 1`
}
else {}
}
}
ast.Ident {
ifdef := g.comp_if_to_ifdef(cond.name, false)
g.write('defined($ifdef)')
} else {}
}
else {}
}
}

View File

@ -34,11 +34,7 @@ const (
)
pub fn (mut g Gen) generate_elf_header() {
g.buf << [byte(mag0),
mag1,
mag2,
mag3
]
g.buf << [byte(mag0), mag1, mag2, mag3]
g.buf << elfclass64 // file class
g.buf << elfdata2lsb // data encoding
g.buf << ev_current // file version

View File

@ -32,7 +32,7 @@ fn test_x64() {
bench.step()
full_test_path := os.real_path(test)
println('x.v: $wrkdir/x.v')
os.system('cp ${dir}/${test} $wrkdir/x.v') // cant run .vv file
os.system('cp $dir/$test $wrkdir/x.v') // cant run .vv file
os.exec('$vexe -o exe -x64 $wrkdir/x.v') or {
bench.fail()
eprintln(bench.step_message_fail('x64 $test failed'))

View File

@ -63,9 +63,15 @@ fn (mut p Parser) check_cross_variables(exprs []ast.Expr, val ast.Expr) bool {
}
}
}
ast.InfixExpr { return p.check_cross_variables(exprs, val_.left) || p.check_cross_variables(exprs, val_.right) }
ast.PrefixExpr { return p.check_cross_variables(exprs, val_.right) }
ast.PostfixExpr { return p.check_cross_variables(exprs, val_.expr) }
ast.InfixExpr {
return p.check_cross_variables(exprs, val_.left) || p.check_cross_variables(exprs, val_.right)
}
ast.PrefixExpr {
return p.check_cross_variables(exprs, val_.right)
}
ast.PostfixExpr {
return p.check_cross_variables(exprs, val_.expr)
}
ast.SelectorExpr {
for expr in exprs {
if expr.str() == val.str() {
@ -119,7 +125,8 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme
share = iv.share
if iv.is_static {
if !p.pref.translated {
p.error_with_pos('static variables are supported only in -translated mode', lx.pos)
p.error_with_pos('static variables are supported only in -translated mode',
lx.pos)
}
is_static = true
}

View File

@ -72,7 +72,8 @@ fn (mut p Parser) array_init() ast.ArrayInit {
last_pos = p.tok.position()
p.check(.rcbr)
} else {
p.warn_with_pos('use e.g. `x := [1]Type{}` instead of `x := [1]Type`', last_pos)
p.warn_with_pos('use e.g. `x := [1]Type{}` instead of `x := [1]Type`',
last_pos)
}
} else {
if p.tok.kind == .not {

View File

@ -13,8 +13,6 @@ fn (mut p Parser) lock_expr() ast.LockExpr {
for p.tok.kind == .name {
lockeds << ast.Ident{
language: table.Language.v
// kind is set in checker once ident is processed
// kind: .variable
pos: p.tok.position()
mod: p.mod
name: p.tok.lit

View File

@ -21,7 +21,8 @@ pub struct Parser {
pref &pref.Preferences
mut:
scanner &scanner.Scanner
comments_mode scanner.CommentsMode = .skip_comments // see comment in parse_file
comments_mode scanner.CommentsMode = .skip_comments
// see comment in parse_file
tok token.Token
prev_tok token.Token
peek_tok token.Token

View File

@ -47,13 +47,9 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
}
.dollar {
match p.peek_tok.kind {
.name {
return p.vweb()
} .key_if {
return p.if_expr(true)
} else {
p.error('unexpected $')
}
.name { return p.vweb() }
.key_if { return p.if_expr(true) }
else { p.error('unexpected $') }
}
}
.chartoken {
@ -275,7 +271,8 @@ pub fn (mut p Parser) expr_with_left(left ast.Expr, precedence int, is_stmt_iden
return node
}
// added 10/2020: LATER this will be parsed as PrefixExpr instead
p.warn_with_pos('move infix `$p.tok.kind` operator before new line (if infix intended) or use brackets for a prefix expression', p.tok.position())
p.warn_with_pos('move infix `$p.tok.kind` operator before new line (if infix intended) or use brackets for a prefix expression',
p.tok.position())
}
// continue on infix expr
node = p.infix_expr(node)
@ -286,9 +283,9 @@ pub fn (mut p Parser) expr_with_left(left ast.Expr, precedence int, is_stmt_iden
} else if p.tok.kind in [.inc, .dec] || (p.tok.kind == .question && p.inside_ct_if_expr) {
// Postfix
// detect `f(x++)`, `a[x++]`
if p.peek_tok.kind in [.rpar, .rsbr] &&
p.mod !in ['builtin', 'regex', 'strconv'] { // temp
p.warn_with_pos('`$p.tok.kind` operator can only be used as a statement', p.peek_tok.position())
if p.peek_tok.kind in [.rpar, .rsbr] && p.mod !in ['builtin', 'regex', 'strconv'] { // temp
p.warn_with_pos('`$p.tok.kind` operator can only be used as a statement',
p.peek_tok.position())
}
node = ast.PostfixExpr{
op: p.tok.kind
@ -321,8 +318,8 @@ fn (mut p Parser) infix_expr(left ast.Expr) ast.Expr {
}
right = p.expr(precedence)
p.expecting_type = prev_expecting_type
if p.pref.is_vet && op in [.key_in, .not_in] &&
right is ast.ArrayInit && (right as ast.ArrayInit).exprs.len == 1 {
if p.pref.is_vet && op in [.key_in, .not_in] && right is ast.ArrayInit && (right as ast.ArrayInit).exprs.len ==
1 {
p.vet_error('Use `var == value` instead of `var in [value]`', pos.line_nr)
}
return ast.InfixExpr{

View File

@ -154,22 +154,8 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
typ := p.parse_type()
type_pos := p.prev_tok.position()
field_pos := field_start_pos.extend(type_pos)
// if name == '_net_module_s' {
// if name.contains('App') {
// s := p.table.get_type_symbol(typ)
// println('struct decl field type ' + s.str())
// }
// Comments after type (same line)
line_pos := field_pos.line_nr
for p.tok.kind == .comment && line_pos + 1 == p.tok.line_nr {
if p.tok.lit.contains('\n') {
break
}
comments << p.comment()
if p.tok.kind == .rcbr {
break
}
}
comments << p.eat_comments()
if p.tok.kind == .lsbr {
// attrs are stored in `p.attrs`
p.attributes()
@ -284,38 +270,38 @@ fn (mut p Parser) struct_init(short_syntax bool) ast.StructInit {
p.is_amp = false
for p.tok.kind != .rcbr && p.tok.kind != .rpar {
mut field_name := ''
mut expr := ast.Expr{}
mut field_pos := token.Position{}
mut comments := []ast.Comment{}
if no_keys {
expr := p.expr(0)
comments := p.eat_comments()
// name will be set later in checker
fields << ast.StructInitField{
expr: expr
pos: expr.position()
comments: comments
}
expr = p.expr(0)
field_pos = expr.position()
comments = p.eat_comments()
} else {
first_field_pos := p.tok.position()
field_name = p.check_name()
p.check(.colon)
expr := p.expr(0)
comments := p.eat_comments()
expr = p.expr(0)
comments = p.eat_comments()
last_field_pos := expr.position()
field_pos := token.Position{
field_pos = token.Position{
line_nr: first_field_pos.line_nr
pos: first_field_pos.pos
len: last_field_pos.pos - first_field_pos.pos + last_field_pos.len
}
fields << ast.StructInitField{
name: field_name
expr: expr
pos: field_pos
comments: comments
}
}
i++
if p.tok.kind == .comma {
p.next()
}
comments << p.eat_comments()
fields << ast.StructInitField{
name: field_name
expr: expr
pos: field_pos
comments: comments
}
}
last_pos := p.tok.position()
if !short_syntax {

View File

@ -125,14 +125,15 @@ fn test_parse_expr() {
if true {
return
}
input := ['1 == 1', '234234', '2 * 8 + 3', 'a := 3', 'a++', 'b := 4 + 2', 'neg := -a',
'a + a', 'bo := 2 + 3 == 5', '2 + 1', 'q := 1', 'q + 777', '2 + 3', '2+2*4', 'x := 10',
'mut aa := 12', 'ab := 10 + 3 * 9', 's := "hi"', 'x = 11', 'a += 10', '1.2 + 3.4', '4 + 4',
'1 + 2 * 5', '-a+1', '2+2']
expecting := ['1 == 1;', '234234;', '2 * 8 + 3;', 'int a = 3;', 'a++;', 'int b = 4 + 2;',
'int neg = -a;', 'a + a;', 'bool bo = 2 + 3 == 5;', '2 + 1;', 'int q = 1;', 'q + 777;',
'2 + 3;', '2 + 2 * 4;', 'int x = 10;', 'int aa = 12;', 'int ab = 10 + 3 * 9;', 'string s = tos3("hi");',
'x = 11;', 'a += 10;', '1.2 + 3.4;', '4 + 4;', '1 + 2 * 5;', '-a + 1;', '2 + 2;']
input := ['1 == 1', '234234', '2 * 8 + 3', 'a := 3', 'a++', 'b := 4 + 2', 'neg := -a', 'a + a',
'bo := 2 + 3 == 5', '2 + 1', 'q := 1', 'q + 777', '2 + 3', '2+2*4', 'x := 10', 'mut aa := 12',
'ab := 10 + 3 * 9', 's := "hi"', 'x = 11', 'a += 10', '1.2 + 3.4', '4 + 4', '1 + 2 * 5', '-a+1',
'2+2',
]
expecting := ['1 == 1;', '234234;', '2 * 8 + 3;', 'int a = 3;', 'a++;', 'int b = 4 + 2;', 'int neg = -a;',
'a + a;', 'bool bo = 2 + 3 == 5;', '2 + 1;', 'int q = 1;', 'q + 777;', '2 + 3;', '2 + 2 * 4;',
'int x = 10;', 'int aa = 12;', 'int ab = 10 + 3 * 9;', 'string s = tos3("hi");', 'x = 11;', 'a += 10;',
'1.2 + 3.4;', '4 + 4;', '1 + 2 * 5;', '-a + 1;', '2 + 2;']
mut e := []ast.Stmt{}
table := table.new_table()
vpref := &pref.Preferences{}

View File

@ -22,95 +22,39 @@ pub enum OS {
// Helper function to convert string names to OS enum
pub fn os_from_string(os_str string) ?OS {
match os_str {
'linux' {
return .linux
}
'windows' {
return .windows
}
'ios' {
return .ios
}
'macos' {
return .macos
}
'freebsd' {
return .freebsd
}
'openbsd' {
return .openbsd
}
'netbsd' {
return .netbsd
}
'dragonfly' {
return .dragonfly
}
'js' {
return .js
}
'solaris' {
return .solaris
}
'android' {
return .android
}
'haiku' {
return .haiku
}
'linux_or_macos' {
return .linux
}
'' {
return ._auto
}
else {
return error('bad OS $os_str')
}
'linux' { return .linux }
'windows' { return .windows }
'ios' { return .ios }
'macos' { return .macos }
'freebsd' { return .freebsd }
'openbsd' { return .openbsd }
'netbsd' { return .netbsd }
'dragonfly' { return .dragonfly }
'js' { return .js }
'solaris' { return .solaris }
'android' { return .android }
'haiku' { return .haiku }
'linux_or_macos' { return .linux }
'' { return ._auto }
else { return error('bad OS $os_str') }
}
}
pub fn (o OS) str() string {
match o {
._auto {
return 'RESERVED: AUTO'
}
.ios {
return 'iOS'
}
.macos {
return 'MacOS'
}
.linux {
return 'Linux'
}
.windows {
return 'Windows'
}
.freebsd {
return 'FreeBSD'
}
.openbsd {
return 'OpenBSD'
}
.netbsd {
return 'NetBSD'
}
.dragonfly {
return 'Dragonfly'
}
.js {
return 'JavaScript'
}
.android {
return 'Android'
}
.solaris {
return 'Solaris'
}
.haiku {
return 'Haiku'
}
._auto { return 'RESERVED: AUTO' }
.ios { return 'iOS' }
.macos { return 'MacOS' }
.linux { return 'Linux' }
.windows { return 'Windows' }
.freebsd { return 'FreeBSD' }
.openbsd { return 'OpenBSD' }
.netbsd { return 'NetBSD' }
.dragonfly { return 'Dragonfly' }
.js { return 'JavaScript' }
.android { return 'Android' }
.solaris { return 'Solaris' }
.haiku { return 'Haiku' }
}
}

View File

@ -1104,7 +1104,7 @@ fn (mut s Scanner) text_scan() token.Token {
}
}
if is_separate_line_comment {
comment = '|' + comment
comment = '\x01' + comment
}
return s.new_token(.comment, comment, comment.len + 2)
}

View File

@ -20,7 +20,8 @@ fn (mut t TestStruct) test_struct_w_high_order(cb fn(int)string) string {
return 'test' + cb(2)
}
struct TestFn { }
struct TestFn {
}
fn (mut t TestFn) tst_1() {
assert @FN == 'tst_1'
@ -49,13 +50,11 @@ fn test_at_file() {
fn test_at_fn() {
// Test @FN
assert @FN == 'test_at_fn'
fn_name_mod_level()
fn_name_mod_level_high_order(fn (i int) {
t := i + 1
assert t == 2
})
mut tfn := TestFn{}
tfn.tst_1()
tfn.tst_2(fn (i int) {
@ -72,7 +71,9 @@ fn test_at_mod() {
fn test_at_struct() {
// Test @STRUCT
assert @STRUCT == ''
mut ts := TestStruct { test: "test" }
mut ts := TestStruct{
test: 'test'
}
ts.test_struct()
r1 := ts.test_struct_w_return()
r2 := ts.test_struct_w_high_order(fn (i int) string {

View File

@ -59,14 +59,12 @@ fn test_float_without_fraction() {
assert result[0] == .name
assert result[1] == .decl_assign
assert result[2] == .number
result = scan_kinds('return 3., 4.')
assert result.len == 4
assert result[0] == .key_return
assert result[1] == .number
assert result[2] == .comma
assert result[3] == .number
result = scan_kinds('fun(5.)')
assert result.len == 4
assert result[0] == .name

View File

@ -21,8 +21,7 @@ pub fn (attr Attr) str() string {
}
if attr.is_string {
s += "'$attr.name'"
}
else {
} else {
s += attr.name
if attr.arg.len > 0 {
s += ': '
@ -31,8 +30,7 @@ pub fn (attr Attr) str() string {
// FIXME: other escapes e.g. \r\n
a = a.replace("'", "\\'")
s += "'$a'"
}
else {
} else {
s += attr.arg
}
}

View File

@ -64,7 +64,7 @@ fn assert_parse_invalid_flag(mut t table.Table, flag string) {
assert false
}
fn make_flag(os, name, value string) cflag.CFlag {
fn make_flag(os string, name string, value string) cflag.CFlag {
return cflag.CFlag{
mod: module_name
os: os

View File

@ -117,7 +117,10 @@ pub fn (f &Fn) source_signature() string {
sig += ', '
}
}
sig += ') $f.return_type_source_name'
sig += ')'
if f.return_type != void_type {
sig += ' $f.return_type_source_name'
}
return sig
}

View File

@ -56,7 +56,7 @@ fn opendiff_exists() bool {
pub fn color_compare_files(diff_cmd string, file1 string, file2 string) string {
if diff_cmd != '' {
full_cmd := '$diff_cmd --minimal --text --unified=2 ' + ' --show-function-line="fn " "$file1" "$file2" '
full_cmd := '$diff_cmd --minimal --text --unified=2 --show-function-line="fn " "$file1" "$file2" '
x := os.exec(full_cmd) or {
return 'comparison command: `$full_cmd` failed'
}

View File

@ -21,7 +21,7 @@ fn get_tests_in_dir(dir string) []string {
return tests
}
fn check_path(vexe, dir string, tests []string) int {
fn check_path(vexe string, dir string, tests []string) int {
mut nb_fail := 0
paths := vtest.filter_vtest_only(tests, {
basepath: dir