ci: vet all files from the compiler (#5994)

pull/5996/head
Enzo 2020-07-27 12:15:29 +02:00 committed by GitHub
parent 1086150ab9
commit 2de1437a1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 650 additions and 643 deletions

View File

@ -45,12 +45,8 @@ jobs:
run: ./v build-tools run: ./v build-tools
- name: v vet - name: v vet
run: | run: |
./v vet vlib/v/scanner
./v vet vlib/v/parser
./v vet vlib/v/ast
./v vet vlib/v/gen/cgen.v
./v vet vlib/v/checker
./v vet vlib/sqlite ./v vet vlib/sqlite
./v vet vlib/v
- name: v fmt - name: v fmt
run: | run: |
./v fmt -verify vlib/v/checker/checker.v ./v fmt -verify vlib/v/checker/checker.v

View File

@ -48,7 +48,7 @@ pub fn (mut b Builder) build_c(v_files []string, out_file string) {
pub fn (mut b Builder) compile_c() { pub fn (mut b Builder) compile_c() {
if os.user_os() != 'windows' && b.pref.ccompiler == 'msvc' { if os.user_os() != 'windows' && b.pref.ccompiler == 'msvc' {
verror('Cannot build with msvc on ${os.user_os()}') verror('Cannot build with msvc on $os.user_os()')
} }
// cgen.genln('// Generated by V') // cgen.genln('// Generated by V')
// println('compile2()') // println('compile2()')
@ -57,7 +57,9 @@ pub fn (mut b Builder) compile_c() {
// println(files) // println(files)
} }
$if windows { $if windows {
b.pref.ccompiler = b.find_win_cc() or { panic(no_compiler_error) } b.pref.ccompiler = b.find_win_cc() or {
panic(no_compiler_error)
}
} }
// v1 compiler files // v1 compiler files
// v.add_v_files_to_compile() // v.add_v_files_to_compile()

View File

@ -10,10 +10,13 @@ fn (v &Builder) get_os_cflags() []cflag.CFlag {
ctimedefines << v.pref.compile_defines ctimedefines << v.pref.compile_defines
} }
for flag in v.table.cflags { for flag in v.table.cflags {
if flag.os == '' || (flag.os == 'linux' && v.pref.os == .linux) || (flag.os == 'darwin' && if flag.os == '' ||
v.pref.os == .mac) || (flag.os == 'freebsd' && v.pref.os == .freebsd) || (flag.os == 'windows' && (flag.os == 'linux' && v.pref.os == .linux) ||
v.pref.os == .windows) || (flag.os == 'mingw' && v.pref.os == .windows && v.pref.ccompiler != (flag.os == 'darwin' && v.pref.os == .mac) ||
'msvc') || (flag.os == 'solaris' && v.pref.os == .solaris) { (flag.os == 'freebsd' && v.pref.os == .freebsd) ||
(flag.os == 'windows' && v.pref.os == .windows) ||
(flag.os == 'mingw' && v.pref.os == .windows && v.pref.ccompiler != 'msvc') ||
(flag.os == 'solaris' && v.pref.os == .solaris) {
flags << flag flags << flag
} }
if flag.os in ctimedefines { if flag.os in ctimedefines {

View File

@ -34,4 +34,4 @@ pub fn (b &Builder) generic_struct_insts_to_concrete() {
typ.info = parent_info typ.info = parent_info
} }
} }
} }

View File

@ -8,7 +8,6 @@ import v.cflag
#flag windows -l shell32 #flag windows -l shell32
#flag windows -l dbghelp #flag windows -l dbghelp
#flag windows -l advapi32 #flag windows -l advapi32
struct MsvcResult { struct MsvcResult {
full_cl_exe_path string full_cl_exe_path string
exe_path string exe_path string
@ -19,7 +18,7 @@ struct MsvcResult {
ucrt_include_path string ucrt_include_path string
vs_include_path string vs_include_path string
shared_include_path string shared_include_path string
valid bool valid bool
} }
// shell32 for RegOpenKeyExW etc // shell32 for RegOpenKeyExW etc
@ -51,7 +50,8 @@ fn find_windows_kit_internal(key RegKey, versions []string) ?string {
continue continue
} }
// //
else{} else {
}
result2 := C.RegQueryValueEx(key, version.to_wide(), 0, 0, value, &alloc_length) result2 := C.RegQueryValueEx(key, version.to_wide(), 0, 0, value, &alloc_length)
if result2 != 0 { if result2 != 0 {
continue continue
@ -143,7 +143,7 @@ fn find_vs(vswhere_dir, host_arch string) ?VsInstallation {
res_output := res.output.trim_right('\r\n') res_output := res.output.trim_right('\r\n')
// println('res: "$res"') // println('res: "$res"')
version := os.read_file('$res_output\\VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt') or { version := os.read_file('$res_output\\VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt') or {
//println('Unable to find msvc version') // println('Unable to find msvc version')
return error('Unable to find vs installation') return error('Unable to find vs installation')
} }
version2 := version // TODO remove. cgen option bug if expr version2 := version // TODO remove. cgen option bug if expr
@ -214,13 +214,11 @@ pub fn (mut v Builder) cc_msvc() {
} else { } else {
a << '/MDd' a << '/MDd'
} }
if v.pref.is_debug { if v.pref.is_debug {
// /Zi generates a .pdb // /Zi generates a .pdb
// /Fd sets the pdb file name (so its not just vc140 all the time) // /Fd sets the pdb file name (so its not just vc140 all the time)
a << ['/Zi', '/Fd"$out_name_pdb"'] a << ['/Zi', '/Fd"$out_name_pdb"']
} }
if v.pref.is_shared { if v.pref.is_shared {
if !v.pref.out_name.ends_with('.dll') { if !v.pref.out_name.ends_with('.dll') {
v.pref.out_name += '.dll' v.pref.out_name += '.dll'
@ -261,7 +259,7 @@ pub fn (mut v Builder) cc_msvc() {
// Not all of these are needed (but the compiler should discard them if they are not used) // Not all of these are needed (but the compiler should discard them if they are not used)
// these are the defaults used by msbuild and visual studio // these are the defaults used by msbuild and visual studio
mut real_libs := ['kernel32.lib', 'user32.lib', 'advapi32.lib'] mut real_libs := ['kernel32.lib', 'user32.lib', 'advapi32.lib']
//sflags := v.get_os_cflags().msvc_string_flags() // sflags := v.get_os_cflags().msvc_string_flags()
sflags := msvc_string_flags(v.get_os_cflags()) sflags := msvc_string_flags(v.get_os_cflags())
real_libs << sflags.real_libs real_libs << sflags.real_libs
inc_paths := sflags.inc_paths inc_paths := sflags.inc_paths
@ -324,7 +322,6 @@ pub fn (mut v Builder) cc_msvc() {
fn (mut v Builder) build_thirdparty_obj_file_with_msvc(path string, moduleflags []cflag.CFlag) { fn (mut v Builder) build_thirdparty_obj_file_with_msvc(path string, moduleflags []cflag.CFlag) {
msvc := v.cached_msvc msvc := v.cached_msvc
if msvc.valid == false { if msvc.valid == false {
verror('Cannot find MSVC on this OS') verror('Cannot find MSVC on this OS')
return return
@ -368,7 +365,7 @@ mut:
other_flags []string other_flags []string
} }
//pub fn (cflags []CFlag) msvc_string_flags() MsvcStringFlags { // pub fn (cflags []CFlag) msvc_string_flags() MsvcStringFlags {
pub fn msvc_string_flags(cflags []cflag.CFlag) MsvcStringFlags { pub fn msvc_string_flags(cflags []cflag.CFlag) MsvcStringFlags {
mut real_libs := []string{} mut real_libs := []string{}
mut inc_paths := []string{} mut inc_paths := []string{}

View File

@ -17,7 +17,6 @@ pub fn (mut b Builder) build_x64(v_files []string, out_file string) {
t1 := time.ticks() t1 := time.ticks()
parse_time := t1 - t0 parse_time := t1 - t0
b.timing_message('PARSE', parse_time) b.timing_message('PARSE', parse_time)
b.checker.check_files(b.parsed_files) b.checker.check_files(b.parsed_files)
t2 := time.ticks() t2 := time.ticks()
check_time := t2 - t1 check_time := t2 - t1

View File

@ -18,7 +18,8 @@ fn test_all() {
// -prod so that warns are errors // -prod so that warns are errors
total_errors += check_path(vexe, classic_dir, '-prod', '.out', classic_tests) total_errors += check_path(vexe, classic_dir, '-prod', '.out', classic_tests)
total_errors += check_path(vexe, global_dir, '--enable-globals', '.out', global_tests) total_errors += check_path(vexe, global_dir, '--enable-globals', '.out', global_tests)
total_errors += check_path(vexe, classic_dir, '--enable-globals run', '.run.out', ['globals_error.vv']) total_errors += check_path(vexe, classic_dir, '--enable-globals run', '.run.out',
['globals_error.vv'])
total_errors += check_path(vexe, run_dir, 'run', '.run.out', run_tests) total_errors += check_path(vexe, run_dir, 'run', '.run.out', run_tests)
total_errors += check_path(vexe, parser_dir, '-prod', '.out', parser_tests) total_errors += check_path(vexe, parser_dir, '-prod', '.out', parser_tests)
assert total_errors == 0 assert total_errors == 0
@ -76,7 +77,7 @@ fn check_path(vexe, dir, voptions, result_extension string, tests []string) int
println('found:') println('found:')
println(found) println(found)
println('============\n') println('============\n')
diff_content( expected, found ) diff_content(expected, found)
nb_fail++ nb_fail++
} else { } else {
println(term.green('OK')) println(term.green('OK'))
@ -95,9 +96,11 @@ fn clean_line_endings(s string) string {
return res return res
} }
fn diff_content(s1 string, s2 string) { fn diff_content(s1, s2 string) {
diff_cmd := util.find_working_diff_command() or { return } diff_cmd := util.find_working_diff_command() or {
return
}
println('diff: ') println('diff: ')
println( util.color_compare_strings(diff_cmd, s1, s2) ) println(util.color_compare_strings(diff_cmd, s1, s2))
println('============\n') println('============\n')
} }

View File

@ -914,7 +914,7 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
} }
ast.PrefixExpr { ast.PrefixExpr {
f.write(node.op.str()) f.write(node.op.str())
f.prefix_expr_cast_expr( node.right ) f.prefix_expr_cast_expr(node.right)
} }
ast.RangeExpr { ast.RangeExpr {
f.expr(node.low) f.expr(node.low)
@ -1274,12 +1274,8 @@ pub fn (mut f Fmt) infix_expr(node ast.InfixExpr) {
else {} else {}
} }
match node.right as right { match node.right as right {
ast.InfixExpr { ast.InfixExpr { penalty-- }
penalty-- ast.ParExpr { penalty = 1 }
}
ast.ParExpr {
penalty = 1
}
else {} else {}
} }
f.penalties << penalty f.penalties << penalty
@ -1311,8 +1307,8 @@ pub fn (mut f Fmt) infix_expr(node ast.InfixExpr) {
} }
pub fn (mut f Fmt) if_expr(it ast.IfExpr) { pub fn (mut f Fmt) if_expr(it ast.IfExpr) {
single_line := it.branches.len == 2 && it.has_else && single_line := it.branches.len == 2 && it.has_else && it.branches[0].stmts.len == 1 &&
it.branches[0].stmts.len == 1 && it.branches[1].stmts.len == 1 && it.branches[1].stmts.len == 1 &&
(it.is_expr || f.is_assign) (it.is_expr || f.is_assign)
f.single_line_if = single_line f.single_line_if = single_line
for i, branch in it.branches { for i, branch in it.branches {
@ -1321,11 +1317,9 @@ pub fn (mut f Fmt) if_expr(it ast.IfExpr) {
if branch.cond is ast.InfixExpr { if branch.cond is ast.InfixExpr {
infix := branch.cond as ast.InfixExpr infix := branch.cond as ast.InfixExpr
if infix.op == .key_is && if infix.op == .key_is &&
(infix.left is ast.Ident || infix.left is ast.SelectorExpr) && (infix.left is ast.Ident || infix.left is ast.SelectorExpr) && infix.right is ast.Type {
infix.right is ast.Type { // right_expr := infix.right as ast.Type
//right_expr := infix.right as ast.Type is_variable = if infix.left is ast.Ident { (infix.left as ast.Ident).kind == .variable } else { true }
is_variable = if infix.left is ast.Ident { (infix.left as ast.Ident).kind ==
.variable } else { true }
} }
} }
if i == 0 { if i == 0 {
@ -1661,15 +1655,12 @@ pub fn (mut f Fmt) array_init(it ast.ArrayInit) {
} }
mut penalty := if f.array_init_break[f.array_init_depth - 1] { 0 } else { 3 } mut penalty := if f.array_init_break[f.array_init_depth - 1] { 0 } else { 3 }
if penalty > 0 { if penalty > 0 {
if i == 0 || if i == 0 || it.exprs[i - 1] is ast.ArrayInit || it.exprs[i - 1] is ast.StructInit ||
it.exprs[i - 1] is ast.ArrayInit ||
it.exprs[i - 1] is ast.StructInit ||
it.exprs[i - 1] is ast.MapInit || it.exprs[i - 1] is ast.CallExpr { it.exprs[i - 1] is ast.MapInit || it.exprs[i - 1] is ast.CallExpr {
penalty-- penalty--
} }
if expr is ast.ArrayInit || if expr is ast.ArrayInit ||
expr is ast.StructInit || expr is ast.MapInit || expr is ast.StructInit || expr is ast.MapInit || expr is ast.CallExpr {
expr is ast.CallExpr {
penalty-- penalty--
} }
} }
@ -1786,10 +1777,10 @@ pub fn (mut f Fmt) const_decl(it ast.ConstDecl) {
} }
fn (mut f Fmt) is_external_name(name string) bool { fn (mut f Fmt) is_external_name(name string) bool {
if name.len > 2 && name[0]==`C` && name[1]==`.` { if name.len > 2 && name[0] == `C` && name[1] == `.` {
return true return true
} }
if name.len > 3 && name[0]==`J` && name[1]==`S` && name[2] == `.` { if name.len > 3 && name[0] == `J` && name[1] == `S` && name[2] == `.` {
return true return true
} }
return false return false

View File

@ -48,7 +48,7 @@ const (
// for __offset_of // for __offset_of
#ifndef __offsetof #ifndef __offsetof
#define __offsetof(s,memb) \\ #define __offsetof(s,memb) \\
((size_t)((char *)&((s *)0)->memb - (char *)0)) ((size_t)((char *)&((s *)0)->memb - (char *)0))
#endif #endif
#define OPTION_CAST(x) (x) #define OPTION_CAST(x) (x)
@ -337,7 +337,7 @@ void _vcleanup();
else if (_likely_(i)) _wymix128(_wyr3(p,i)^_wyp0,_wyp1, &seed, &see1); else if (_likely_(i)) _wymix128(_wyr3(p,i)^_wyp0,_wyp1, &seed, &see1);
else _wymix128(_wyp0,_wyp1, &seed, &see1); else _wymix128(_wyp0,_wyp1, &seed, &see1);
} }
else _wymix128(_wyr8(p)^_wyp0,_wyr8(p+i-8)^_wyp1, &seed, &see1); else _wymix128(_wyr8(p)^_wyp0,_wyr8(p+i-8)^_wyp1, &seed, &see1);
#endif #endif
_wymix128(len,_wyp0, &seed, &see1); _wymix128(len,_wyp0, &seed, &see1);
return seed^see1; return seed^see1;

View File

@ -11,6 +11,8 @@ fn vararg_test() {
variadic(1, 2, 3) variadic(1, 2, 3)
} }
// TODO Remove `fn main` once vet supports scripts
fn main() {
vararg_test() vararg_test()
arr1 := ['Hello', 'JS', 'Backend'] arr1 := ['Hello', 'JS', 'Backend']
@ -118,3 +120,4 @@ $f1
$f2 $f2
$f3 $f3
$f4') $f4')
}

View File

@ -6,6 +6,8 @@ enum Test {
baz baz
} }
// TODO Remove `fn main` once vet supports scripts
fn main() {
mut a := hello.Ccc.a mut a := hello.Ccc.a
a = .b a = .b
a = .c a = .c
@ -15,3 +17,4 @@ println(a)
mut b := Test.foo mut b := Test.foo
b = .bar b = .bar
println(b) println(b)
}

View File

@ -2,132 +2,120 @@ import hello as hl
import hello.hello1 as hl1 import hello.hello1 as hl1
const ( const (
i_am_a_const = 21214 i_am_a_const = 21214
super = 'amazing keyword' super = 'amazing keyword'
) )
struct Foo { struct Foo {
mut: mut:
a hl.Aaa a hl.Aaa
} }
struct Companies { struct Companies {
google int google int
amazon bool amazon bool
yahoo string yahoo string
} }
enum POSITION { enum POSITION {
go_back go_back
dont_go_back dont_go_back
} }
fn class(extends string, instanceof int) { fn class(extends string, instanceof int) {
delete := instanceof delete := instanceof
_ = delete _ = delete
} }
fn main() { fn main() {
println('Hello from V.js!') println('Hello from V.js!')
println(JS.Math.atan2(1, 0)) println(JS.Math.atan2(1, 0))
mut a := 1
mut a := 1 a *= 2
a *= 2 a += 3
a += 3 println(a) // TODO: Handle string interpolation
println(a) // TODO: Handle string interpolation mut b := hl.Aaa{}
b.update('an update')
mut b := hl.Aaa{} println(b)
b.update('an update') mut c := Foo{hl.Aaa{}}
println(b) c.a.update('another update')
println(c)
mut c := Foo{ hl.Aaa{} } _ = 'done'
c.a.update('another update') {
println(c) _ = 'block'
}
_ = "done" _ = POSITION.go_back
{ _ = hl.Ccc.a
_ = "block" debugger := 'JS keywords'
} // TODO: Implement interpolation
await := '$super: $debugger'
_ = POSITION.go_back mut finally := 'implemented'
_ = hl.Ccc.a println('$await $finally')
dun := i_am_a_const * 20
debugger := 'JS keywords' dunn := hl.hello // External constant
// TODO: Implement interpolation _ = hl1.nested()
await := '$super: $debugger' for i := 0; i < 10; i++ {
mut finally := 'implemented' }
for i, x in 'hello' {
println('$await $finally') }
for x in 1 .. 10 {
dun := i_am_a_const * 20 }
dunn := hl.hello // External constant arr := [1, 2, 3, 4, 5]
_ = hl1.nested() for i in arr {
}
for i := 0; i < 10; i++ {} ma := {
'str': 'done'
for i, x in 'hello' {} 'ddo': 'baba'
}
for x in 1..10 {} // panic('foo')
for m, n in ma {
arr := [1,2,3,4,5] iss := m
for i in arr {} }
go async(0, 'hello')
ma := { fn_in_var := fn (number int) {
'str': "done" println('number: $number')
'ddo': "baba" }
} hl.debugger()
anon_consumer(hl.excited(), fn (message string) {
// panic('foo') println(message)
for m, n in ma { })
iss := m hl.raw_js_log()
}
go async(0, "hello")
fn_in_var := fn (number int) {
println("number: $number")
}
hl.debugger()
anon_consumer(hl.excited(), fn (message string) {
println(message)
})
hl.raw_js_log()
} }
fn anon_consumer (greeting string, anon fn(message string)) { fn anon_consumer(greeting string, anon fn (message string)) {
anon(greeting) anon(greeting)
} }
fn async(num int, def string) {} fn async(num int, def string) {
}
[inline] [inline]
[deprecated] [deprecated]
fn hello(game_on int, dummy ...string) (int, int) { fn hello(game_on int, dummy ...string) (int, int) {
defer { defer {
do := "not" do := 'not'
} }
for dd in dummy { for dd in dummy {
l := dd l := dd
} }
return game_on + 2, 221 return game_on + 2, 221
} }
fn (it Companies) method() int { fn (it Companies) method() int {
ss := Companies{
ss := Companies { google: 2
google: 2 amazon: true
amazon: true yahoo: 'hello'
yahoo: "hello"
} }
a, b := hello(2, 'google', 'not google')
a, b := hello(2, 'google', 'not google') glue := if a > 2 {
'more_glue'
glue := if a > 2 { 'more_glue' } else if a > 5 {'more glueee'} else { 'less glue' } } else if a > 5 {
'more glueee'
if a != 2 {} } else {
'less glue'
return 0 }
if a != 2 {
}
return 0
} }

View File

@ -5,7 +5,7 @@ const (w = 30 h = 30)
fn get(game [][]bool, x int, y int) bool { fn get(game [][]bool, x int, y int) bool {
if y < 0 || x < 0 { return false } if y < 0 || x < 0 { return false }
if y >= h || x >= w { return false } if y >= h || x >= w { return false }
return game[y][x] return game[y][x]
} }
@ -51,6 +51,8 @@ fn show(game [][]bool) {
} }
} }
// TODO Remove `fn main` once vet supports scripts
fn main() {
mut game := [][]bool{ len: h, init: []bool{ len: w } } mut game := [][]bool{ len: h, init: []bool{ len: w } }
game[11][15] = true game[11][15] = true
@ -62,3 +64,4 @@ game[12][21] = true
game[12][22] = true game[12][22] = true
JS.setInterval(fn () { show(game) game = step(game) }, 500) JS.setInterval(fn () { show(game) game = step(game) }, 500)
}

View File

@ -2,35 +2,39 @@ module main
struct Int { struct Int {
mut: mut:
value int value int
test map[string]int test map[string]int
hello []int hello []int
} }
fn (mut i Int) add(value int) { fn (mut i Int) add(value int) {
i.value += value i.value += value
} }
fn (i Int) get() int { fn (i Int) get() int {
return i.value return i.value
} }
struct Config { struct Config {
foo int foo int
bar string bar string
} }
fn use_config(c Config) {} fn use_config(c Config) {
}
fn main() { fn main() {
mut a := Int { value: 10 } mut a := Int{
a.add(5) value: 10
println(a) // 15 }
a.add(5)
mut b := Int{} println(a) // 15
b.add(10) mut b := Int{}
println(b.get()) // 10 b.add(10)
println(b.get()) // 10
use_config(Config{ 2, 'bar' }) use_config(Config{2, 'bar'})
use_config(foo: 2, bar: 'bar') use_config({
foo: 2
bar: 'bar'
})
} }

View File

@ -23,7 +23,7 @@ fn (mut g Gen) gen_json_for_type(typ table.Type) {
mut enc := strings.new_builder(100) mut enc := strings.new_builder(100)
sym := g.table.get_type_symbol(typ) sym := g.table.get_type_symbol(typ)
styp := g.typ(typ) styp := g.typ(typ)
if is_js_prim(sym.name) || sym.kind == .enum_{ if is_js_prim(sym.name) || sym.kind == .enum_ {
return return
} }
if sym.kind == .array { if sym.kind == .array {
@ -38,26 +38,24 @@ fn (mut g Gen) gen_json_for_type(typ table.Type) {
// cJSON_Parse(str) call is added by the compiler // cJSON_Parse(str) call is added by the compiler
// Code gen decoder // Code gen decoder
dec_fn_name := js_dec_name(sym.name) dec_fn_name := js_dec_name(sym.name)
// Make sure that this optional type actually exists // Make sure that this optional type actually exists
g.register_optional(typ) g.register_optional(typ)
dec_fn_dec := 'Option_$styp ${dec_fn_name}(cJSON* root)' dec_fn_dec := 'Option_$styp ${dec_fn_name}(cJSON* root)'
dec.writeln(' dec.writeln('
//Option_$styp ${dec_fn_name}(cJSON* root, $styp* res) { //Option_$styp ${dec_fn_name}(cJSON* root, $styp* res) {
$dec_fn_dec { $dec_fn_dec {
$styp res; $styp res;
if (!root) { if (!root) {
const char *error_ptr = cJSON_GetErrorPtr(); const char *error_ptr = cJSON_GetErrorPtr();
if (error_ptr != NULL) { if (error_ptr != NULL) {
// fprintf(stderr, "Error in decode() for $styp error_ptr=: %%s\\n", error_ptr); // fprintf(stderr, "Error in decode() for $styp error_ptr=: %%s\\n", error_ptr);
// printf("\\nbad js=%%s\\n", js.str); // printf("\\nbad js=%%s\\n", js.str);
Option err = v_error(tos2(error_ptr)); Option err = v_error(tos2(error_ptr));
return *(Option_$styp *)&err; return *(Option_$styp *)&err;
} }
} }
') ')
g.json_forward_decls.writeln('$dec_fn_dec;') g.json_forward_decls.writeln('$dec_fn_dec;')
// Code gen encoder // Code gen encoder
// encode_TYPE funcs receive an object to encode // encode_TYPE funcs receive an object to encode
enc_fn_name := js_enc_name(sym.name) enc_fn_name := js_enc_name(sym.name)
@ -107,11 +105,9 @@ $enc_fn_dec {
dec.writeln(' res . ${c_name(field.name)} = *($field_type*) $dec_name (js_get(root,"$name")).data;') dec.writeln(' res . ${c_name(field.name)} = *($field_type*) $dec_name (js_get(root,"$name")).data;')
} }
} }
mut enc_name := js_enc_name(field_type) mut enc_name := js_enc_name(field_type)
if g.table.get_type_symbol(field.typ).kind == .enum_ { if g.table.get_type_symbol(field.typ).kind == .enum_ {
enc.writeln('\tcJSON_AddItemToObject(o, "$name", json__encode_u64(val.${c_name(field.name)}));') enc.writeln('\tcJSON_AddItemToObject(o, "$name", json__encode_u64(val.${c_name(field.name)}));')
} else { } else {
enc.writeln('\tcJSON_AddItemToObject(o, "$name", ${enc_name}(val.${c_name(field.name)}));') enc.writeln('\tcJSON_AddItemToObject(o, "$name", ${enc_name}(val.${c_name(field.name)}));')
} }
@ -160,7 +156,7 @@ const cJSON *jsval = NULL;
cJSON_ArrayForEach(jsval, root) cJSON_ArrayForEach(jsval, root)
{ {
$s $s
array_push(&res, &val); array_push(&res, &val);
} }
' '
} }
@ -171,7 +167,7 @@ fn (mut g Gen) encode_array(value_type table.Type) string {
return ' return '
o = cJSON_CreateArray(); o = cJSON_CreateArray();
for (int i = 0; i < val.len; i++){ for (int i = 0; i < val.len; i++){
cJSON_AddItemToArray(o, $fn_name ( (($styp*)val.data)[i] )); cJSON_AddItemToArray(o, $fn_name ( (($styp*)val.data)[i] ));
} }
' '
} }

View File

@ -40,12 +40,13 @@ fn (mut g Gen) generate_hotcode_reloader_code() {
mut load_code := []string{} mut load_code := []string{}
if g.pref.os != .windows { if g.pref.os != .windows {
for so_fn in g.hotcode_fn_names { for so_fn in g.hotcode_fn_names {
load_code << 'impl_live_${so_fn} = dlsym(live_lib, "impl_live_${so_fn}");' load_code << 'impl_live_$so_fn = dlsym(live_lib, "impl_live_$so_fn");'
} }
phd = posix_hotcode_definitions_1 phd = posix_hotcode_definitions_1
} else { } else {
for so_fn in g.hotcode_fn_names { for so_fn in g.hotcode_fn_names {
load_code << 'impl_live_${so_fn} = (void *)GetProcAddress(live_lib, "impl_live_${so_fn}"); ' load_code <<
'impl_live_$so_fn = (void *)GetProcAddress(live_lib, "impl_live_$so_fn"); '
} }
phd = windows_hotcode_definitions_1 phd = windows_hotcode_definitions_1
} }
@ -54,14 +55,14 @@ fn (mut g Gen) generate_hotcode_reloader_code() {
} }
const ( const (
posix_hotcode_definitions_1 = ' posix_hotcode_definitions_1 = '
void v_bind_live_symbols(void* live_lib){ void v_bind_live_symbols(void* live_lib){
@LOAD_FNS@ @LOAD_FNS@
} }
' '
windows_hotcode_definitions_1 = ' windows_hotcode_definitions_1 = '
void v_bind_live_symbols(void* live_lib){ void v_bind_live_symbols(void* live_lib){
@LOAD_FNS@ @LOAD_FNS@
} }
' '
) )
@ -76,10 +77,10 @@ fn (mut g Gen) generate_hotcode_reloading_main_caller() {
g.writeln('\t{') g.writeln('\t{')
g.writeln('\t\t// initialization of live function pointers') g.writeln('\t\t// initialization of live function pointers')
for fname in g.hotcode_fn_names { for fname in g.hotcode_fn_names {
g.writeln('\t\timpl_live_${fname} = 0;') g.writeln('\t\timpl_live_$fname = 0;')
} }
vexe := util.cescaped_path( pref.vexe_path() ) vexe := util.cescaped_path(pref.vexe_path())
file := util.cescaped_path( g.pref.path ) file := util.cescaped_path(g.pref.path)
msvc := if g.pref.ccompiler == 'msvc' { '-cc msvc' } else { '' } msvc := if g.pref.ccompiler == 'msvc' { '-cc msvc' } else { '' }
so_debug_flag := if g.pref.is_debug { '-cg' } else { '' } so_debug_flag := if g.pref.is_debug { '-cg' } else { '' }
vopts := '$msvc $so_debug_flag -sharedlive -shared' vopts := '$msvc $so_debug_flag -sharedlive -shared'

View File

@ -4,6 +4,8 @@ import v.ast
import v.table import v.table
fn (mut p Parser) lock_expr() ast.LockExpr { fn (mut p Parser) lock_expr() ast.LockExpr {
// TODO Handle aliasing sync
p.register_used_import('sync')
pos := p.tok.position() pos := p.tok.position()
is_rlock := p.tok.kind == .key_rlock is_rlock := p.tok.kind == .key_rlock
p.next() p.next()

View File

@ -30,15 +30,16 @@ fn (mut p Parser) register_used_import(alias string) {
} }
fn (mut p Parser) check_unused_imports() { fn (mut p Parser) check_unused_imports() {
if p.pref.is_repl { if p.pref.is_repl || p.pref.is_fmt {
// The REPL should be much more liberal, and should not warn about // The REPL should be much more liberal, and should not warn about
// unused imports, because they probably will be in the next few lines... // unused imports, because they probably will be in the next few lines...
// vfmt doesn't care about unused imports either
return return
} }
for import_m in p.ast_imports { for import_m in p.ast_imports {
alias := import_m.alias alias := import_m.alias
mod := import_m.mod mod := import_m.mod
if !p.is_used_import(alias) && !p.pref.is_fmt { if !p.is_used_import(alias) {
mod_alias := if alias == mod { alias } else { '$alias ($mod)' } mod_alias := if alias == mod { alias } else { '$alias ($mod)' }
p.warn_with_pos("module '$mod_alias' is imported but never used", import_m.pos) p.warn_with_pos("module '$mod_alias' is imported but never used", import_m.pos)
} }

View File

@ -15,8 +15,8 @@ import strings
pub type Type int pub type Type int
pub type TypeInfo = Alias | Array | ArrayFixed | Enum | FnType | Interface | Map | MultiReturn | pub type TypeInfo = Alias | Array | ArrayFixed | Enum | FnType | GenericStructInst | Interface |
Struct | GenericStructInst | SumType Map | MultiReturn | Struct | SumType
pub enum Language { pub enum Language {
v v
@ -46,10 +46,9 @@ pub enum TypeFlag {
} }
/* /*
To save precious TypeFlag bits the 4 possible ShareTypes are coded in the two To save precious TypeFlag bits the 4 possible ShareTypes are coded in the two
bits `shared` and `atomic_or_rw` (see sharetype_from_flags() below). bits `shared` and `atomic_or_rw` (see sharetype_from_flags() below).
*/ */
pub enum ShareType { pub enum ShareType {
mut_t mut_t
shared_t shared_t
@ -127,7 +126,6 @@ pub fn (t Type) to_ptr() Type {
if nr_muls == 255 { if nr_muls == 255 {
panic('to_ptr: nr_muls is already at max of 255') panic('to_ptr: nr_muls is already at max of 255')
} }
return int(t) & 0xff00ffff | ((nr_muls + 1) << 16) return int(t) & 0xff00ffff | ((nr_muls + 1) << 16)
} }
@ -144,13 +142,13 @@ pub fn (t Type) deref() Type {
// set `flag` on `t` and return `t` // set `flag` on `t` and return `t`
[inline] [inline]
pub fn (t Type) set_flag(flag TypeFlag) Type { pub fn (t Type) set_flag(flag TypeFlag) Type {
return int(t) | (1 << (int(flag) + 24)) return int(t) | (1 << (int(flag) + 24))
} }
// clear `flag` on `t` and return `t` // clear `flag` on `t` and return `t`
[inline] [inline]
pub fn (t Type) clear_flag(flag TypeFlag) Type { pub fn (t Type) clear_flag(flag TypeFlag) Type {
return int(t) & ~(1 << (int(flag) + 24)) return int(t) & ~(1 << (int(flag) + 24))
} }
// clear all flags // clear all flags
@ -162,7 +160,7 @@ pub fn (t Type) clear_flags() Type {
// return true if `flag` is set on `t` // return true if `flag` is set on `t`
[inline] [inline]
pub fn (t Type) has_flag(flag TypeFlag) bool { pub fn (t Type) has_flag(flag TypeFlag) bool {
return int(t) & (1 << (int(flag) + 24)) > 0 return int(t) & (1 << (int(flag) + 24)) > 0
} }
// copy flags & nr_muls from `t_from` to `t` and return `t` // copy flags & nr_muls from `t_from` to `t` and return `t`
@ -263,24 +261,12 @@ pub const (
pub const ( pub const (
integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx, integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx,
u16_type_idx, u16_type_idx, u32_type_idx, u64_type_idx, any_int_type_idx]
u32_type_idx,
u64_type_idx,
any_int_type_idx
]
signed_integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx] signed_integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx]
unsigned_integer_type_idxs = [byte_type_idx, u16_type_idx, u32_type_idx, u64_type_idx] unsigned_integer_type_idxs = [byte_type_idx, u16_type_idx, u32_type_idx, u64_type_idx]
float_type_idxs = [f32_type_idx, f64_type_idx, any_flt_type_idx] float_type_idxs = [f32_type_idx, f64_type_idx, any_flt_type_idx]
number_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, number_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx,
i64_type_idx, byte_type_idx, u16_type_idx, u32_type_idx, u64_type_idx, f32_type_idx, f64_type_idx, any_int_type_idx, any_flt_type_idx]
u16_type_idx,
u32_type_idx,
u64_type_idx,
f32_type_idx,
f64_type_idx,
any_int_type_idx,
any_flt_type_idx
]
pointer_type_idxs = [voidptr_type_idx, byteptr_type_idx, charptr_type_idx] pointer_type_idxs = [voidptr_type_idx, byteptr_type_idx, charptr_type_idx]
string_type_idxs = [string_type_idx, ustring_type_idx] string_type_idxs = [string_type_idx, ustring_type_idx]
) )
@ -314,13 +300,9 @@ pub const (
) )
pub const ( pub const (
builtin_type_names = ['void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64', builtin_type_names = ['void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64', 'u16',
'u16', 'u32', 'u64', 'any_int', 'f32', 'f64', 'any_float', 'string', 'ustring', 'char', 'byte', 'bool',
'u32', 'none', 'array', 'array_fixed', 'map', 'any', 'struct', 'mapnode', 'size_t']
'u64', 'any_int', 'f32', 'f64', 'any_float', 'string', 'ustring', 'char', 'byte',
'bool', 'none', 'array', 'array_fixed',
'map', 'any', 'struct',
'mapnode', 'size_t']
) )
pub struct MultiReturn { pub struct MultiReturn {
@ -548,10 +530,10 @@ pub fn (mut t Table) register_builtin_type_symbols() {
mod: 'builtin' mod: 'builtin'
}) })
// t.register_type_symbol({ // t.register_type_symbol({
// kind: .any // kind: .any
// name: 'T' // name: 'T'
// mod: 'builtin' // mod: 'builtin'
// is_public: true // is_public: true
// }) // })
t.register_type_symbol({ t.register_type_symbol({
kind: .any_float kind: .any_float
@ -681,15 +663,15 @@ pub mut:
pub struct Enum { pub struct Enum {
pub: pub:
vals []string vals []string
is_flag bool is_flag bool
is_multi_allowed bool is_multi_allowed bool
} }
pub struct Alias { pub struct Alias {
pub: pub:
parent_type Type parent_type Type
language Language language Language
} }
// NB: FExpr here is a actually an ast.Expr . // NB: FExpr here is a actually an ast.Expr .

View File

@ -1,102 +1,81 @@
import table import table
fn test_idx() { fn test_idx() {
mut t := table.new_type(table.void_type_idx) mut t := table.new_type(table.void_type_idx)
assert t.idx() == table.void_type_idx assert t.idx() == table.void_type_idx
t = table.new_type(table.i8_type_idx)
t = table.new_type(table.i8_type_idx)
assert t.idx() == table.i8_type_idx assert t.idx() == table.i8_type_idx
} }
fn test_muls() { fn test_muls() {
mut t := table.new_type(table.void_type_idx) mut t := table.new_type(table.void_type_idx)
idx := t.idx()
idx := t.idx()
assert t.nr_muls() == 0 assert t.nr_muls() == 0
for i in 0 .. 32 {
for i in 0..32 {
t = t.set_nr_muls(i) t = t.set_nr_muls(i)
assert t.nr_muls() == i assert t.nr_muls() == i
} }
t = t.set_nr_muls(0) t = t.set_nr_muls(0)
assert t.nr_muls() == 0 assert t.nr_muls() == 0
assert t.is_ptr() == false assert t.is_ptr() == false
t = t.to_ptr() t = t.to_ptr()
assert t.nr_muls() == 1 assert t.nr_muls() == 1
assert t.is_ptr() == true assert t.is_ptr() == true
t = t.to_ptr() t = t.to_ptr()
assert t.nr_muls() == 2 assert t.nr_muls() == 2
assert t.is_ptr() == true assert t.is_ptr() == true
t = t.deref() t = t.deref()
assert t.nr_muls() == 1 assert t.nr_muls() == 1
assert t.is_ptr() == true assert t.is_ptr() == true
t = t.deref() t = t.deref()
assert t.nr_muls() == 0 assert t.nr_muls() == 0
assert t.is_ptr() == false assert t.is_ptr() == false
assert t.idx() == idx assert t.idx() == idx
} }
fn test_flags() { fn test_flags() {
mut t := table.new_type(table.void_type_idx) mut t := table.new_type(table.void_type_idx)
idx := t.idx()
idx := t.idx() nr_muls := t.nr_muls()
nr_muls := t.nr_muls() t = t.set_flag(table.TypeFlag.optional)
assert t.has_flag(table.TypeFlag.optional) == true
t = t.set_flag(table.TypeFlag.optional) assert t.has_flag(table.TypeFlag.variadic) == false
assert t.has_flag(table.TypeFlag.optional) == true assert t.has_flag(table.TypeFlag.generic) == false
assert t.has_flag(table.TypeFlag.variadic) == false t = t.set_flag(table.TypeFlag.variadic)
assert t.has_flag(table.TypeFlag.generic) == false assert t.has_flag(table.TypeFlag.optional) == true
assert t.has_flag(table.TypeFlag.variadic) == true
t = t.set_flag(table.TypeFlag.variadic) assert t.has_flag(table.TypeFlag.generic) == false
assert t.has_flag(table.TypeFlag.optional) == true t = t.set_flag(table.TypeFlag.generic)
assert t.has_flag(table.TypeFlag.variadic) == true assert t.has_flag(table.TypeFlag.optional) == true
assert t.has_flag(table.TypeFlag.generic) == false assert t.has_flag(table.TypeFlag.variadic) == true
assert t.has_flag(table.TypeFlag.generic) == true
t = t.set_flag(table.TypeFlag.generic) assert t.idx() == idx
assert t.has_flag(table.TypeFlag.optional) == true assert t.nr_muls() == nr_muls
assert t.has_flag(table.TypeFlag.variadic) == true t = t.clear_flag(table.TypeFlag.optional)
assert t.has_flag(table.TypeFlag.generic) == true assert t.has_flag(table.TypeFlag.optional) == false
assert t.has_flag(table.TypeFlag.variadic) == true
assert t.idx() == idx assert t.has_flag(table.TypeFlag.generic) == true
assert t.nr_muls() == nr_muls t = t.clear_flag(table.TypeFlag.variadic)
assert t.has_flag(table.TypeFlag.optional) == false
t = t.clear_flag(table.TypeFlag.optional) assert t.has_flag(table.TypeFlag.variadic) == false
assert t.has_flag(table.TypeFlag.optional) == false assert t.has_flag(table.TypeFlag.generic) == true
assert t.has_flag(table.TypeFlag.variadic) == true t = t.clear_flag(table.TypeFlag.generic)
assert t.has_flag(table.TypeFlag.generic) == true assert t.has_flag(table.TypeFlag.optional) == false
assert t.has_flag(table.TypeFlag.variadic) == false
t = t.clear_flag(table.TypeFlag.variadic) assert t.has_flag(table.TypeFlag.generic) == false
assert t.has_flag(table.TypeFlag.optional) == false assert t.idx() == idx
assert t.has_flag(table.TypeFlag.variadic) == false assert t.nr_muls() == nr_muls
assert t.has_flag(table.TypeFlag.generic) == true
t = t.clear_flag(table.TypeFlag.generic)
assert t.has_flag(table.TypeFlag.optional) == false
assert t.has_flag(table.TypeFlag.variadic) == false
assert t.has_flag(table.TypeFlag.generic) == false
assert t.idx() == idx
assert t.nr_muls() == nr_muls
} }
fn test_derive() { fn test_derive() {
mut t := table.new_type(table.i8_type_idx) mut t := table.new_type(table.i8_type_idx)
t = t.set_flag(table.TypeFlag.generic) t = t.set_flag(table.TypeFlag.generic)
t = t.set_flag(table.TypeFlag.variadic) t = t.set_flag(table.TypeFlag.variadic)
t = t.set_nr_muls(10) t = t.set_nr_muls(10)
mut t2 := table.new_type(table.i16_type_idx)
mut t2 := table.new_type(table.i16_type_idx)
t2 = t2.derive(t) t2 = t2.derive(t)
assert t2.has_flag(table.TypeFlag.optional) == false assert t2.has_flag(table.TypeFlag.optional) == false
assert t2.has_flag(table.TypeFlag.variadic) == true assert t2.has_flag(table.TypeFlag.variadic) == true
assert t2.has_flag(table.TypeFlag.generic) == true assert t2.has_flag(table.TypeFlag.generic) == true
assert t2.nr_muls() == 10 assert t2.nr_muls() == 10
} }

View File

@ -19,7 +19,7 @@ fn test_parse_valid_cflags() {
make_flag('darwin', '-framework', 'Cocoa'), make_flag('darwin', '-framework', 'Cocoa'),
make_flag('windows', '-l', 'gdi32'), make_flag('windows', '-l', 'gdi32'),
make_flag(no_os, '-l', 'mysqlclient'), make_flag(no_os, '-l', 'mysqlclient'),
make_flag(no_os, no_name, '-test') make_flag(no_os, no_name, '-test'),
] ]
parse_valid_flag(mut t, '-lmysqlclient') parse_valid_flag(mut t, '-lmysqlclient')
parse_valid_flag(mut t, '-test') parse_valid_flag(mut t, '-test')
@ -54,8 +54,7 @@ fn test_parse_invalid_cflags() {
} }
fn parse_valid_flag(mut t table.Table, flag string) { fn parse_valid_flag(mut t table.Table, flag string) {
t.parse_cflag(flag, module_name, cdefines) or { t.parse_cflag(flag, module_name, cdefines) or { }
}
} }
fn assert_parse_invalid_flag(mut t table.Table, flag string) { fn assert_parse_invalid_flag(mut t table.Table, flag string) {

View File

@ -112,12 +112,12 @@ pub fn (t &Table) known_fn(name string) bool {
} }
pub fn (mut t Table) register_fn(new_fn Fn) { pub fn (mut t Table) register_fn(new_fn Fn) {
// println('reg fn $new_fn.name nr_args=$new_fn.args.len') // println('reg fn $new_fn.name nr_args=$new_fn.args.len')
t.fns[new_fn.name] = new_fn t.fns[new_fn.name] = new_fn
} }
pub fn (mut t TypeSymbol) register_method(new_fn Fn) { pub fn (mut t TypeSymbol) register_method(new_fn Fn) {
// println('reg me $new_fn.name nr_args=$new_fn.args.len') // println('reg me $new_fn.name nr_args=$new_fn.args.len')
t.methods << new_fn t.methods << new_fn
} }
@ -194,7 +194,7 @@ pub fn (t &Table) get_type_symbol(typ Type) &TypeSymbol {
return &t.types[idx] return &t.types[idx]
} }
// this should never happen // this should never happen
panic('get_type_symbol: invalid type (typ=$typ idx=${idx}). Compiler bug. This should never happen') panic('get_type_symbol: invalid type (typ=$typ idx=$idx). Compiler bug. This should never happen')
} }
// get_final_type_symbol follows aliases until it gets to a "real" Type // get_final_type_symbol follows aliases until it gets to a "real" Type
@ -210,7 +210,7 @@ pub fn (t &Table) get_final_type_symbol(typ Type) &TypeSymbol {
return &t.types[idx] return &t.types[idx]
} }
// this should never happen // this should never happen
panic('get_final_type_symbol: invalid type (typ=$typ idx=${idx}). Compiler bug. This should never happen') panic('get_final_type_symbol: invalid type (typ=$typ idx=$idx). Compiler bug. This should never happen')
} }
[inline] [inline]
@ -245,8 +245,7 @@ pub fn (mut t Table) register_builtin_type_symbol(typ TypeSymbol) int {
typ | typ |
kind: existing_type.kind kind: existing_type.kind
} }
} } else {
else {
t.types[existing_idx] = typ t.types[existing_idx] = typ
} }
} }
@ -296,7 +295,7 @@ pub fn (t &Table) known_type(name string) bool {
[inline] [inline]
pub fn (t &Table) array_name(elem_type Type, nr_dims int) string { pub fn (t &Table) array_name(elem_type Type, nr_dims int) string {
elem_type_sym := t.get_type_symbol(elem_type) elem_type_sym := t.get_type_symbol(elem_type)
return 'array_${elem_type_sym.name}' + if elem_type.is_ptr() { return 'array_$elem_type_sym.name' + if elem_type.is_ptr() {
'_ptr'.repeat(elem_type.nr_muls()) '_ptr'.repeat(elem_type.nr_muls())
} else { } else {
'' ''
@ -310,7 +309,7 @@ pub fn (t &Table) array_name(elem_type Type, nr_dims int) string {
[inline] [inline]
pub fn (t &Table) array_fixed_name(elem_type Type, size, nr_dims int) string { pub fn (t &Table) array_fixed_name(elem_type Type, size, nr_dims int) string {
elem_type_sym := t.get_type_symbol(elem_type) elem_type_sym := t.get_type_symbol(elem_type)
return 'array_fixed_${elem_type_sym.name}_${size}' + if elem_type.is_ptr() { return 'array_fixed_${elem_type_sym.name}_$size' + if elem_type.is_ptr() {
'_ptr' '_ptr'
} else { } else {
'' ''
@ -326,7 +325,7 @@ pub fn (t &Table) map_name(key_type, value_type Type) string {
key_type_sym := t.get_type_symbol(key_type) key_type_sym := t.get_type_symbol(key_type)
value_type_sym := t.get_type_symbol(value_type) value_type_sym := t.get_type_symbol(value_type)
suffix := if value_type.is_ptr() { '_ptr' } else { '' } suffix := if value_type.is_ptr() { '_ptr' } else { '' }
return 'map_${key_type_sym.name}_${value_type_sym.name}' + suffix return 'map_${key_type_sym.name}_$value_type_sym.name' + suffix
// return 'map_${value_type_sym.name}' + suffix // return 'map_${value_type_sym.name}' + suffix
} }
@ -489,7 +488,7 @@ pub fn (t &Table) mktyp(typ Type) Type {
// this is not optimal // this is not optimal
pub fn (table &Table) qualify_module(mod, file_path string) string { pub fn (table &Table) qualify_module(mod, file_path string) string {
for m in table.imports { for m in table.imports {
//if m.contains('gen') { println('qm=$m') } // if m.contains('gen') { println('qm=$m') }
if m.contains('.') && m.contains(mod) { if m.contains('.') && m.contains(mod) {
m_parts := m.split('.') m_parts := m.split('.')
m_path := m_parts.join(os.path_separator) m_path := m_parts.join(os.path_separator)
@ -512,12 +511,11 @@ pub fn (mut table Table) register_fn_gen_type(fn_name string, typ Type) {
table.fn_gen_types[fn_name] = a table.fn_gen_types[fn_name] = a
} }
// TODO: there is a bug when casting sumtype the other way if its pointer // TODO: there is a bug when casting sumtype the other way if its pointer
// so until fixed at least show v (not C) error `x(variant) = y(SumType*)` // so until fixed at least show v (not C) error `x(variant) = y(SumType*)`
pub fn (table &Table) sumtype_has_variant(parent Type, variant Type) bool { pub fn (table &Table) sumtype_has_variant(parent, variant Type) bool {
parent_sym := table.get_type_symbol(parent) parent_sym := table.get_type_symbol(parent)
if parent_sym.kind ==.sum_type { if parent_sym.kind == .sum_type {
parent_info := parent_sym.info as SumType parent_info := parent_sym.info as SumType
for v in parent_info.variants { for v in parent_info.variants {
if v.idx() == variant.idx() { if v.idx() == variant.idx() {
@ -529,4 +527,5 @@ pub fn (table &Table) sumtype_has_variant(parent Type, variant Type) bool {
} }
} }
return false return false
} }

View File

@ -26,7 +26,7 @@ fn test_autolocked_array() {
rlock abc { rlock abc {
finished_threads = unsafe { finished_threads = unsafe {
abc[0] abc[0]
} }
} }
if finished_threads == 2 { if finished_threads == 2 {
break break

View File

@ -1,10 +1,10 @@
import rand import rand
const ( const (
my_random_letter_const = byte(65 + rand.u32n(25)) my_random_letter_const = byte(65 + rand.u32n(25))
) )
fn test_rand_is_initialized_before_main(){ fn test_rand_is_initialized_before_main() {
eprintln('random letter: $my_random_letter_const.str() | ASCII code: $my_random_letter_const') eprintln('random letter: $my_random_letter_const.str() | ASCII code: $my_random_letter_const')
assert my_random_letter_const.is_capital() assert my_random_letter_const.is_capital()
} }

View File

@ -1,20 +1,20 @@
struct Abc { struct Abc {
mut: mut:
flags []Flag flags []Flag
} }
enum Flag { enum Flag {
flag_one flag_one
flag_two flag_two
} }
fn test_enum_array_field() { fn test_enum_array_field() {
mut a := Abc{} mut a := Abc{}
a.flags << .flag_one a.flags << .flag_one
assert true assert true
a.flags << .flag_two a.flags << .flag_two
assert true assert true
a.flags << .flag_one a.flags << .flag_one
println(a) println(a)
assert true assert true
} }

View File

@ -68,7 +68,6 @@ fn mut_arg<T>(mut x T) {
println(x.name) // = 'foo' println(x.name) // = 'foo'
} }
fn mut_arg2<T>(mut x T) T { fn mut_arg2<T>(mut x T) T {
println(x.name) // = 'foo' println(x.name) // = 'foo'
return x return x
@ -99,99 +98,98 @@ fn test_return_array() {
/* /*
fn map_f<T,U>(l []T, f fn(T)U) []U { fn map_f<T,U>(l []T, f fn(T)U) []U {
mut r := []U{} mut r := []U{}
for e in l { for e in l {
r << f(e) r << f(e)
} }
return r return r
} }
fn foldl<T>(l []T, nil T, f fn(T,T)T) T { fn foldl<T>(l []T, nil T, f fn(T,T)T) T {
mut r := nil mut r := nil
for e in l { for e in l {
r = f(r, e) r = f(r, e)
} }
return r return r
} }
fn square(x int) int { fn square(x int) int {
return x*x return x*x
} }
fn mul_int(x int, y int) int { fn mul_int(x int, y int) int {
return x*y return x*y
} }
fn assert_eq<T>(a, b T) { fn assert_eq<T>(a, b T) {
r := a == b r := a == b
println('$a == $b: ${r.str()}') println('$a == $b: ${r.str()}')
assert r assert r
} }
fn print_nice<T>(x T, indent int) { fn print_nice<T>(x T, indent int) {
mut space := '' mut space := ''
for _ in 0..indent { for _ in 0..indent {
space = space + ' ' space = space + ' '
} }
println('$space$x') println('$space$x')
} }
fn test_generic_fn() { fn test_generic_fn() {
assert_eq(simple(0+1), 1) assert_eq(simple(0+1), 1)
assert_eq(simple('g') + 'h', 'gh') assert_eq(simple('g') + 'h', 'gh')
assert_eq(sum([5.1,6.2,7.0]), 18.3) assert_eq(sum([5.1,6.2,7.0]), 18.3)
assert_eq(plus(i64(4), i64(6)), i64(10)) assert_eq(plus(i64(4), i64(6)), i64(10))
a := [1,2,3,4] a := [1,2,3,4]
b := map_f(a, square) b := map_f(a, square)
assert_eq(sum(b), 30) // 1+4+9+16 = 30 assert_eq(sum(b), 30) // 1+4+9+16 = 30
assert_eq(foldl(b, 1, mul_int), 576) // 1*4*9*16 = 576 assert_eq(foldl(b, 1, mul_int), 576) // 1*4*9*16 = 576
print_nice('str', 8) print_nice('str', 8)
} }
struct Point { struct Point {
mut: mut:
x f64 x f64
y f64 y f64
} }
fn (mut p Point) translate<T>(x, y T) { fn (mut p Point) translate<T>(x, y T) {
p.x += x p.x += x
p.y += y p.y += y
} }
fn test_generic_method() { fn test_generic_method() {
mut p := Point{} mut p := Point{}
p.translate(2, 1.0) p.translate(2, 1.0)
assert p.x == 2.0 && p.y == 1.0 assert p.x == 2.0 && p.y == 1.0
} }
fn get_values<T>(i T) []T { fn get_values<T>(i T) []T {
return [i] return [i]
} }
fn test_generic_fn_in_for_in_expression() { fn test_generic_fn_in_for_in_expression() {
for value in get_values(1) { for value in get_values(1) {
assert value == 1 assert value == 1
} }
for i, val in get_values(0) { for i, val in get_values(0) {
assert i == val assert i == val
} }
for value in get_values('a') { for value in get_values('a') {
assert value == 'a' assert value == 'a'
} }
} }
*/ */
// test generic struct // test generic struct
struct DB { struct DB {
driver string driver string
} }
struct Group { struct Group {
pub mut: pub mut:
name string name string
group_name string group_name string
} }
@ -200,41 +198,40 @@ pub mut:
name string name string
} }
struct Repo<T,U> { struct Repo<T, U> {
db DB db DB
pub mut: pub mut:
model T model T
permission U permission U
} }
// TODO: multiple type generic struct needs fixing in return for fn // TODO: multiple type generic struct needs fixing in return for fn
// fn new_repo<T>(db DB) Repo<T,U> { // fn new_repo<T>(db DB) Repo<T,U> {
// return Repo<T,Permission>{db: db} // return Repo<T,Permission>{db: db}
// } // }
fn test_generic_struct() { fn test_generic_struct() {
mut a := Repo<User,Permission>{ mut a := Repo<User, Permission>{
model: User{name: 'joe'} model: User{
name: 'joe'
}
} }
// a.model.name = 'joe' // a.model.name = 'joe'
assert a.model.name == 'joe' assert a.model.name == 'joe'
println('a.model.name: $a.model.name') println('a.model.name: $a.model.name')
mut b := Repo<Group, Permission>{
mut b := Repo<Group,Permission>{ permission: Permission{
permission: Permission{name: 'superuser'} name: 'superuser'
}
} }
b.model.name = 'admins' b.model.name = 'admins'
assert b.model.name == 'admins' assert b.model.name == 'admins'
assert b.permission.name == 'superuser' assert b.permission.name == 'superuser'
println('b.model.name: $b.model.name') println('b.model.name: $b.model.name')
println('b.permission.name: $b.permission.name') println('b.permission.name: $b.permission.name')
assert typeof(a.model) == 'User' assert typeof(a.model) == 'User'
assert typeof(b.model) == 'Group' assert typeof(b.model) == 'Group'
println('typeof(a.model): ' + typeof(a.model)) println('typeof(a.model): ' + typeof(a.model))
println('typeof(b.model): ' + typeof(b.model)) println('typeof(b.model): ' + typeof(b.model))
// mut x := new_repo<User>(DB{}) // mut x := new_repo<User>(DB{})
// x.model.name = 'joe2' // x.model.name = 'joe2'
// println(x.model.name) // println(x.model.name)

View File

@ -217,5 +217,5 @@ fn test_optimized_in_expression_with_string() {
fn test_in_array_init() { fn test_in_array_init() {
assert 1 !in []int{} assert 1 !in []int{}
assert [1] in [[1]] assert [1] in [[1], [2]]
} }

View File

@ -6,7 +6,9 @@ fn test_all() {
mut total_errors := 0 mut total_errors := 0
vexe := os.getenv('VEXE') vexe := os.getenv('VEXE')
vroot := os.dir(vexe) vroot := os.dir(vexe)
diff_cmd := util.find_working_diff_command() or { '' } diff_cmd := util.find_working_diff_command() or {
''
}
dir := 'vlib/v/tests/inout' dir := 'vlib/v/tests/inout'
files := os.ls(dir) or { files := os.ls(dir) or {
panic(err) panic(err)
@ -70,8 +72,8 @@ fn test_all() {
expected = expected.trim_right('\r\n').replace('\r\n', '\n') expected = expected.trim_right('\r\n').replace('\r\n', '\n')
if expected.contains('================ V panic ================') { if expected.contains('================ V panic ================') {
// panic include backtraces and absolute file paths, so can't do char by char comparison // panic include backtraces and absolute file paths, so can't do char by char comparison
n_found := normalize_panic_message( found, vroot ) n_found := normalize_panic_message(found, vroot)
n_expected := normalize_panic_message( expected, vroot ) n_expected := normalize_panic_message(expected, vroot)
if found.contains('================ V panic ================') { if found.contains('================ V panic ================') {
if n_found.contains(n_expected) { if n_found.contains(n_expected) {
println(term.green('OK (panic)')) println(term.green('OK (panic)'))
@ -87,12 +89,12 @@ fn test_all() {
} }
if expected != found { if expected != found {
println(term.red('FAIL')) println(term.red('FAIL'))
println(term.header('expected:','-')) println(term.header('expected:', '-'))
println(expected) println(expected)
println(term.header('found:','-')) println(term.header('found:', '-'))
println(found) println(found)
if diff_cmd != '' { if diff_cmd != '' {
println(term.header('difference:','-')) println(term.header('difference:', '-'))
println(util.color_compare_strings(diff_cmd, expected, found)) println(util.color_compare_strings(diff_cmd, expected, found))
} else { } else {
println(term.h_divider('-')) println(term.h_divider('-'))
@ -105,7 +107,7 @@ fn test_all() {
assert total_errors == 0 assert total_errors == 0
} }
fn normalize_panic_message(message string, vroot string) string { fn normalize_panic_message(message, vroot string) string {
mut msg := message.all_before('=========================================') mut msg := message.all_before('=========================================')
msg = msg.replace(vroot + os.path_separator, '') msg = msg.replace(vroot + os.path_separator, '')
msg = msg.trim_space() msg = msg.trim_space()

View File

@ -1,5 +1,3 @@
import os
fn main() { fn main() {
println('hello world') println('hello world')
} }

View File

@ -1,5 +1,3 @@
import os
fn main() { fn main() {
areas := ['game', 'web', 'tools', 'science', 'systems', 'embedded'] areas := ['game', 'web', 'tools', 'science', 'systems', 'embedded']
for i :=0; i < areas.len; i++{ for i :=0; i < areas.len; i++{

View File

@ -1,6 +1,5 @@
fn main() { fn main() {
test := 'hello' test := 'hello'
hello := 'world' hello := 'world'
println('%.*s$hello$test') println('%.*s$hello$test')
} }

57
vlib/v/tests/live_test.v 100755 → 100644
View File

@ -5,29 +5,28 @@ import time
The goal of this test, is to simulate a developer, that has run a program, compiled with -live flag. The goal of this test, is to simulate a developer, that has run a program, compiled with -live flag.
It does so by writing a new generated program containing a [live] fn pmessage() string {...} function, It does so by writing a new generated program containing a [live] fn pmessage() string {...} function,
then runs the generated program at the start *in the background*, then runs the generated program at the start *in the background*,
waits some time, so that the program could run a few iterations, then modifies its source waits some time, so that the program could run a few iterations, then modifies its source
(simulates a developer that has saved a new version of the program source), (simulates a developer that has saved a new version of the program source),
then it waits some more, modifies it again and saves it once more. then it waits some more, modifies it again and saves it once more.
On each modification, the running program, should detect that its source code has changed, On each modification, the running program, should detect that its source code has changed,
and recompile a shared library, which it then it should load, and thus modify its own and recompile a shared library, which it then it should load, and thus modify its own
behavior at runtime (the pmessage function). behavior at runtime (the pmessage function).
If everything works fine, the output of the generated program would have changed at least 1-2 times, If everything works fine, the output of the generated program would have changed at least 1-2 times,
which then is detected by the test program (the histogram checks). which then is detected by the test program (the histogram checks).
Since this test program is sensitive to coordination (or lack of) of several processes, Since this test program is sensitive to coordination (or lack of) of several processes,
it tries to sidestep the coordination issue by polling the file system for the existance it tries to sidestep the coordination issue by polling the file system for the existance
of files, ORIGINAL.txt ... STOP.txt , which are appended to by the generated program. of files, ORIGINAL.txt ... STOP.txt , which are appended to by the generated program.
NB: That approach of monitoring the state of the running generated program, is clearly not ideal, NB: That approach of monitoring the state of the running generated program, is clearly not ideal,
but sidesteps the issue of coordinating processes through IPC or stdin/stdout in hopefully but sidesteps the issue of coordinating processes through IPC or stdin/stdout in hopefully
not very flaky way. not very flaky way.
TODO: Cleanup this when/if v has better process control/communication primitives. TODO: Cleanup this when/if v has better process control/communication primitives.
*/ */
const ( const (
vexe = os.getenv('VEXE') vexe = os.getenv('VEXE')
tmp_file = os.join_path(os.temp_dir(), 'generated_live_program.tmp.v') tmp_file = os.join_path(os.temp_dir(), 'generated_live_program.tmp.v')
@ -48,14 +47,14 @@ import live
fn append_to_file(fname, s string) { fn append_to_file(fname, s string) {
mut f := os.open_append(fname) or { mut f := os.open_append(fname) or {
println('>>>> could not open file \$fname for appending, err: \$err ') println('>>>> could not open file \$fname for appending, err: \$err ')
return return
} }
f.writeln('\$s') f.writeln('\$s')
//info := live.info() //info := live.info()
//f.writeln('>>> reloads: \${info.reloads} | ok reloads: \${info.reloads_ok}') //f.writeln('>>> reloads: \${info.reloads} | ok reloads: \${info.reloads_ok}')
f.flush() f.flush()
f.close() f.close()
} }
fn myprintln(s string) { fn myprintln(s string) {
append_to_file('$output_file', s) append_to_file('$output_file', s)
@ -76,12 +75,12 @@ const (
fn main() { fn main() {
mut info := live.info() mut info := live.info()
info.recheck_period_ms = 5 info.recheck_period_ms = 5
myprintln('START') myprintln('START')
myprintln('DATE: ' + time.now().str()) myprintln('DATE: ' + time.now().str())
pmessage() pmessage()
pmessage() pmessage()
// NB: 1000 * 5 = maximum of ~5s runtime // NB: 1000 * 5 = maximum of ~5s runtime
for i:=0; i<1000; i++ { for i:=0; i<1000; i++ {
s := pmessage() s := pmessage()
append_to_file(os.resource_abs_path(s + '.txt'), s) append_to_file(os.resource_abs_path(s + '.txt'), s)
@ -98,12 +97,12 @@ fn main() {
" "
) )
fn atomic_write_source( source string ){ fn atomic_write_source(source string) {
// NB: here wrtiting is done in 2 steps, since os.write_file can take some time, // NB: here wrtiting is done in 2 steps, since os.write_file can take some time,
// during which the file will be modified, but it will still be not completely written. // during which the file will be modified, but it will still be not completely written.
// The os.mv after that, guarantees that the reloader will see a complete valid V program. // The os.mv after that, guarantees that the reloader will see a complete valid V program.
os.write_file(tmp_file, source) os.write_file(tmp_file, source)
os.mv(tmp_file, source_file ) os.mv(tmp_file, source_file)
} }
// //
@ -114,13 +113,15 @@ fn testsuite_begin() {
eprintln('You can still do it by setting FORCE_LIVE_TEST=1 .') eprintln('You can still do it by setting FORCE_LIVE_TEST=1 .')
exit(0) exit(0)
} }
for f in [ tmp_file, source_file, output_file, res_original_file, res_changed_file, res_another_file, res_stop_file] { for f in [tmp_file, source_file, output_file, res_original_file, res_changed_file, res_another_file,
res_stop_file,
] {
os.rm(f) os.rm(f)
} }
atomic_write_source( live_program_source ) atomic_write_source(live_program_source)
} }
[if debuglivetest] [debuglivetest]
fn vprintln(s string) { fn vprintln(s string) {
eprintln(s) eprintln(s)
} }
@ -132,36 +133,36 @@ fn testsuite_end() {
output_lines := os.read_lines(output_file) or { output_lines := os.read_lines(output_file) or {
panic('could not read $output_file, error: $err') panic('could not read $output_file, error: $err')
} }
mut histogram := map[string]int mut histogram := map[string]int{}
for line in output_lines { for line in output_lines {
histogram[line] = histogram[line] + 1 histogram[line] = histogram[line] + 1
} }
for k, v in histogram { for k, v in histogram {
eprintln('> found ${v:5d} times: ${k}') eprintln('> found ${v:5d} times: $k')
} }
vprintln('---------------------------------------------------------------------------') vprintln('---------------------------------------------------------------------------')
assert histogram['START'] > 0 assert histogram['START'] > 0
assert histogram['ORIGINAL'] > 0 assert histogram['ORIGINAL'] > 0
assert histogram['CHANGED'] + histogram['ANOTHER'] > 0 assert histogram['CHANGED'] + histogram['ANOTHER'] > 0
//assert histogram['END'] > 0 // assert histogram['END'] > 0
} }
fn change_source(new string) { fn change_source(new string) {
time.sleep_ms(100) time.sleep_ms(100)
vprintln('> change ORIGINAL to: $new') vprintln('> change ORIGINAL to: $new')
atomic_write_source( live_program_source.replace('ORIGINAL', new) ) atomic_write_source(live_program_source.replace('ORIGINAL', new))
wait_for_file(new) wait_for_file(new)
} }
fn wait_for_file(new string){ fn wait_for_file(new string) {
time.sleep_ms(100) time.sleep_ms(100)
expected_file := os.join_path(os.temp_dir(), new + '.txt') expected_file := os.join_path(os.temp_dir(), new + '.txt')
eprintln('waiting for $expected_file ...') eprintln('waiting for $expected_file ...')
for i:=0 ; i <= 400 ; i++ { for i := 0; i <= 400; i++ {
if i % 25 == 0 { if i % 25 == 0 {
vprintln(' checking ${i:-10d} for $expected_file ...') vprintln(' checking ${i:-10d} for $expected_file ...')
} }
if os.exists( expected_file ) { if os.exists(expected_file) {
assert true assert true
vprintln('> done.') vprintln('> done.')
time.sleep_ms(100) time.sleep_ms(100)

View File

@ -2,6 +2,6 @@
module local module local
pub fn local_fn() bool { pub fn local_fn() bool {
return true return true
} }

View File

@ -12,13 +12,19 @@ fn test_match_integers() {
mut a := 3 mut a := 3
mut b := 0 mut b := 0
match a { match a {
2 { println('two') } 2 {
println('two')
}
3 { 3 {
println('three') println('three')
b = 3 b = 3
} }
4 { println('four') } 4 {
else { println('???') } println('four')
}
else {
println('???')
}
} }
assert b == 3 assert b == 3
assert match 2 { assert match 2 {
@ -36,8 +42,12 @@ fn test_match_integers() {
} == 5 } == 5
a = 0 a = 0
match 2 { match 2 {
0 { a = 1 } 0 {
1 { a = 2 } a = 1
}
1 {
a = 2
}
else { else {
a = 3 a = 3
println('a is $a') println('a is $a')
@ -46,7 +56,9 @@ fn test_match_integers() {
assert a == 3 assert a == 3
a = 0 a = 0
match 1 { match 1 {
0 { a = 1 } 0 {
a = 1
}
1 { 1 {
a = 2 a = 2
a = a + 2 a = a + 2
@ -83,18 +95,24 @@ fn test_match_range() {
fn test_match_enums() { fn test_match_enums() {
mut b := Color.red mut b := Color.red
match b { match b {
.red { b = .green } .red {
.green { b = .blue } b = .green
}
.green {
b = .blue
}
else { else {
println('b is ${b.str()}') println('b is $b.str()')
b = .red b = .red
} }
} }
assert b == .green assert b == .green
match b { match b {
.red { b = .green } .red {
b = .green
}
else { else {
println('b is ${b.str()}') println('b is $b.str()')
b = .blue b = .blue
} }
} }
@ -106,23 +124,22 @@ type Sum = A1 | B1
struct A1 { struct A1 {
pos int pos int
} }
struct B1 { struct B1 {
val string val string
} }
fn f(s Sum) string { fn f(s Sum) string {
match s { match s {
A1 { A1 { return typeof(s) }
return typeof(s) B1 { return '' }
} }
B1 {
return ''
}
}
return '' return ''
} }
fn test_sum_type_name() { fn test_sum_type_name() {
a := A1{pos: 22} a := A1{
pos: 22
}
assert f(a) == 'A1' assert f(a) == 'A1'
} }

View File

@ -1,16 +1,14 @@
module amodule module amodule
// This tests whether _test.v files can be *internal* to a // This tests whether _test.v files can be *internal* to a
// module, and thus have access to its guts. // module, and thus have access to its guts.
// NB: the function test_private_isub() is defined both here // NB: the function test_private_isub() is defined both here
// and inside internal_module_test.v . That is done on purpose, // and inside internal_module_test.v . That is done on purpose,
// with the goal of ensuring that _test.v files are compiled // with the goal of ensuring that _test.v files are compiled
// *independently* from each other. // *independently* from each other.
// //
// _test.v files should *only* import all the other normal .v // _test.v files should *only* import all the other normal .v
// files from the same folder, NOT other _test.v files from it. // files from the same folder, NOT other _test.v files from it.
fn test_private_isub() {
fn test_private_isub(){ assert private_isub(7, 5) == 2
assert private_isub(7,5) == 2
} }

View File

@ -1,16 +1,15 @@
module amodule module amodule
// this tests whether _test.v files can be *internal* // this tests whether _test.v files can be *internal*
// to a module, and thus have access to its guts. // to a module, and thus have access to its guts.
fn test_iadd() {
fn test_iadd(){
assert iadd(10, 20) == 30 assert iadd(10, 20) == 30
} }
fn test_imul(){ fn test_imul() {
assert imul(5,8) == 40 assert imul(5, 8) == 40
} }
fn test_private_isub(){ fn test_private_isub() {
assert private_isub(10,6) == 4 assert private_isub(10, 6) == 4
} }

View File

@ -1,15 +1,14 @@
module amodule module amodule
pub fn iadd(x int, y int) int { pub fn iadd(x, y int) int {
return x + y return x + y
} }
pub fn imul(x int, y int) int { pub fn imul(x, y int) int {
return x * y return x * y
} }
/////////////////////////////////////// // /////////////////////////////////////
fn private_isub(x, y int) int {
fn private_isub(x int, y int) int { return x - y
return x - y
} }

View File

@ -8,10 +8,13 @@ fn new_st() MyStruct {
fn get_st() MyStruct { fn get_st() MyStruct {
r := new_st() r := new_st()
return {r|s:'6'} return {
r |
s: '6'
}
} }
fn main() { fn main() {
s := get_st() s := get_st()
println(s) println(s)
} }

View File

@ -2,7 +2,7 @@ module main
import mod1 import mod1
fn main(){ fn main() {
res := mod1.vadd(1,2) res := mod1.vadd(1, 2)
println( res ) println(res)
} }

View File

@ -1,10 +1,10 @@
import mod1.submodule as m import mod1.submodule as m
fn test_mod1_can_still_be_found_through_parent_project_vmod(){ fn test_mod1_can_still_be_found_through_parent_project_vmod() {
assert 1051 == m.f() assert 1051 == m.f()
} }
/* /*
NB: this main program is under bin/ , but it still NB: this main program is under bin/ , but it still
can find mod1, because the parent project has v.mod, can find mod1, because the parent project has v.mod,
so v module lookup for this program will find mod1 through so v module lookup for this program will find mod1 through

View File

@ -1,11 +1,10 @@
import mod1 import mod1
import mod1.submodule import mod1.submodule
fn test_mod1(){ fn test_mod1() {
assert 1 == mod1.f() assert 1 == mod1.f()
} }
fn test_mod1_submodule_can_find_and_use_all_its_sibling_submodules(){ fn test_mod1_submodule_can_find_and_use_all_its_sibling_submodules() {
assert 1051 == submodule.f() assert 1051 == submodule.f()
} }

View File

@ -1,9 +1,8 @@
fn iadd(x, y int) int {
fn iadd(x int, y int) int {
return x + y return x + y
} }
fn main(){ fn main() {
println('Hello world') println('Hello world')
println('iadd: ' + iadd(1,2).str()) println('iadd: ' + iadd(1, 2).str())
} }

View File

@ -1,6 +1,7 @@
module main module main
fn test_iadd_3_4(){
a := iadd(3,4) fn test_iadd_3_4() {
assert a == 7 a := iadd(3, 4)
assert iadd(10,20) == 30 assert a == 7
assert iadd(10, 20) == 30
} }

View File

@ -1,9 +1,11 @@
module main module main
fn test_iadd_3_4(){
a := iadd(3,4) fn test_iadd_3_4() {
assert a == 7 a := iadd(3, 4)
assert a == 7
} }
fn test_iadd_5_6(){
a := iadd(5,6) fn test_iadd_5_6() {
assert a == 11 a := iadd(5, 6)
assert a == 11
} }

View File

@ -5,7 +5,7 @@ import v.util
pub struct RunnerOptions { pub struct RunnerOptions {
pub: pub:
wd string wd string
vexec string vexec string
files []string files []string
} }
@ -30,51 +30,45 @@ pub fn full_path_to_v(dirs_in int) string {
println('vreal : $vreal') println('vreal : $vreal')
println('myself : $myself') println('myself : $myself')
println('wd : $wd') println('wd : $wd')
*/ */
return vexec return vexec
} }
fn diff_files( file_result, file_expected string ) string { fn diff_files(file_result, file_expected string) string {
diffcmd := util.find_working_diff_command() or { return err } diffcmd := util.find_working_diff_command() or {
return err
}
return util.color_compare_files(diffcmd, file_result, file_expected) return util.color_compare_files(diffcmd, file_result, file_expected)
} }
pub fn run_repl_file(wd string, vexec string, file string) ?string { pub fn run_repl_file(wd, vexec, file string) ?string {
vexec_folder := os.dir(vexec) + os.path_separator vexec_folder := os.dir(vexec) + os.path_separator
fcontent := os.read_file(file) or { return error('Could not read file ${file}') } fcontent := os.read_file(file) or {
return error('Could not read file $file')
}
content := fcontent.replace('\r', '') content := fcontent.replace('\r', '')
input := content.all_before('===output===\n') input := content.all_before('===output===\n')
output := content.all_after('===output===\n').trim_right('\n\r') output := content.all_after('===output===\n').trim_right('\n\r')
fname := os.file_name(file)
fname := os.file_name( file ) input_temporary_filename := os.real_path(os.join_path(wd, 'input_temporary_filename.txt'))
input_temporary_filename := os.real_path(os.join_path( wd, 'input_temporary_filename.txt'))
os.write_file(input_temporary_filename, input) os.write_file(input_temporary_filename, input)
os.write_file( os.real_path(os.join_path( wd, 'original.txt' ) ), fcontent ) os.write_file(os.real_path(os.join_path(wd, 'original.txt')), fcontent)
rcmd := '"$vexec" repl -replfolder "$wd" -replprefix "${fname}." < $input_temporary_filename' rcmd := '"$vexec" repl -replfolder "$wd" -replprefix "${fname}." < $input_temporary_filename'
r := os.exec(rcmd) or { r := os.exec(rcmd) or {
os.rm(input_temporary_filename) os.rm(input_temporary_filename)
return error('Could not execute: $rcmd') return error('Could not execute: $rcmd')
} }
os.rm(input_temporary_filename) os.rm(input_temporary_filename)
result := r.output.replace('\r', '').replace('>>> ', '').replace('>>>', '').replace('... ',
result := r.output.replace('\r','') '').all_after('Use Ctrl-C or `exit` to exit\n').replace(wd + os.path_separator, '').replace(vexec_folder,
.replace('>>> ', '') '').replace('\\', '/').trim_right('\n\r')
.replace('>>>', '')
.replace('... ', '')
.all_after('Use Ctrl-C or `exit` to exit\n')
.replace(wd + os.path_separator, '' )
.replace(vexec_folder, '')
.replace('\\', '/')
.trim_right('\n\r')
if result != output { if result != output {
file_result := '${file}.result.txt' file_result := '${file}.result.txt'
file_expected := '${file}.expected.txt' file_expected := '${file}.expected.txt'
os.write_file( file_result, result ) os.write_file(file_result, result)
os.write_file( file_expected, output ) os.write_file(file_expected, output)
diff := diff_files( file_result, file_expected ) diff := diff_files(file_result, file_expected)
return error('Difference found in REPL file: ${file} return error('Difference found in REPL file: $file
====> Got : ====> Got :
|$result| |$result|
====> Expected : ====> Expected :
@ -83,31 +77,29 @@ pub fn run_repl_file(wd string, vexec string, file string) ?string {
$diff $diff
') ')
} else { } else {
return 'Repl file ${file} is OK' return 'Repl file $file is OK'
} }
} }
pub fn run_prod_file(wd string, vexec string, file string) ?string { pub fn run_prod_file(wd, vexec, file string) ?string {
file_expected := '${file}.expected.txt' file_expected := '${file}.expected.txt'
f_expected_content := os.read_file(file_expected) or { return error('Could not read file ${file}') } f_expected_content := os.read_file(file_expected) or {
return error('Could not read file $file')
}
expected_content := f_expected_content.replace('\r', '') expected_content := f_expected_content.replace('\r', '')
cmd := '"$vexec" -prod run "$file"'
cmd := '"$vexec" -prod run "${file}"'
r := os.exec(cmd) or { r := os.exec(cmd) or {
return error('Could not execute: $cmd') return error('Could not execute: $cmd')
} }
if r.exit_code != 0 { if r.exit_code != 0 {
return error('$cmd return exit code: $r.exit_code') return error('$cmd return exit code: $r.exit_code')
} }
result := r.output.replace('\r', '')
result := r.output.replace('\r','')
if result != expected_content { if result != expected_content {
file_result := '${file}.result.txt' file_result := '${file}.result.txt'
os.write_file( file_result, result ) os.write_file(file_result, result)
diff := diff_files( file_result, file_expected ) diff := diff_files(file_result, file_expected)
return error('Difference found in test: ${file} return error('Difference found in test: $file
====> Got : ====> Got :
|$result| |$result|
====> Expected : ====> Expected :
@ -116,7 +108,7 @@ pub fn run_prod_file(wd string, vexec string, file string) ?string {
$diff $diff
') ')
} else { } else {
return 'Prod file ${file} is OK' return 'Prod file $file is OK'
} }
} }
@ -127,11 +119,11 @@ pub fn new_options() RunnerOptions {
if os.args.len > 1 { if os.args.len > 1 {
files = os.args[1..] files = os.args[1..]
} else { } else {
os.chdir( os.dir(vexec) ) os.chdir(os.dir(vexec))
wd = os.getwd() wd = os.getwd()
files = os.walk_ext('.', '.repl') files = os.walk_ext('.', '.repl')
} }
return RunnerOptions { return RunnerOptions{
wd: wd wd: wd
vexec: vexec vexec: vexec
files: files files: files
@ -147,7 +139,7 @@ pub fn new_prod_options() RunnerOptions {
} else { } else {
files = os.walk_ext(wd, '.prod.v') files = os.walk_ext(wd, '.prod.v')
} }
return RunnerOptions { return RunnerOptions{
wd: wd wd: wd
vexec: vexec vexec: vexec
files: files files: files

View File

@ -1,6 +1,7 @@
struct Zest {
val int
}
struct Zest { val int }
fn (t Zest) get_a_finger_to_the_moon() voidptr { fn (t Zest) get_a_finger_to_the_moon() voidptr {
return voidptr(0) return voidptr(0)
} }
@ -8,9 +9,11 @@ fn (t Zest) get_a_finger_to_the_moon() voidptr {
fn get_the_dao_way() voidptr { fn get_the_dao_way() voidptr {
return voidptr(0) return voidptr(0)
} }
fn test_returning_a_void_pointer_from_a_method() { fn test_returning_a_void_pointer_from_a_method() {
t := &Zest{ val: 123 } t := &Zest{
val: 123
}
z := voidptr(0) z := voidptr(0)
assert z == t.get_a_finger_to_the_moon() assert z == t.get_a_finger_to_the_moon()
assert t.get_a_finger_to_the_moon() == 0 assert t.get_a_finger_to_the_moon() == 0

View File

@ -32,7 +32,7 @@ fn test_shared_array() {
finished_threads = unsafe { finished_threads = unsafe {
foo[2] foo[2]
} }
} }
if finished_threads == 4 { if finished_threads == 4 {
break break
@ -43,11 +43,11 @@ fn test_shared_array() {
f0 := unsafe { f0 := unsafe {
foo[0] foo[0]
} }
f1 := unsafe { f1 := unsafe {
foo[1] foo[1]
} }
assert f0 == 100010 assert f0 == 100010
assert f1 == 350020 assert f1 == 350020
} }

View File

@ -2,7 +2,7 @@ module main
struct Anything { struct Anything {
mut: mut:
name string = "" name string = ''
keepo int = 0 keepo int = 0
} }
@ -12,80 +12,102 @@ fn (a Anything) str() string {
fn test_array_of_ptrs_to_structs_can_be_printed() { fn test_array_of_ptrs_to_structs_can_be_printed() {
mut testing := []&Anything{} mut testing := []&Anything{}
testing << &Anything{name: "Hehe"} testing << &Anything{
testing << &Anything{name: "other"} name: 'Hehe'
testing << &Anything{name: "test"} }
testing << &Anything{
name: 'other'
}
testing << &Anything{
name: 'test'
}
for test in testing { for test in testing {
println(test) println(test)
assert true assert true
} }
println('testing: $testing') println('testing: $testing')
println( testing ) println(testing)
assert true assert true
} }
// At the same time, this should also work: // At the same time, this should also work:
// (note the str method defined on (a &T), instead on (a T)) // (note the str method defined on (a &T), instead on (a T))
struct PstrAnything { struct PstrAnything {
mut: mut:
name string = "" name string = ''
keepo int = 0 keepo int = 0
} }
fn (a &PstrAnything) str() string { fn (a &PstrAnything) str() string {
return a.name return a.name
} }
fn test_array_of_ptrs_to_structs_can_be_printed_when_structs_have_str_with_ptr() { fn test_array_of_ptrs_to_structs_can_be_printed_when_structs_have_str_with_ptr() {
mut testing := []&PstrAnything{} mut testing := []&PstrAnything{}
testing << &PstrAnything{name: "abc"} testing << &PstrAnything{
testing << &PstrAnything{name: "def"} name: 'abc'
testing << &PstrAnything{name: "ghi"} }
testing << &PstrAnything{
name: 'def'
}
testing << &PstrAnything{
name: 'ghi'
}
for test in testing { for test in testing {
println(test) println(test)
assert true assert true
} }
println('testing: $testing') println('testing: $testing')
println( testing ) println(testing)
assert true assert true
} }
// //
fn test_stack_array_of_structs_can_be_printed_when_structs_have_ordinary_str() { fn test_stack_array_of_structs_can_be_printed_when_structs_have_ordinary_str() {
mut t := [3]Anything mut t := [3]Anything
t[0] = Anything{name: "012"} t[0] = Anything{
t[1] = Anything{name: "345"} name: '012'
t[2] = Anything{name: "678"} }
t[1] = Anything{
name: '345'
}
t[2] = Anything{
name: '678'
}
for test in t { for test in t {
println(test) println(test)
assert true assert true
} }
println('t: $t') println('t: $t')
println( t ) println(t)
println( 't[0] := ${t[0]}') println('t[0] := ${t[0]}')
assert true assert true
} }
fn test_stack_array_of_structs_can_be_printed_when_structs_have_str_with_ptr() { fn test_stack_array_of_structs_can_be_printed_when_structs_have_str_with_ptr() {
// this generates a C error // this generates a C error
mut pt := [3]PstrAnything mut pt := [3]PstrAnything
pt[0] = PstrAnything{name: "P012"} pt[0] = PstrAnything{
pt[1] = PstrAnything{name: "P345"} name: 'P012'
pt[2] = PstrAnything{name: "P678"} }
pt[1] = PstrAnything{
name: 'P345'
}
pt[2] = PstrAnything{
name: 'P678'
}
for test in pt { for test in pt {
println(test) println(test)
assert true assert true
} }
println('pt: $pt') println('pt: $pt')
println( pt ) println(pt)
print( 'pt[0] := ') print('pt[0] := ')
print( pt[0] ) print(pt[0])
println('') println('')
assert true assert true
$if debug_buggy_println ? { $if debug_buggy_println ? {
//TODO: fix string interpolation for structs with `fn (t &T) str() string` too: // TODO: fix string interpolation for structs with `fn (t &T) str() string` too:
println( 'pt[0] := ${pt[0]}') println('pt[0] := ${pt[0]}')
} }
} }

View File

@ -1,31 +1,51 @@
fn test_ptr_assign() { fn test_ptr_assign() {
v := [int(5), 6, 77, 1] v := [int(5), 6, 77, 1]
mut p := &v[0] mut p := &v[0]
unsafe { (*p)++ } unsafe {
unsafe { p++ } // p now points to v[1] (*p)++
unsafe { (*p) += 2 } }
unsafe { p += 2 } // p now points to v[3] unsafe {
unsafe { *p = 31 } p++
assert v[0] == 6 } // p now points to v[1]
assert v[1] == 8 unsafe {
assert v[2] == 77 (*p) += 2
assert v[3] == 31 }
unsafe {
p += 2
} // p now points to v[3]
unsafe {
*p = 31
}
assert v[0] == 6
assert v[1] == 8
assert v[2] == 77
assert v[3] == 31
} }
fn test_ptr_infix() { fn test_ptr_infix() {
v := 4 v := 4
mut q := unsafe{ &v - 1 } mut q := unsafe {
q = unsafe {q + 3} &v - 1
_ := q }
_ := v
q = unsafe {
q + 3
}
_ := q
_ := v
} }
struct S1 {} struct S1 {
}
[unsafe_fn] [unsafe_fn]
fn (s S1) f(){} fn (s S1) f() {
}
fn test_funcs() { fn test_funcs() {
s := S1{} s := S1{}
unsafe { s.f() } unsafe {
s.f()
}
} }

View File

@ -168,11 +168,7 @@ fn get_array_content(tokens []Token, st_idx int) ?([]string, int) {
if tokens[idx + 1].typ !in [.comma, .rabr] { if tokens[idx + 1].typ !in [.comma, .rabr] {
return error('vmod: invalid separator "${tokens[idx+1].val}"') return error('vmod: invalid separator "${tokens[idx+1].val}"')
} }
idx += if tokens[idx + 1].typ == .comma { idx += if tokens[idx + 1].typ == .comma { 2 } else { 1 }
2
} else {
1
}
} }
.rabr { .rabr {
idx++ idx++

View File

@ -19,14 +19,11 @@ import os
// => ModFileAndFolder{'vlib/v.mod', 'vlib'} // => ModFileAndFolder{'vlib/v.mod', 'vlib'}
// ModFileCacher.get('vlib/v/test/project_with_c_code/mod1') // ModFileCacher.get('vlib/v/test/project_with_c_code/mod1')
// => ModFileAndFolder{'vlib/v/test/project_with_c_code/mod1/v.mod', 'vlib/v/test/project_with_c_code/mod1'} // => ModFileAndFolder{'vlib/v/test/project_with_c_code/mod1/v.mod', 'vlib/v/test/project_with_c_code/mod1'}
pub struct ModFileAndFolder { pub struct ModFileAndFolder {
pub: pub:
// vmod_file contains the full path of the found 'v.mod' file, or '' // vmod_file contains the full path of the found 'v.mod' file, or ''
// if no 'v.mod' file was found in file_path_dir, or in its parent folders. // if no 'v.mod' file was found in file_path_dir, or in its parent folders.
vmod_file string vmod_file string
// vmod_folder contains the file_path_dir, if there is no 'v.mod' file in // vmod_folder contains the file_path_dir, if there is no 'v.mod' file in
// *any* of the parent folders, otherwise it is the first parent folder, // *any* of the parent folders, otherwise it is the first parent folder,
// where a v.mod file was found. // where a v.mod file was found.
@ -36,7 +33,7 @@ pub:
[ref_only] [ref_only]
pub struct ModFileCacher { pub struct ModFileCacher {
mut: mut:
cache map[string]ModFileAndFolder cache map[string]ModFileAndFolder
// folder_files caches os.ls(key) // folder_files caches os.ls(key)
folder_files map[string][]string folder_files map[string][]string
} }
@ -49,35 +46,34 @@ pub fn (mcache &ModFileCacher) dump() {
$if debug { $if debug {
eprintln('ModFileCacher DUMP:') eprintln('ModFileCacher DUMP:')
eprintln(' ModFileCacher.cache:') eprintln(' ModFileCacher.cache:')
for k,v in mcache.cache { for k, v in mcache.cache {
eprintln(' K: ${k:-32s} | V: "${v.vmod_file:32s}" | "${v.vmod_folder:32s}" ') eprintln(' K: ${k:-32s} | V: "${v.vmod_file:32s}" | "${v.vmod_folder:32s}" ')
} }
eprintln(' ModFileCacher.folder_files:') eprintln(' ModFileCacher.folder_files:')
for k,v in mcache.folder_files { for k, v in mcache.folder_files {
eprintln(' K: ${k:-32s} | V: ${v.str()}') eprintln(' K: ${k:-32s} | V: $v.str()')
} }
} }
} }
pub fn (mut mcache ModFileCacher) get_by_file(vfile string) ModFileAndFolder { pub fn (mut mcache ModFileCacher) get_by_file(vfile string) ModFileAndFolder {
return mcache.get_by_folder( os.dir( vfile ) ) return mcache.get_by_folder(os.dir(vfile))
} }
pub fn (mut mcache ModFileCacher) get_by_folder(vfolder string) ModFileAndFolder { pub fn (mut mcache ModFileCacher) get_by_folder(vfolder string) ModFileAndFolder {
mfolder := os.real_path( vfolder ) mfolder := os.real_path(vfolder)
if mfolder in mcache.cache { if mfolder in mcache.cache {
return mcache.cache[ mfolder ] return mcache.cache[mfolder]
} }
traversed_folders, res := mcache.traverse( mfolder ) traversed_folders, res := mcache.traverse(mfolder)
for tfolder in traversed_folders { for tfolder in traversed_folders {
mcache.add( tfolder, res ) mcache.add(tfolder, res)
} }
return res return res
} }
fn (mut cacher ModFileCacher) add(path string, result ModFileAndFolder) { fn (mut cacher ModFileCacher) add(path string, result ModFileAndFolder) {
cacher.cache[ path ] = result cacher.cache[path] = result
} }
fn (mut mcache ModFileCacher) traverse(mfolder string) ([]string, ModFileAndFolder) { fn (mut mcache ModFileCacher) traverse(mfolder string) ([]string, ModFileAndFolder) {
@ -92,47 +88,59 @@ fn (mut mcache ModFileCacher) traverse(mfolder string) ([]string, ModFileAndFold
break break
} }
if cfolder in mcache.cache { if cfolder in mcache.cache {
res := mcache.cache[ cfolder ] res := mcache.cache[cfolder]
if res.vmod_file.len == 0 { if res.vmod_file.len == 0 {
mcache.mark_folders_as_vmod_free( folders_so_far ) mcache.mark_folders_as_vmod_free(folders_so_far)
}else{ } else {
mcache.mark_folders_with_vmod( folders_so_far, res ) mcache.mark_folders_with_vmod(folders_so_far, res)
} }
return []string{}, res return []string{}, res
} }
files := mcache.get_files( cfolder ) files := mcache.get_files(cfolder)
if 'v.mod' in files { if 'v.mod' in files {
// TODO: actually read the v.mod file and parse its contents to see // TODO: actually read the v.mod file and parse its contents to see
// if its source folder is different // if its source folder is different
res := ModFileAndFolder{ vmod_file: os.join_path( cfolder, 'v.mod'), vmod_folder: cfolder } res := ModFileAndFolder{
vmod_file: os.join_path(cfolder, 'v.mod')
vmod_folder: cfolder
}
return folders_so_far, res return folders_so_far, res
} }
if mcache.check_for_stop( cfolder, files ) { if mcache.check_for_stop(cfolder, files) {
break break
} }
cfolder = os.base_dir( cfolder ) cfolder = os.base_dir(cfolder)
folders_so_far << cfolder folders_so_far << cfolder
levels++ levels++
} }
mcache.mark_folders_as_vmod_free( folders_so_far ) mcache.mark_folders_as_vmod_free(folders_so_far)
return [mfolder], ModFileAndFolder{ vmod_file: '', vmod_folder: mfolder } return [mfolder], ModFileAndFolder{
} vmod_file: ''
vmod_folder: mfolder
fn (mut mcache ModFileCacher) mark_folders_with_vmod( folders_so_far []string, vmod ModFileAndFolder ) {
for f in folders_so_far {
mcache.add( f, vmod )
} }
} }
fn (mut mcache ModFileCacher) mark_folders_as_vmod_free( folders_so_far []string ) { fn (mut mcache ModFileCacher) mark_folders_with_vmod(folders_so_far []string, vmod ModFileAndFolder) {
for f in folders_so_far {
mcache.add(f, vmod)
}
}
fn (mut mcache ModFileCacher) mark_folders_as_vmod_free(folders_so_far []string) {
// No need to check these folders anymore, // No need to check these folders anymore,
// because their parents do not contain v.mod files // because their parents do not contain v.mod files
for f in folders_so_far { for f in folders_so_far {
mcache.add( f, ModFileAndFolder{ vmod_file: '', vmod_folder: f } ) mcache.add(f, ModFileAndFolder{
vmod_file: ''
vmod_folder: f
})
} }
} }
const ( mod_file_stop_paths = ['.git', '.hg', '.svn', '.v.mod.stop' ] ) const (
mod_file_stop_paths = ['.git', '.hg', '.svn', '.v.mod.stop']
)
fn (mcache &ModFileCacher) check_for_stop(cfolder string, files []string) bool { fn (mcache &ModFileCacher) check_for_stop(cfolder string, files []string) bool {
for i in mod_file_stop_paths { for i in mod_file_stop_paths {
if i in files { if i in files {
@ -144,20 +152,23 @@ fn (mcache &ModFileCacher) check_for_stop(cfolder string, files []string) bool {
fn (mut mcache ModFileCacher) get_files(cfolder string) []string { fn (mut mcache ModFileCacher) get_files(cfolder string) []string {
if cfolder in mcache.folder_files { if cfolder in mcache.folder_files {
return mcache.folder_files[ cfolder ] return mcache.folder_files[cfolder]
} }
mut files := []string{} mut files := []string{}
if os.exists( cfolder ) && os.is_dir(cfolder) { if os.exists(cfolder) && os.is_dir(cfolder) {
if listing := os.ls(cfolder) { if listing := os.ls(cfolder) {
files = listing files = listing
} }
} }
mcache.folder_files[ cfolder ] = files mcache.folder_files[cfolder] = files
return files return files
} }
// used during lookup for v.mod to support @VROOT // used during lookup for v.mod to support @VROOT
const ( private_file_cacher = new_mod_file_cacher() ) const (
private_file_cacher = new_mod_file_cacher()
)
pub fn get_cache() &ModFileCacher { pub fn get_cache() &ModFileCacher {
return private_file_cacher return private_file_cacher
} }