fmt: lots of fixes

pull/4586/head
Enzo Baldisserri 2020-04-25 17:49:16 +02:00 committed by GitHub
parent 7c080c5d4a
commit fb54a2635c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 698 additions and 550 deletions

View File

@ -8,9 +8,9 @@ import v.table
pub type TypeDecl = AliasTypeDecl | SumTypeDecl | FnTypeDecl pub type TypeDecl = AliasTypeDecl | SumTypeDecl | FnTypeDecl
pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral | CharLiteral | FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr | AssignExpr | PrefixExpr | IndexExpr | RangeExpr | MatchExpr | CastExpr | EnumVal | Assoc | SizeOf | None | MapInit | IfGuardExpr | ParExpr | OrExpr | ConcatExpr | Type | AsCast | TypeOf | StringInterLiteral | AnonFn pub type Expr = AnonFn | ArrayInit | AsCast | AssignExpr | Assoc | BoolLiteral | CastExpr | CallExpr | CharLiteral | ConcatExpr | EnumVal | FloatLiteral | IfExpr | Ident | IfGuardExpr | InfixExpr | IndexExpr | IntegerLiteral | MapInit | MatchExpr | None | OrExpr | ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectorExpr | SizeOf | StringLiteral | StringInterLiteral | StructInit | Type | TypeOf
pub type Stmt = GlobalDecl | FnDecl | Return | Module | Import | ExprStmt | ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt | HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt | Comment | AssertStmt | UnsafeStmt | GoStmt | Block | InterfaceDecl pub type Stmt = AssignStmt | AssertStmt | Attr | Block | BranchStmt | Comment | CompIf | ConstDecl | DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | Return | StructDecl | TypeDecl | UnsafeStmt
pub type ScopeObject = ConstField | GlobalDecl | Var pub type ScopeObject = ConstField | GlobalDecl | Var

View File

@ -30,7 +30,7 @@ pub fn (node &FnDecl) str(t &table.Table) string {
receiver = '($node.receiver.name $m$name) ' receiver = '($node.receiver.name $m$name) '
*/ */
} }
mut name := node.name.after('.') mut name := if node.is_anon { '' } else { node.name.after('.') }
if node.is_c { if node.is_c {
name = 'C.$name' name = 'C.$name'
} }

View File

@ -46,7 +46,7 @@ pub fn new_builder(pref &pref.Preferences) Builder {
} }
// parse all deps from already parsed files // parse all deps from already parsed files
pub fn (b mut Builder) parse_imports() { pub fn (mut b Builder) parse_imports() {
mut done_imports := []string mut done_imports := []string
// NB: b.parsed_files is appended in the loop, // NB: b.parsed_files is appended in the loop,
// so we can not use the shorter `for in` form. // so we can not use the shorter `for in` form.
@ -84,7 +84,7 @@ pub fn (b mut Builder) parse_imports() {
b.resolve_deps() b.resolve_deps()
} }
pub fn (b mut Builder) resolve_deps() { pub fn (mut b Builder) resolve_deps() {
graph := b.import_graph() graph := b.import_graph()
deps_resolved := graph.resolve() deps_resolved := graph.resolve()
if !deps_resolved.acyclic { if !deps_resolved.acyclic {

View File

@ -1,14 +1,12 @@
module builder module builder
import ( import time
time import os
os import v.parser
v.parser import v.pref
v.pref import v.gen
v.gen
)
pub fn (b mut Builder) gen_c(v_files []string) string { pub fn (mut b Builder) gen_c(v_files []string) string {
t0 := time.ticks() t0 := time.ticks()
b.parsed_files = parser.parse_files(v_files, b.table, b.pref, b.global_scope) b.parsed_files = parser.parse_files(v_files, b.table, b.pref, b.global_scope)
b.parse_imports() b.parse_imports()
@ -35,7 +33,7 @@ pub fn (b mut Builder) gen_c(v_files []string) string {
return res return res
} }
pub fn (b mut Builder) build_c(v_files []string, out_file string) { pub fn (mut b Builder) build_c(v_files []string, out_file string) {
b.out_name_c = out_file b.out_name_c = out_file
b.info('build_c($out_file)') b.info('build_c($out_file)')
mut f := os.create(out_file) or { mut f := os.create(out_file) or {
@ -46,7 +44,7 @@ pub fn (b mut Builder) build_c(v_files []string, out_file string) {
// os.write_file(out_file, b.gen_c(v_files)) // os.write_file(out_file, b.gen_c(v_files))
} }
pub fn (b mut 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()}')
} }
@ -54,7 +52,7 @@ pub fn (b mut Builder) compile_c() {
// println('compile2()') // println('compile2()')
if b.pref.is_verbose { if b.pref.is_verbose {
println('all .v files before:') println('all .v files before:')
//println(files) // println(files)
} }
// v1 compiler files // v1 compiler files
// v.add_v_files_to_compile() // v.add_v_files_to_compile()

View File

@ -3,21 +3,19 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module builder module builder
import ( import os
os import time
time import v.cflag
v.cflag import v.pref
v.pref import v.util
v.util import term
term
)
fn todo() { fn todo() {
} }
fn (v &Builder) no_cc_installed() bool { fn (v &Builder) no_cc_installed() bool {
$if windows { $if windows {
os.exec('$v.pref.ccompiler -v')or{ os.exec('$v.pref.ccompiler -v') or {
if v.pref.is_verbose { if v.pref.is_verbose {
println('C compiler not found, trying to build with msvc...') println('C compiler not found, trying to build with msvc...')
} }
@ -27,7 +25,7 @@ fn (v &Builder) no_cc_installed() bool {
return false return false
} }
fn (v mut Builder) cc() { fn (mut v Builder) cc() {
if os.executable().contains('vfmt') { if os.executable().contains('vfmt') {
return return
} }
@ -55,8 +53,7 @@ fn (v mut Builder) cc() {
ret := os.system('$vexe -o $vjs_path -os js $vdir/cmd/v') ret := os.system('$vexe -o $vjs_path -os js $vdir/cmd/v')
if ret == 0 { if ret == 0 {
println('Done.') println('Done.')
} } else {
else {
println('Failed.') println('Failed.')
exit(1) exit(1)
} }
@ -69,7 +66,7 @@ fn (v mut Builder) cc() {
} }
} }
// v.out_name_c may be on a different partition than v.out_name // v.out_name_c may be on a different partition than v.out_name
os.mv_by_cp(v.out_name_c, v.pref.out_name)or{ os.mv_by_cp(v.out_name_c, v.pref.out_name) or {
panic(err) panic(err)
} }
exit(0) exit(0)
@ -88,14 +85,16 @@ fn (v mut Builder) cc() {
} }
} }
// arguments for the C compiler // arguments for the C compiler
mut a := [v.pref.cflags, '-std=gnu11', '-Wall', '-Wextra', mut a := [ v.pref.cflags, '-std=gnu11', '-Wall', '-Wextra',
// TODO : activate -Werror once no warnings remain // TODO : activate -Werror once no warnings remain
// '-Werror', // '-Werror',
// TODO : try and remove the below workaround options when the corresponding // TODO : try and remove the below workaround options when the corresponding
// warnings are totally fixed/removed // warnings are totally fixed/removed
'-Wno-unused-variable', '-Wno-unused-variable',
// '-Wno-unused-but-set-variable', // '-Wno-unused-but-set-variable',
'-Wno-unused-parameter', '-Wno-unused-result', '-Wno-unused-function', '-Wno-missing-braces', '-Wno-unused-label'] '-Wno-unused-parameter', '-Wno-unused-result', '-Wno-unused-function', '-Wno-missing-braces',
'-Wno-unused-label'
]
// TCC on Linux by default, unless -cc was provided // TCC on Linux by default, unless -cc was provided
// TODO if -cc = cc, TCC is still used, default compiler should be // TODO if -cc = cc, TCC is still used, default compiler should be
// used instead. // used instead.
@ -125,15 +124,10 @@ fn (v mut Builder) cc() {
verror('-fast is only supported on Linux right now') verror('-fast is only supported on Linux right now')
} }
} }
if !v.pref.is_shared && v.pref.build_mode != .build_module && os.user_os() == 'windows' &&
if !v.pref.is_shared !v.pref.out_name.ends_with('.exe') {
&& v.pref.build_mode != .build_module
&& os.user_os() == 'windows'
&& !v.pref.out_name.ends_with('.exe')
{
v.pref.out_name += '.exe' v.pref.out_name += '.exe'
} }
// linux_host := os.user_os() == 'linux' // linux_host := os.user_os() == 'linux'
v.log('cc() isprod=$v.pref.is_prod outname=$v.pref.out_name') v.log('cc() isprod=$v.pref.is_prod outname=$v.pref.out_name')
if v.pref.is_shared { if v.pref.is_shared {
@ -159,7 +153,7 @@ fn (v mut Builder) cc() {
mut guessed_compiler := v.pref.ccompiler mut guessed_compiler := v.pref.ccompiler
if guessed_compiler == 'cc' && v.pref.is_prod { if guessed_compiler == 'cc' && v.pref.is_prod {
// deliberately guessing only for -prod builds for performance reasons // deliberately guessing only for -prod builds for performance reasons
if ccversion:=os.exec('cc --version'){ if ccversion := os.exec('cc --version') {
if ccversion.exit_code == 0 { if ccversion.exit_code == 0 {
if ccversion.output.contains('This is free software;') && ccversion.output.contains('Free Software Foundation, Inc.') { if ccversion.output.contains('This is free software;') && ccversion.output.contains('Free Software Foundation, Inc.') {
guessed_compiler = 'gcc' guessed_compiler = 'gcc'
@ -172,8 +166,8 @@ fn (v mut Builder) cc() {
} }
// //
is_cc_clang := v.pref.ccompiler.contains('clang') || guessed_compiler == 'clang' is_cc_clang := v.pref.ccompiler.contains('clang') || guessed_compiler == 'clang'
is_cc_tcc := v.pref.ccompiler.contains('tcc') || guessed_compiler == 'tcc' is_cc_tcc := v.pref.ccompiler.contains('tcc') || guessed_compiler == 'tcc'
is_cc_gcc := v.pref.ccompiler.contains('gcc') || guessed_compiler == 'gcc' is_cc_gcc := v.pref.ccompiler.contains('gcc') || guessed_compiler == 'gcc'
// is_cc_msvc := v.pref.ccompiler.contains('msvc') || guessed_compiler == 'msvc' // is_cc_msvc := v.pref.ccompiler.contains('msvc') || guessed_compiler == 'msvc'
// //
if is_cc_clang { if is_cc_clang {
@ -221,8 +215,7 @@ fn (v mut Builder) cc() {
mut libs := '' // builtin.o os.o http.o etc mut libs := '' // builtin.o os.o http.o etc
if v.pref.build_mode == .build_module { if v.pref.build_mode == .build_module {
a << '-c' a << '-c'
} } else if v.pref.is_cache {
else if v.pref.is_cache {
/* /*
QTODO QTODO
builtin_o_path := os.join_path(pref.default_module_path, 'cache', 'vlib', 'builtin.o') builtin_o_path := os.join_path(pref.default_module_path, 'cache', 'vlib', 'builtin.o')
@ -268,7 +261,6 @@ fn (v mut Builder) cc() {
} }
*/ */
} }
if v.pref.sanitize { if v.pref.sanitize {
a << '-fsanitize=leak' a << '-fsanitize=leak'
} }
@ -289,7 +281,7 @@ fn (v mut Builder) cc() {
// Output executable name // Output executable name
a << '-o "$v.pref.out_name"' a << '-o "$v.pref.out_name"'
if os.is_dir(v.pref.out_name) { if os.is_dir(v.pref.out_name) {
verror("\'$v.pref.out_name\' is a directory") verror("'$v.pref.out_name' is a directory")
} }
// macOS code can include objective C TODO remove once objective C is replaced with C // macOS code can include objective C TODO remove once objective C is replaced with C
if v.pref.os == .mac { if v.pref.os == .mac {
@ -313,9 +305,8 @@ fn (v mut Builder) cc() {
// add all flags (-I -l -L etc) not .o files // add all flags (-I -l -L etc) not .o files
a << cflags.c_options_without_object_files() a << cflags.c_options_without_object_files()
a << libs a << libs
if v.pref.is_cache { if v.pref.is_cache {
cached_files := ['builtin.o', 'math.o'] cached_files := [ 'builtin.o', 'math.o']
for cfile in cached_files { for cfile in cached_files {
ofile := os.join_path(pref.default_module_path, 'cache', 'vlib', cfile) ofile := os.join_path(pref.default_module_path, 'cache', 'vlib', cfile)
if os.exists(ofile) { if os.exists(ofile) {
@ -328,10 +319,10 @@ fn (v mut Builder) cc() {
} }
} }
} }
// Without these libs compilation will fail on Linux // Without these libs compilation will fail on Linux
// || os.user_os() == 'linux' // || os.user_os() == 'linux'
if !v.pref.is_bare && v.pref.build_mode != .build_module && v.pref.os in [.linux, .freebsd, .openbsd, .netbsd, .dragonfly, .solaris, .haiku] { if !v.pref.is_bare && v.pref.build_mode != .build_module && v.pref.os in [ .linux, .freebsd,
.openbsd, .netbsd, .dragonfly, .solaris, .haiku] {
a << '-lm -lpthread ' a << '-lm -lpthread '
// -ldl is a Linux only thing. BSDs have it in libc. // -ldl is a Linux only thing. BSDs have it in libc.
if v.pref.os == .linux { if v.pref.os == .linux {
@ -346,7 +337,7 @@ fn (v mut Builder) cc() {
a << '-lm' a << '-lm'
} }
args := a.join(' ') args := a.join(' ')
start: start:
todo() todo()
// TODO remove // TODO remove
cmd := '${v.pref.ccompiler} $args' cmd := '${v.pref.ccompiler} $args'
@ -356,7 +347,7 @@ start:
println(cmd) println(cmd)
} }
ticks := time.ticks() ticks := time.ticks()
res := os.exec(cmd)or{ res := os.exec(cmd) or {
// C compilation failed. // C compilation failed.
// If we are on Windows, try msvc // If we are on Windows, try msvc
println('C compilation failed.') println('C compilation failed.')
@ -367,7 +358,6 @@ start:
return return
} }
*/ */
verror(err) verror(err)
return return
} }
@ -381,7 +371,9 @@ start:
goto start goto start
} }
} }
verror('C compiler error, while attempting to run: \n' + '-----------------------------------------------------------\n' + '$cmd\n' + '-----------------------------------------------------------\n' + 'Probably your C compiler is missing. \n' + 'Please reinstall it, or make it available in your PATH.\n\n' + missing_compiler_info()) verror('C compiler error, while attempting to run: \n' + '-----------------------------------------------------------\n' +
'$cmd\n' + '-----------------------------------------------------------\n' + 'Probably your C compiler is missing. \n' +
'Please reinstall it, or make it available in your PATH.\n\n' + missing_compiler_info())
} }
if v.pref.is_debug { if v.pref.is_debug {
eword := 'error:' eword := 'error:'
@ -399,12 +391,11 @@ If you were not working with C interop and are not sure about what's happening,
please put the whole output in a pastebin and contact us through the following ways with a link to the pastebin: please put the whole output in a pastebin and contact us through the following ways with a link to the pastebin:
- Raise an issue on GitHub: https://github.com/vlang/v/issues/new/choose - Raise an issue on GitHub: https://github.com/vlang/v/issues/new/choose
- Ask a question in #help on Discord: https://discord.gg/vlang") - Ask a question in #help on Discord: https://discord.gg/vlang")
} } else {
else {
if res.output.len < 30 { if res.output.len < 30 {
println(res.output) println(res.output)
} else { } else {
elines := error_context_lines( res.output, 'error:', 1, 12 ) elines := error_context_lines(res.output, 'error:', 1, 12)
println('==================') println('==================')
for eline in elines { for eline in elines {
println(eline) println(eline)
@ -451,7 +442,6 @@ If you're confident that all of the above is true, please try running V with the
println('linux cross compilation done. resulting binary: "$v.out_name"') println('linux cross compilation done. resulting binary: "$v.out_name"')
} }
*/ */
if !v.pref.is_keep_c && v.out_name_c != 'v.c' { if !v.pref.is_keep_c && v.out_name_c != 'v.c' {
os.rm(v.out_name_c) os.rm(v.out_name_c)
} }
@ -486,7 +476,7 @@ If you're confident that all of the above is true, please try running V with the
} }
} }
fn (c mut Builder) cc_windows_cross() { fn (mut c Builder) cc_windows_cross() {
/* /*
QTODO QTODO
println('Cross compiling for Windows...') println('Cross compiling for Windows...')
@ -568,8 +558,7 @@ fn (c &Builder) build_thirdparty_obj_files() {
rest_of_module_flags := c.get_rest_of_module_cflags(flag) rest_of_module_flags := c.get_rest_of_module_cflags(flag)
if c.pref.ccompiler == 'msvc' || c.no_cc_installed() { if c.pref.ccompiler == 'msvc' || c.no_cc_installed() {
build_thirdparty_obj_file_with_msvc(flag.value, rest_of_module_flags) build_thirdparty_obj_file_with_msvc(flag.value, rest_of_module_flags)
} } else {
else {
c.build_thirdparty_obj_file(flag.value, rest_of_module_flags) c.build_thirdparty_obj_file(flag.value, rest_of_module_flags)
} }
} }
@ -583,7 +572,7 @@ fn (v &Builder) build_thirdparty_obj_file(path string, moduleflags []cflag.CFlag
} }
println('$obj_path not found, building it...') println('$obj_path not found, building it...')
parent := os.dir(obj_path) parent := os.dir(obj_path)
files := os.ls(parent)or{ files := os.ls(parent) or {
panic(err) panic(err)
} }
mut cfiles := '' mut cfiles := ''
@ -595,7 +584,7 @@ fn (v &Builder) build_thirdparty_obj_file(path string, moduleflags []cflag.CFlag
btarget := moduleflags.c_options_before_target() btarget := moduleflags.c_options_before_target()
atarget := moduleflags.c_options_after_target() atarget := moduleflags.c_options_after_target()
cmd := '$v.pref.ccompiler $v.pref.third_party_option $btarget -c -o "$obj_path" $cfiles $atarget ' cmd := '$v.pref.ccompiler $v.pref.third_party_option $btarget -c -o "$obj_path" $cfiles $atarget '
res := os.exec(cmd)or{ res := os.exec(cmd) or {
println('failed thirdparty object build cmd: $cmd') println('failed thirdparty object build cmd: $cmd')
verror(err) verror(err)
return return

View File

@ -36,4 +36,3 @@ fn (v &Builder) get_rest_of_module_cflags(c &cflag.CFlag) []cflag.CFlag {
} }
return flags return flags
} }

View File

@ -3,13 +3,11 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module builder module builder
import ( import benchmark
benchmark import os
os import v.pref
v.pref import v.util
v.util import strings
strings
)
fn get_vtmp_folder() string { fn get_vtmp_folder() string {
vtmp := os.join_path(os.temp_dir(), 'v') vtmp := os.join_path(os.temp_dir(), 'v')
@ -35,9 +33,15 @@ pub fn compile(command string, pref &pref.Preferences) {
} }
mut tmark := benchmark.new_benchmark() mut tmark := benchmark.new_benchmark()
match pref.backend { match pref.backend {
.c { b.compile_c() } .c {
.js { b.compile_js() } b.compile_c()
.x64 { b.compile_x64() } }
.js {
b.compile_js()
}
.x64 {
b.compile_x64()
}
else { else {
eprintln('backend not implemented `$pref.backend`') eprintln('backend not implemented `$pref.backend`')
exit(1) exit(1)
@ -53,7 +57,7 @@ pub fn compile(command string, pref &pref.Preferences) {
// v.finalize_compilation() // v.finalize_compilation()
} }
fn (b mut Builder) run_compiled_executable_and_exit() { fn (mut b Builder) run_compiled_executable_and_exit() {
if b.pref.is_verbose { if b.pref.is_verbose {
println('============ running $b.pref.out_name ============') println('============ running $b.pref.out_name ============')
} }
@ -88,7 +92,7 @@ fn (b mut Builder) run_compiled_executable_and_exit() {
// 'strings' => 'VROOT/vlib/strings' // 'strings' => 'VROOT/vlib/strings'
// 'installed_mod' => '~/.vmodules/installed_mod' // 'installed_mod' => '~/.vmodules/installed_mod'
// 'local_mod' => '/path/to/current/dir/local_mod' // 'local_mod' => '/path/to/current/dir/local_mod'
fn (v mut Builder) set_module_lookup_paths() { fn (mut v Builder) set_module_lookup_paths() {
// Module search order: // Module search order:
// 0) V test files are very commonly located right inside the folder of the // 0) V test files are very commonly located right inside the folder of the
// module, which they test. Adding the parent folder of the module folder // module, which they test. Adding the parent folder of the module folder
@ -103,7 +107,7 @@ fn (v mut Builder) set_module_lookup_paths() {
// 3.2) search in ~/.vmodules/ (i.e. modules installed with vpm) // 3.2) search in ~/.vmodules/ (i.e. modules installed with vpm)
v.module_search_paths = [] v.module_search_paths = []
if v.pref.is_test { if v.pref.is_test {
v.module_search_paths << os.base_dir(v.compiled_dir) // pdir of _test.v v.module_search_paths << os.base_dir(v.compiled_dir) // pdir of _test.v
} }
v.module_search_paths << v.compiled_dir v.module_search_paths << v.compiled_dir
x := os.join_path(v.compiled_dir, 'modules') x := os.join_path(v.compiled_dir, 'modules')
@ -119,7 +123,7 @@ fn (v mut Builder) set_module_lookup_paths() {
} }
pub fn (v Builder) get_builtin_files() []string { pub fn (v Builder) get_builtin_files() []string {
if v.pref.build_mode == .build_module && v.pref.path == 'vlib/builtin' { // .contains('builtin/' + location { if v.pref.build_mode == .build_module && v.pref.path == 'vlib/builtin' { // .contains('builtin/' + location {
// We are already building builtin.o, no need to import them again // We are already building builtin.o, no need to import them again
if v.pref.is_verbose { if v.pref.is_verbose {
println('skipping builtin modules for builtin.o') println('skipping builtin modules for builtin.o')

View File

@ -1,15 +1,13 @@
module builder module builder
import ( import time
time import os
os import v.parser
v.parser import v.pref
v.pref import v.gen
v.gen import v.gen.js
v.gen.js
)
pub fn (b mut Builder) gen_js(v_files []string) string { pub fn (mut b Builder) gen_js(v_files []string) string {
t0 := time.ticks() t0 := time.ticks()
b.parsed_files = parser.parse_files(v_files, b.table, b.pref, b.global_scope) b.parsed_files = parser.parse_files(v_files, b.table, b.pref, b.global_scope)
b.parse_imports() b.parse_imports()
@ -30,7 +28,7 @@ pub fn (b mut Builder) gen_js(v_files []string) string {
return res return res
} }
pub fn (b mut Builder) build_js(v_files []string, out_file string) { pub fn (mut b Builder) build_js(v_files []string, out_file string) {
b.out_name_js = out_file b.out_name_js = out_file
b.info('build_js($out_file)') b.info('build_js($out_file)')
mut f := os.create(out_file) or { mut f := os.create(out_file) or {
@ -40,8 +38,8 @@ pub fn (b mut Builder) build_js(v_files []string, out_file string) {
f.close() f.close()
} }
pub fn (b mut Builder) compile_js() { pub fn (mut b Builder) compile_js() {
//TODO files << b.get_builtin_files() // TODO files << b.get_builtin_files()
files := b.get_user_files() files := b.get_user_files()
b.set_module_lookup_paths() b.set_module_lookup_paths()
if b.pref.is_verbose { if b.pref.is_verbose {
@ -49,5 +47,5 @@ pub fn (b mut Builder) compile_js() {
println(files) println(files)
} }
b.build_js(files, b.pref.out_name + '.js') b.build_js(files, b.pref.out_name + '.js')
//TODO run the file // TODO run the file
} }

View File

@ -1,9 +1,7 @@
module builder module builder
import ( import os
os import time
time
)
fn (v &Builder) generate_hotcode_reloading_declarations() { fn (v &Builder) generate_hotcode_reloading_declarations() {
/* /*

View File

@ -1,15 +1,13 @@
module builder module builder
import ( import time
time import os
os import v.parser
v.parser import v.pref
v.pref import v.gen
v.gen import v.gen.x64
v.gen.x64
)
pub fn (b mut Builder) build_x64(v_files []string, out_file string) { pub fn (mut b Builder) build_x64(v_files []string, out_file string) {
$if !linux { $if !linux {
println('v -x64 can only generate Linux binaries for now') println('v -x64 can only generate Linux binaries for now')
println('You are not on a Linux system, so you will not ' + 'be able to run the resulting executable') println('You are not on a Linux system, so you will not ' + 'be able to run the resulting executable')
@ -30,9 +28,9 @@ pub fn (b mut Builder) build_x64(v_files []string, out_file string) {
b.info('x64 GEN: ${gen_time}ms') b.info('x64 GEN: ${gen_time}ms')
} }
pub fn (b mut Builder) compile_x64() { pub fn (mut b Builder) compile_x64() {
// v.files << v.v_files_from_dir(os.join_path(v.pref.vlib_path,'builtin','bare')) // v.files << v.v_files_from_dir(os.join_path(v.pref.vlib_path,'builtin','bare'))
files := [b.pref.path] files := [ b.pref.path]
b.set_module_lookup_paths() b.set_module_lookup_paths()
b.build_x64(files, b.pref.out_name) b.build_x64(files, b.pref.out_name)
} }

View File

@ -3,16 +3,14 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module checker module checker
import ( import v.ast
v.ast import v.depgraph
v.depgraph import v.table
v.table import v.token
v.token import v.pref
v.pref import v.util
v.util import v.scanner
v.scanner import os
os
)
const ( const (
max_nr_errors = 300 max_nr_errors = 300
@ -35,7 +33,7 @@ mut:
// checked_ident string // to avoid infinit checker loops // checked_ident string // to avoid infinit checker loops
var_decl_name string var_decl_name string
returns bool returns bool
mod string // current module name mod string // current module name
is_builtin_mod bool // are we in `builtin`? is_builtin_mod bool // are we in `builtin`?
} }
@ -46,14 +44,14 @@ pub fn new_checker(table &table.Table, pref &pref.Preferences) Checker {
} }
} }
pub fn (c mut Checker) check(ast_file ast.File) { pub fn (mut c Checker) check(ast_file ast.File) {
c.file = ast_file c.file = ast_file
for stmt in ast_file.stmts { for stmt in ast_file.stmts {
c.stmt(stmt) c.stmt(stmt)
} }
} }
pub fn (c mut Checker) check2(ast_file ast.File) []scanner.Error { pub fn (mut c Checker) check2(ast_file ast.File) []scanner.Error {
c.file = ast_file c.file = ast_file
for stmt in ast_file.stmts { for stmt in ast_file.stmts {
c.stmt(stmt) c.stmt(stmt)
@ -61,7 +59,7 @@ pub fn (c mut Checker) check2(ast_file ast.File) []scanner.Error {
return c.errors return c.errors
} }
pub fn (c mut Checker) check_files(ast_files []ast.File) { pub fn (mut c Checker) check_files(ast_files []ast.File) {
mut has_main_fn := false mut has_main_fn := false
for file in ast_files { for file in ast_files {
c.check(file) c.check(file)
@ -90,7 +88,7 @@ const (
// do checks specific to files in main module // do checks specific to files in main module
// returns `true` if a main function is in the file // returns `true` if a main function is in the file
fn (c mut Checker) check_file_in_main(file ast.File) bool { fn (mut c Checker) check_file_in_main(file ast.File) bool {
mut has_main_fn := false mut has_main_fn := false
for stmt in file.stmts { for stmt in file.stmts {
match stmt { match stmt {
@ -122,7 +120,8 @@ fn (c mut Checker) check_file_in_main(file ast.File) bool {
} }
if it.ctdefine.len > 0 { if it.ctdefine.len > 0 {
if it.return_type != table.void_type { if it.return_type != table.void_type {
c.error('only functions that do NOT return values can have `[if ${it.ctdefine}]` tags', it.pos) c.error('only functions that do NOT return values can have `[if ${it.ctdefine}]` tags',
it.pos)
} }
} }
} }
@ -156,7 +155,7 @@ fn (c mut Checker) check_file_in_main(file ast.File) bool {
return has_main_fn return has_main_fn
} }
pub fn (c mut Checker) struct_decl(decl ast.StructDecl) { pub fn (mut c Checker) struct_decl(decl ast.StructDecl) {
splitted_full_name := decl.name.split('.') splitted_full_name := decl.name.split('.')
is_builtin := splitted_full_name[0] == 'builtin' is_builtin := splitted_full_name[0] == 'builtin'
name := splitted_full_name.last() name := splitted_full_name.last()
@ -168,28 +167,25 @@ pub fn (c mut Checker) struct_decl(decl ast.StructDecl) {
} }
c.error('struct name must begin with capital letter', pos) c.error('struct name must begin with capital letter', pos)
} }
for fi, _ in decl.fields { for fi, _ in decl.fields {
if decl.fields[fi].has_default_expr { if decl.fields[fi].has_default_expr {
c.expected_type = decl.fields[fi].typ c.expected_type = decl.fields[fi].typ
field_expr_type := c.expr(decl.fields[fi].default_expr) field_expr_type := c.expr(decl.fields[fi].default_expr)
if !c.table.check( field_expr_type, decl.fields[fi].typ ) { if !c.table.check(field_expr_type, decl.fields[fi].typ) {
field_expr_type_sym := c.table.get_type_symbol( field_expr_type ) field_expr_type_sym := c.table.get_type_symbol(field_expr_type)
field_type_sym := c.table.get_type_symbol( decl.fields[fi].typ ) field_type_sym := c.table.get_type_symbol(decl.fields[fi].typ)
field_name := decl.fields[fi].name field_name := decl.fields[fi].name
fet_name := field_expr_type_sym.name fet_name := field_expr_type_sym.name
ft_name := field_type_sym.name ft_name := field_type_sym.name
c.error('default expression for field `${field_name}` '+ c.error('default expression for field `${field_name}` ' + 'has type `${fet_name}`, but should be `${ft_name}`',
'has type `${fet_name}`, but should be `${ft_name}`', decl.fields[fi].default_expr.position())
decl.fields[fi].default_expr.position()
)
} }
} }
} }
// && (p.tok.lit[0].is_capital() || is_c || (p.builtin_mod && Sp.tok.lit in table.builtin_type_names)) // && (p.tok.lit[0].is_capital() || is_c || (p.builtin_mod && Sp.tok.lit in table.builtin_type_names))
} }
pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type { pub fn (mut c Checker) struct_init(struct_init mut ast.StructInit) table.Type {
// typ := c.table.find_type(struct_init.typ.typ.name) or { // typ := c.table.find_type(struct_init.typ.typ.name) or {
// c.error('unknown struct: $struct_init.typ.typ.name', struct_init.pos) // c.error('unknown struct: $struct_init.typ.typ.name', struct_init.pos)
// panic('') // panic('')
@ -203,7 +199,6 @@ pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type {
struct_init.typ = c.expected_type struct_init.typ = c.expected_type
} }
type_sym := c.table.get_type_symbol(struct_init.typ) type_sym := c.table.get_type_symbol(struct_init.typ)
// println('check struct $typ_sym.name') // println('check struct $typ_sym.name')
match type_sym.kind { match type_sym.kind {
.placeholder { .placeholder {
@ -239,7 +234,8 @@ pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type {
} }
} }
if !exists { if !exists {
c.error('unknown field `$field.name` in struct literal of type `$type_sym.name`', field.pos) c.error('unknown field `$field.name` in struct literal of type `$type_sym.name`',
field.pos)
continue continue
} }
if field_name in inited_fields { if field_name in inited_fields {
@ -253,7 +249,8 @@ pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type {
expr_type_sym := c.table.get_type_symbol(expr_type) expr_type_sym := c.table.get_type_symbol(expr_type)
field_type_sym := c.table.get_type_symbol(info_field.typ) field_type_sym := c.table.get_type_symbol(info_field.typ)
if !c.table.check(expr_type, info_field.typ) { if !c.table.check(expr_type, info_field.typ) {
c.error('cannot assign `$expr_type_sym.name` as `$field_type_sym.name` for field `$info_field.name`', field.pos) c.error('cannot assign `$expr_type_sym.name` as `$field_type_sym.name` for field `$info_field.name`',
field.pos)
} }
struct_init.fields[i].typ = expr_type struct_init.fields[i].typ = expr_type
struct_init.fields[i].expected_type = info_field.typ struct_init.fields[i].expected_type = info_field.typ
@ -274,7 +271,7 @@ pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type {
return struct_init.typ return struct_init.typ
} }
pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type { pub fn (mut c Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
// println('checker: infix expr(op $infix_expr.op.str())') // println('checker: infix expr(op $infix_expr.op.str())')
c.expected_type = table.void_type c.expected_type = table.void_type
left_type := c.expr(infix_expr.left) left_type := c.expr(infix_expr.left)
@ -318,12 +315,14 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
if right.kind == .array { if right.kind == .array {
right_sym := c.table.get_type_symbol(right.array_info().elem_type) right_sym := c.table.get_type_symbol(right.array_info().elem_type)
if left.kind != right_sym.kind { if left.kind != right_sym.kind {
c.error('the data type on the left of `in` does not match the array item type', infix_expr.pos) c.error('the data type on the left of `in` does not match the array item type',
infix_expr.pos)
} }
} else if right.kind == .map { } else if right.kind == .map {
key_sym := c.table.get_type_symbol(right.map_info().key_type) key_sym := c.table.get_type_symbol(right.map_info().key_type)
if left.kind != key_sym.kind { if left.kind != key_sym.kind {
c.error('the data type on the left of `in` does not match the map key type', infix_expr.pos) c.error('the data type on the left of `in` does not match the map key type',
infix_expr.pos)
} }
} else if right.kind == .string { } else if right.kind == .string {
if left.kind != .string { if left.kind != .string {
@ -336,10 +335,11 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
} }
if infix_expr.op in [.amp, .pipe, .xor] { if infix_expr.op in [.amp, .pipe, .xor] {
if !left.is_int() { if !left.is_int() {
c.error('left type of `${infix_expr.op.str()}` cannot be non-integer type $left.name', infix_expr.left.position()) c.error('left type of `${infix_expr.op.str()}` cannot be non-integer type $left.name',
} infix_expr.left.position())
else if !right.is_int() { } else if !right.is_int() {
c.error('right type of `${infix_expr.op.str()}` cannot be non-integer type $right.name', infix_expr.right.position()) c.error('right type of `${infix_expr.op.str()}` cannot be non-integer type $right.name',
infix_expr.right.position())
} }
} }
if infix_expr.op == .mod { if infix_expr.op == .mod {
@ -376,7 +376,8 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
if left_type == table.void_type || right_type == table.void_type { if left_type == table.void_type || right_type == table.void_type {
return table.void_type return table.void_type
} }
c.error('infix expr: cannot use `$right.name` (right expression) as `$left.name`', infix_expr.pos) c.error('infix expr: cannot use `$right.name` (right expression) as `$left.name`',
infix_expr.pos)
} }
if infix_expr.op.is_relational() { if infix_expr.op.is_relational() {
return table.bool_type return table.bool_type
@ -384,7 +385,7 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
return left_type return left_type
} }
fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) { fn (mut c Checker) assign_expr(assign_expr mut ast.AssignExpr) {
c.expected_type = table.void_type c.expected_type = table.void_type
left_type := c.expr(assign_expr.left) left_type := c.expr(assign_expr.left)
c.expected_type = left_type c.expected_type = left_type
@ -402,7 +403,8 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) {
scope := c.file.scope.innermost(assign_expr.pos.pos) scope := c.file.scope.innermost(assign_expr.pos.pos)
if v := scope.find_var(it.name) { if v := scope.find_var(it.name) {
if !v.is_mut { if !v.is_mut {
c.error('`$it.name` is immutable, declare it with `mut` to assign to it', assign_expr.pos) c.error('`$it.name` is immutable, declare it with `mut` to assign to it',
assign_expr.pos)
} }
} }
} }
@ -410,40 +412,40 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) {
} }
// Single side check // Single side check
match assign_expr.op { match assign_expr.op {
.assign { } // No need to do single side check for =. But here put it first for speed. .assign {} // No need to do single side check for =. But here put it first for speed.
.plus_assign { .plus_assign {
if !left.is_number() && left_type != table.string_type && !left.is_pointer() { if !left.is_number() && left_type != table.string_type && !left.is_pointer() {
c.error('operator += not defined on left operand type `$left.name`', assign_expr.left.position()) c.error('operator += not defined on left operand type `$left.name`', assign_expr.left.position())
} } else if !right.is_number() && right_type != table.string_type && !right.is_pointer() {
else if !right.is_number() && right_type != table.string_type && !right.is_pointer() {
c.error('operator += not defined on right operand type `$right.name`', assign_expr.val.position()) c.error('operator += not defined on right operand type `$right.name`', assign_expr.val.position())
} }
} }
.minus_assign { .minus_assign {
if !left.is_number() && !left.is_pointer() { if !left.is_number() && !left.is_pointer() {
c.error('operator -= not defined on left operand type `$left.name`', assign_expr.left.position()) c.error('operator -= not defined on left operand type `$left.name`', assign_expr.left.position())
} } else if !right.is_number() && !right.is_pointer() {
else if !right.is_number() && !right.is_pointer() {
c.error('operator -= not defined on right operand type `$right.name`', assign_expr.val.position()) c.error('operator -= not defined on right operand type `$right.name`', assign_expr.val.position())
} }
} }
.mult_assign, .div_assign { .mult_assign, .div_assign {
if !left.is_number() { if !left.is_number() {
c.error('operator ${assign_expr.op.str()} not defined on left operand type `$left.name`', assign_expr.left.position()) c.error('operator ${assign_expr.op.str()} not defined on left operand type `$left.name`',
} assign_expr.left.position())
else if !right.is_number() { } else if !right.is_number() {
c.error('operator ${assign_expr.op.str()} not defined on right operand type `$right.name`', assign_expr.val.position()) c.error('operator ${assign_expr.op.str()} not defined on right operand type `$right.name`',
assign_expr.val.position())
} }
} }
.and_assign, .or_assign, .xor_assign, .mod_assign, .left_shift_assign, .right_shift_assign { .and_assign, .or_assign, .xor_assign, .mod_assign, .left_shift_assign, .right_shift_assign {
if !left.is_int() { if !left.is_int() {
c.error('operator ${assign_expr.op.str()} not defined on left operand type `$left.name`', assign_expr.left.position()) c.error('operator ${assign_expr.op.str()} not defined on left operand type `$left.name`',
} assign_expr.left.position())
else if !right.is_int() { } else if !right.is_int() {
c.error('operator ${assign_expr.op.str()} not defined on right operand type `$right.name`', assign_expr.val.position()) c.error('operator ${assign_expr.op.str()} not defined on right operand type `$right.name`',
assign_expr.val.position())
} }
} }
else { } else {}
} }
// Dual sides check (compatibility check) // Dual sides check (compatibility check)
if !c.table.check(right_type, left_type) { if !c.table.check(right_type, left_type) {
@ -455,7 +457,7 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) {
c.check_expr_opt_call(assign_expr.val, right_type, true) c.check_expr_opt_call(assign_expr.val, right_type, true)
} }
pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type { pub fn (mut c Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
c.stmts(call_expr.or_block.stmts) c.stmts(call_expr.or_block.stmts)
if call_expr.is_method { if call_expr.is_method {
return c.call_method(call_expr) return c.call_method(call_expr)
@ -463,7 +465,7 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
return c.call_fn(call_expr) return c.call_fn(call_expr)
} }
pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type { pub fn (mut c Checker) call_method(call_expr mut ast.CallExpr) table.Type {
left_type := c.expr(call_expr.left) left_type := c.expr(call_expr.left)
call_expr.left_type = left_type call_expr.left_type = left_type
left_type_sym := c.table.get_type_symbol(left_type) left_type_sym := c.table.get_type_symbol(left_type)
@ -496,16 +498,18 @@ pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type {
return info.elem_type return info.elem_type
} }
if method := c.table.type_find_method(left_type_sym, method_name) { if method := c.table.type_find_method(left_type_sym, method_name) {
if !method.is_pub && !c.is_builtin_mod && !c.pref.is_test && left_type_sym.mod != c.mod && left_type_sym.mod != '' { // method.mod != c.mod { if !method.is_pub && !c.is_builtin_mod && !c.pref.is_test && left_type_sym.mod != c.mod &&
left_type_sym.mod != '' { // method.mod != c.mod {
// If a private method is called outside of the module // If a private method is called outside of the module
// its receiver type is defined in, show an error. // its receiver type is defined in, show an error.
//println('warn $method_name lef.mod=$left_type_sym.mod c.mod=$c.mod') // println('warn $method_name lef.mod=$left_type_sym.mod c.mod=$c.mod')
c.error('method `${left_type_sym.name}.$method_name` is private', call_expr.pos) c.error('method `${left_type_sym.name}.$method_name` is private', call_expr.pos)
} }
if method.return_type == table.void_type && method.ctdefine.len > 0 && method.ctdefine !in c.pref.compile_defines { if method.return_type == table.void_type && method.ctdefine.len > 0 && method.ctdefine !in
c.pref.compile_defines {
call_expr.should_be_skipped = true call_expr.should_be_skipped = true
} }
nr_args := if method.args.len == 0 { 0 } else {method.args.len - 1} nr_args := if method.args.len == 0 { 0 } else { method.args.len - 1 }
min_required_args := method.args.len - if method.is_variadic && method.args.len > 1 { 2 } else { 1 } min_required_args := method.args.len - if method.is_variadic && method.args.len > 1 { 2 } else { 1 }
if call_expr.args.len < min_required_args { if call_expr.args.len < min_required_args {
c.error('too few arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $min_required_args)', c.error('too few arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $min_required_args)',
@ -528,7 +532,8 @@ pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type {
} }
arg_typ := c.expr(arg.expr) arg_typ := c.expr(arg.expr)
call_expr.args[i].typ = arg_typ call_expr.args[i].typ = arg_typ
if method.is_variadic && arg_typ.flag_is(.variadic) && call_expr.args.len-1 > i { if method.is_variadic && arg_typ.flag_is(.variadic) && call_expr.args.len - 1 >
i {
c.error('when forwarding a varg variable, it must be the final argument', call_expr.pos) c.error('when forwarding a varg variable, it must be the final argument', call_expr.pos)
} }
} }
@ -568,7 +573,7 @@ pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type {
return table.void_type return table.void_type
} }
pub fn (c mut Checker) call_fn(call_expr mut ast.CallExpr) table.Type { pub fn (mut c Checker) call_fn(call_expr mut ast.CallExpr) table.Type {
if call_expr.name == 'panic' { if call_expr.name == 'panic' {
c.returns = true c.returns = true
} }
@ -620,11 +625,9 @@ pub fn (c mut Checker) call_fn(call_expr mut ast.CallExpr) table.Type {
return table.void_type return table.void_type
} }
call_expr.return_type = f.return_type call_expr.return_type = f.return_type
if f.return_type == table.void_type && f.ctdefine.len > 0 && f.ctdefine !in c.pref.compile_defines { if f.return_type == table.void_type && f.ctdefine.len > 0 && f.ctdefine !in c.pref.compile_defines {
call_expr.should_be_skipped = true call_expr.should_be_skipped = true
} }
if f.is_c || call_expr.is_c || f.is_js || call_expr.is_js { if f.is_c || call_expr.is_c || f.is_js || call_expr.is_js {
for arg in call_expr.args { for arg in call_expr.args {
c.expr(arg.expr) c.expr(arg.expr)
@ -659,7 +662,7 @@ pub fn (c mut Checker) call_fn(call_expr mut ast.CallExpr) table.Type {
call_expr.args[i].typ = typ call_expr.args[i].typ = typ
typ_sym := c.table.get_type_symbol(typ) typ_sym := c.table.get_type_symbol(typ)
arg_typ_sym := c.table.get_type_symbol(arg.typ) arg_typ_sym := c.table.get_type_symbol(arg.typ)
if f.is_variadic && typ.flag_is(.variadic) && call_expr.args.len-1 > i { if f.is_variadic && typ.flag_is(.variadic) && call_expr.args.len - 1 > i {
c.error('when forwarding a varg variable, it must be the final argument', call_expr.pos) c.error('when forwarding a varg variable, it must be the final argument', call_expr.pos)
} }
if !c.table.check(typ, arg.typ) { if !c.table.check(typ, arg.typ) {
@ -683,7 +686,7 @@ pub fn (c mut Checker) call_fn(call_expr mut ast.CallExpr) table.Type {
return f.return_type return f.return_type
} }
pub fn (c mut Checker) check_expr_opt_call(x ast.Expr, xtype table.Type, is_return_used bool) { pub fn (mut c Checker) check_expr_opt_call(x ast.Expr, xtype table.Type, is_return_used bool) {
match x { match x {
ast.CallExpr { ast.CallExpr {
if it.return_type.flag_is(.optional) { if it.return_type.flag_is(.optional) {
@ -694,7 +697,7 @@ pub fn (c mut Checker) check_expr_opt_call(x ast.Expr, xtype table.Type, is_retu
} }
} }
pub fn (c mut Checker) check_or_block(call_expr mut ast.CallExpr, ret_type table.Type, is_ret_used bool) { pub fn (mut c Checker) check_or_block(call_expr mut ast.CallExpr, ret_type table.Type, is_ret_used bool) {
if !call_expr.or_block.is_used { if !call_expr.or_block.is_used {
c.error('${call_expr.name}() returns an option, but you missed to add an `or {}` block to it', c.error('${call_expr.name}() returns an option, but you missed to add an `or {}` block to it',
call_expr.pos) call_expr.pos)
@ -746,34 +749,22 @@ pub fn (c mut Checker) check_or_block(call_expr mut ast.CallExpr, ret_type table
fn is_expr_panic_or_exit(expr ast.Expr) bool { fn is_expr_panic_or_exit(expr ast.Expr) bool {
match expr { match expr {
ast.CallExpr { ast.CallExpr { return it.name in ['panic', 'exit'] }
return it.name in ['panic', 'exit'] else { return false }
}
else {
return false
}
} }
} }
// TODO: merge to check_or_block when v can handle it // TODO: merge to check_or_block when v can handle it
pub fn (c mut Checker) is_last_or_block_stmt_valid(stmt ast.Stmt) bool { pub fn (mut c Checker) is_last_or_block_stmt_valid(stmt ast.Stmt) bool {
return match stmt { return match stmt {
ast.Return { ast.Return { true }
true ast.BranchStmt { true }
} ast.ExprStmt { true }
ast.BranchStmt { else { false }
true
}
ast.ExprStmt {
true
}
else {
false
}
} }
} }
pub fn (c mut Checker) selector_expr(selector_expr mut ast.SelectorExpr) table.Type { pub fn (mut c Checker) selector_expr(selector_expr mut ast.SelectorExpr) table.Type {
typ := c.expr(selector_expr.expr) typ := c.expr(selector_expr.expr)
if typ == table.void_type_idx { if typ == table.void_type_idx {
c.error('unknown selector expression', selector_expr.pos) c.error('unknown selector expression', selector_expr.pos)
@ -801,7 +792,7 @@ pub fn (c mut Checker) selector_expr(selector_expr mut ast.SelectorExpr) table.T
} }
// TODO: non deferred // TODO: non deferred
pub fn (c mut Checker) return_stmt(return_stmt mut ast.Return) { pub fn (mut c Checker) return_stmt(return_stmt mut ast.Return) {
c.expected_type = c.fn_return_type c.expected_type = c.fn_return_type
if return_stmt.exprs.len > 0 && c.fn_return_type == table.void_type { if return_stmt.exprs.len > 0 && c.fn_return_type == table.void_type {
c.error('too many arguments to return, current function does not return anything', c.error('too many arguments to return, current function does not return anything',
@ -842,12 +833,13 @@ pub fn (c mut Checker) return_stmt(return_stmt mut ast.Return) {
got_typ_sym := c.table.get_type_symbol(got_typ) got_typ_sym := c.table.get_type_symbol(got_typ)
exp_typ_sym := c.table.get_type_symbol(exp_typ) exp_typ_sym := c.table.get_type_symbol(exp_typ)
pos := return_stmt.exprs[i].position() pos := return_stmt.exprs[i].position()
c.error('cannot use `$got_typ_sym.name` as type `$exp_typ_sym.name` in return argument', pos) c.error('cannot use `$got_typ_sym.name` as type `$exp_typ_sym.name` in return argument',
pos)
} }
} }
} }
pub fn (c mut Checker) enum_decl(decl ast.EnumDecl) { pub fn (mut c Checker) enum_decl(decl ast.EnumDecl) {
for field in decl.fields { for field in decl.fields {
if field.has_expr { if field.has_expr {
match field.expr { match field.expr {
@ -871,13 +863,14 @@ pub fn (c mut Checker) enum_decl(decl ast.EnumDecl) {
} }
} }
pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) { pub fn (mut c Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
c.expected_type = table.none_type // TODO a hack to make `x := if ... work` c.expected_type = table.none_type // TODO a hack to make `x := if ... work`
// check variablename for beginning with capital letter 'Abc' // check variablename for beginning with capital letter 'Abc'
for ident in assign_stmt.left { for ident in assign_stmt.left {
is_decl := assign_stmt.op == .decl_assign is_decl := assign_stmt.op == .decl_assign
if is_decl && scanner.contains_capital(ident.name) { if is_decl && scanner.contains_capital(ident.name) {
c.error('variable names cannot contain uppercase letters, use snake_case instead', ident.pos) c.error('variable names cannot contain uppercase letters, use snake_case instead',
ident.pos)
} else if is_decl && ident.kind != .blank_ident { } else if is_decl && ident.kind != .blank_ident {
if ident.name.starts_with('__') { if ident.name.starts_with('__') {
c.error('variable names cannot start with `__`', ident.pos) c.error('variable names cannot start with `__`', ident.pos)
@ -888,9 +881,7 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
// multi return // multi return
match assign_stmt.right[0] { match assign_stmt.right[0] {
ast.CallExpr {} ast.CallExpr {}
else { else { c.error('assign_stmt: expected call', assign_stmt.pos) }
c.error('assign_stmt: expected call', assign_stmt.pos)
}
} }
right_type := c.expr(assign_stmt.right[0]) right_type := c.expr(assign_stmt.right[0])
right_type_sym := c.table.get_type_symbol(right_type) right_type_sym := c.table.get_type_symbol(right_type)
@ -969,7 +960,7 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
// c.assigned_var_name = '' // c.assigned_var_name = ''
} }
pub fn (c mut Checker) array_init(array_init mut ast.ArrayInit) table.Type { pub fn (mut c Checker) array_init(array_init mut ast.ArrayInit) table.Type {
// println('checker: array init $array_init.pos.line_nr $c.file.path') // println('checker: array init $array_init.pos.line_nr $c.file.path')
mut elem_type := table.void_type mut elem_type := table.void_type
// []string - was set in parser // []string - was set in parser
@ -1056,15 +1047,13 @@ fn const_int_value(cfield ast.ConstField) ?int {
fn is_const_integer(cfield ast.ConstField) ?ast.IntegerLiteral { fn is_const_integer(cfield ast.ConstField) ?ast.IntegerLiteral {
match cfield.expr { match cfield.expr {
ast.IntegerLiteral { ast.IntegerLiteral { return *it }
return *it
}
else {} else {}
} }
return none return none
} }
fn (c mut Checker) stmt(node ast.Stmt) { fn (mut c Checker) stmt(node ast.Stmt) {
// c.expected_type = table.void_type // c.expected_type = table.void_type
match mut node { match mut node {
ast.AssertStmt { ast.AssertStmt {
@ -1151,8 +1140,8 @@ fn (c mut Checker) stmt(node ast.Stmt) {
c.expected_type = table.void_type c.expected_type = table.void_type
c.fn_return_type = it.return_type c.fn_return_type = it.return_type
c.stmts(it.stmts) c.stmts(it.stmts)
if !it.is_c && !it.is_js && !it.no_body && it.return_type != table.void_type && !c.returns && if !it.is_c && !it.is_js && !it.no_body && it.return_type != table.void_type &&
!(it.name in ['panic', 'exit']) { !c.returns && !(it.name in ['panic', 'exit']) {
c.error('missing return at end of function `$it.name`', it.pos) c.error('missing return at end of function `$it.name`', it.pos)
} }
c.returns = false c.returns = false
@ -1198,12 +1187,8 @@ fn (c mut Checker) stmt(node ast.Stmt) {
sym := c.table.get_type_symbol(typ) sym := c.table.get_type_symbol(typ)
if it.key_var.len > 0 { if it.key_var.len > 0 {
key_type := match sym.kind { key_type := match sym.kind {
.map { .map { sym.map_info().key_type }
sym.map_info().key_type else { table.int_type }
}
else {
table.int_type
}
} }
it.key_type = key_type it.key_type = key_type
scope.update_var_type(it.key_var, key_type) scope.update_var_type(it.key_var, key_type)
@ -1233,7 +1218,6 @@ fn (c mut Checker) stmt(node ast.Stmt) {
c.mod = it.name c.mod = it.name
c.is_builtin_mod = it.name == 'builtin' c.is_builtin_mod = it.name == 'builtin'
} }
// ast.GlobalDecl {} // ast.GlobalDecl {}
ast.Return { ast.Return {
c.returns = true c.returns = true
@ -1259,7 +1243,7 @@ fn is_call_expr(expr ast.Expr) bool {
} }
} }
fn (c mut Checker) stmts(stmts []ast.Stmt) { fn (mut c Checker) stmts(stmts []ast.Stmt) {
c.expected_type = table.void_type c.expected_type = table.void_type
for stmt in stmts { for stmt in stmts {
c.stmt(stmt) c.stmt(stmt)
@ -1267,7 +1251,7 @@ fn (c mut Checker) stmts(stmts []ast.Stmt) {
c.expected_type = table.void_type c.expected_type = table.void_type
} }
pub fn (c mut Checker) expr(node ast.Expr) table.Type { pub fn (mut c Checker) expr(node ast.Expr) table.Type {
match mut node { match mut node {
ast.ArrayInit { ast.ArrayInit {
return c.array_init(mut it) return c.array_init(mut it)
@ -1418,8 +1402,8 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
return table.void_type return table.void_type
} }
pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type { pub fn (mut c Checker) ident(ident mut ast.Ident) table.Type {
if ident.name == c.var_decl_name { // c.checked_ident { if ident.name == c.var_decl_name { // c.checked_ident {
c.error('unresolved: `$ident.name`', ident.pos) c.error('unresolved: `$ident.name`', ident.pos)
return table.void_type return table.void_type
} }
@ -1524,7 +1508,7 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type {
return table.void_type return table.void_type
} }
pub fn (c mut Checker) match_expr(node mut ast.MatchExpr) table.Type { pub fn (mut c Checker) match_expr(node mut ast.MatchExpr) table.Type {
node.is_expr = c.expected_type != table.void_type node.is_expr = c.expected_type != table.void_type
node.expected_type = c.expected_type node.expected_type = c.expected_type
cond_type := c.expr(node.cond) cond_type := c.expr(node.cond)
@ -1583,15 +1567,9 @@ fn (mut c Checker) match_exprs(node mut ast.MatchExpr, type_sym table.TypeSymbol
for expr in branch.exprs { for expr in branch.exprs {
mut key := '' mut key := ''
match expr { match expr {
ast.Type { ast.Type { key = c.table.type_to_str(it.typ) }
key = c.table.type_to_str(it.typ) ast.EnumVal { key = it.val }
} else { key = expr.str() }
ast.EnumVal {
key = it.val
}
else {
key = expr.str()
}
} }
val := if key in branch_exprs { branch_exprs[key] } else { 0 } val := if key in branch_exprs { branch_exprs[key] } else { 0 }
if val == 1 { if val == 1 {
@ -1646,7 +1624,7 @@ fn (mut c Checker) match_exprs(node mut ast.MatchExpr, type_sym table.TypeSymbol
} }
} }
pub fn (c mut Checker) if_expr(node mut ast.IfExpr) table.Type { pub fn (mut c Checker) if_expr(node mut ast.IfExpr) table.Type {
if c.expected_type != table.void_type { if c.expected_type != table.void_type {
// | c.assigned_var_name != '' { // | c.assigned_var_name != '' {
// sym := c.table.get_type_symbol(c.expected_type) // sym := c.table.get_type_symbol(c.expected_type)
@ -1656,7 +1634,8 @@ pub fn (c mut Checker) if_expr(node mut ast.IfExpr) table.Type {
node.typ = table.void_type node.typ = table.void_type
for i, branch in node.branches { for i, branch in node.branches {
if branch.cond is ast.ParExpr { if branch.cond is ast.ParExpr {
c.error('unnecessary `()` in an if condition. use `if expr {` instead of `if (expr) {`.', branch.pos) c.error('unnecessary `()` in an if condition. use `if expr {` instead of `if (expr) {`.',
branch.pos)
} }
typ := c.expr(branch.cond) typ := c.expr(branch.cond)
if i < node.branches.len - 1 || !node.has_else { if i < node.branches.len - 1 || !node.has_else {
@ -1686,7 +1665,7 @@ pub fn (c mut Checker) if_expr(node mut ast.IfExpr) table.Type {
return table.bool_type return table.bool_type
} }
pub fn (c mut Checker) postfix_expr(node ast.PostfixExpr) table.Type { pub fn (mut c Checker) postfix_expr(node ast.PostfixExpr) table.Type {
/* /*
match node.expr { match node.expr {
ast.IdentVar { ast.IdentVar {
@ -1694,7 +1673,7 @@ pub fn (c mut Checker) postfix_expr(node ast.PostfixExpr) table.Type {
} }
else {} else {}
} }
*/ */
typ := c.expr(node.expr) typ := c.expr(node.expr)
typ_sym := c.table.get_type_symbol(typ) typ_sym := c.table.get_type_symbol(typ)
// if !typ.is_number() { // if !typ.is_number() {
@ -1705,10 +1684,10 @@ pub fn (c mut Checker) postfix_expr(node ast.PostfixExpr) table.Type {
return typ return typ
} }
pub fn (c mut Checker) index_expr(node mut ast.IndexExpr) table.Type { pub fn (mut c Checker) index_expr(node mut ast.IndexExpr) table.Type {
typ := c.expr(node.left) typ := c.expr(node.left)
node.left_type = typ node.left_type = typ
mut is_range := false // TODO is_range := node.index is ast.RangeExpr mut is_range := false // TODO is_range := node.index is ast.RangeExpr
match node.index { match node.index {
ast.RangeExpr { ast.RangeExpr {
is_range = true is_range = true
@ -1754,10 +1733,10 @@ pub fn (c mut Checker) index_expr(node mut ast.IndexExpr) table.Type {
// `.green` or `Color.green` // `.green` or `Color.green`
// If a short form is used, `expected_type` needs to be an enum // If a short form is used, `expected_type` needs to be an enum
// with this value. // with this value.
pub fn (c mut Checker) enum_val(node mut ast.EnumVal) table.Type { pub fn (mut c Checker) enum_val(node mut ast.EnumVal) table.Type {
typ_idx := if node.enum_name == '' { typ_idx := if node.enum_name == '' {
c.expected_type.idx() c.expected_type.idx()
} else { // } else { //
c.table.find_type_idx(node.enum_name) c.table.find_type_idx(node.enum_name)
} }
// println('checker: enum_val: $node.enum_name typeidx=$typ_idx') // println('checker: enum_val: $node.enum_name typeidx=$typ_idx')
@ -1781,7 +1760,7 @@ pub fn (c mut Checker) enum_val(node mut ast.EnumVal) table.Type {
return typ return typ
} }
pub fn (c mut Checker) map_init(node mut ast.MapInit) table.Type { pub fn (mut c Checker) map_init(node mut ast.MapInit) table.Type {
// `x ;= map[string]string` - set in parser // `x ;= map[string]string` - set in parser
if node.typ != 0 { if node.typ != 0 {
info := c.table.get_type_symbol(node.typ).map_info() info := c.table.get_type_symbol(node.typ).map_info()
@ -1819,19 +1798,19 @@ pub fn (c mut Checker) map_init(node mut ast.MapInit) table.Type {
return map_type return map_type
} }
pub fn (c mut Checker) warn(s string, pos token.Position) { pub fn (mut c Checker) warn(s string, pos token.Position) {
allow_warnings := !c.pref.is_prod // allow warnings only in dev builds allow_warnings := !c.pref.is_prod // allow warnings only in dev builds
c.warn_or_error(s, pos, allow_warnings) // allow warnings only in dev builds c.warn_or_error(s, pos, allow_warnings) // allow warnings only in dev builds
} }
pub fn (c mut Checker) error(message string, pos token.Position) { pub fn (mut c Checker) error(message string, pos token.Position) {
if c.pref.is_verbose { if c.pref.is_verbose {
print_backtrace() print_backtrace()
} }
c.warn_or_error(message, pos, false) c.warn_or_error(message, pos, false)
} }
fn (c mut Checker) warn_or_error(message string, pos token.Position, warn bool) { fn (mut c Checker) warn_or_error(message string, pos token.Position, warn bool) {
// add backtrace to issue struct, how? // add backtrace to issue struct, how?
// if c.pref.is_verbose { // if c.pref.is_verbose {
// print_backtrace() // print_backtrace()

View File

@ -1,7 +1,5 @@
import ( import v.table
v.table import v.doc
v.doc
)
fn test_vdoc() { fn test_vdoc() {
table := table.new_table() table := table.new_table()

View File

@ -3,12 +3,10 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module eval module eval
import ( import v.ast
v.ast import v.checker
v.checker import v.table
v.table import v.pref
v.pref
)
pub type Object = int | string pub type Object = int | string
@ -23,7 +21,7 @@ pub struct Var {
value Object value Object
} }
pub fn (e mut Eval) eval(file ast.File, table &table.Table) string { pub fn (mut e Eval) eval(file ast.File, table &table.Table) string {
vpref := &pref.Preferences{} vpref := &pref.Preferences{}
e.table = table e.table = table
mut res := '' mut res := ''
@ -36,29 +34,24 @@ pub fn (e mut Eval) eval(file ast.File, table &table.Table) string {
fn print_object(o Object) { fn print_object(o Object) {
match o { match o {
int { int { println(it) }
println(it) else { println('unknown object') }
}
else {
println('unknown object')
}
} }
} }
pub fn (o Object) str() string { pub fn (o Object) str() string {
match o { match o {
int { int { return it.str() }
return it.str() else { println('unknown object') }
}
else {
println('unknown object')
}
} }
return '' return ''
} }
fn (e mut Eval) stmt(node ast.Stmt) string { fn (mut e Eval) stmt(node ast.Stmt) string {
match node { match node {
ast.AssignStmt {
// TODO; replaced VarDecl
}
ast.ExprStmt { ast.ExprStmt {
o := e.expr(it.expr) o := e.expr(it.expr)
print('out: ') print('out: ')
@ -66,22 +59,19 @@ fn (e mut Eval) stmt(node ast.Stmt) string {
return o.str() return o.str()
} }
// ast.StructDecl { // ast.StructDecl {
// println('s decl') // println('s decl')
// } // }
ast.AssignStmt {
// TODO; replaced VarDecl
}
// ast.VarDecl { // ast.VarDecl {
// e.vars[it.name] = Var{ // e.vars[it.name] = Var{
// value: e.expr(it.expr) // value: e.expr(it.expr)
// } // }
// } // }
else {} else {}
} }
return '>>' return '>>'
} }
fn (e mut Eval) expr(node ast.Expr) Object { fn (mut e Eval) expr(node ast.Expr) Object {
match node { match node {
ast.IntegerLiteral { ast.IntegerLiteral {
return it.val return it.val
@ -98,14 +88,10 @@ fn (e mut Eval) expr(node ast.Expr) Object {
left := e.expr(it.left) as int left := e.expr(it.left) as int
right := e.expr(it.right) as int right := e.expr(it.right) as int
match it.op { match it.op {
.plus { .plus { return left + right }
return left + right .mul { return left * right }
}
.mul {
return left * right
}
else {} else {}
} }
} }
else {} else {}
} }

View File

@ -106,7 +106,7 @@ fn (mut f Fmt) imports(imports []ast.Import) {
imp_stmt_str := f.imp_stmt_str(imports[0]) imp_stmt_str := f.imp_stmt_str(imports[0])
f.out_imports.writeln('import ${imp_stmt_str}\n') f.out_imports.writeln('import ${imp_stmt_str}\n')
} else if imports.len > 1 { } else if imports.len > 1 {
*/ */
// f.out_imports.writeln('import (') // f.out_imports.writeln('import (')
for imp in imports { for imp in imports {
if !(imp.mod in f.used_imports) { if !(imp.mod in f.used_imports) {
@ -247,23 +247,7 @@ fn (mut f Fmt) stmt(node ast.Stmt) {
} }
} }
ast.FnDecl { ast.FnDecl {
// println('$it.name find_comment($it.pos.line_nr)') f.fn_decl(it)
// f.find_comment(it.pos.line_nr)
s := it.str(f.table)
// f.write(it.str(f.table))
f.write(s.replace(f.cur_mod + '.', '')) // `Expr` instead of `ast.Expr` in mod ast
if !it.is_c && !it.is_js {
f.writeln(' {')
f.stmts(it.stmts)
f.writeln('}\n')
} else {
f.writeln('\n')
}
// Mark all function's used type so that they are not removed from imports
for arg in it.args {
f.mark_types_module_as_used(arg.typ)
}
f.mark_types_module_as_used(it.return_type)
} }
ast.ForCStmt { ast.ForCStmt {
f.write('for ') f.write('for ')
@ -320,6 +304,11 @@ fn (mut f Fmt) stmt(node ast.Stmt) {
f.expr(it.expr) f.expr(it.expr)
} }
} }
ast.GoStmt {
f.write('go ')
f.expr(it.call_expr)
f.writeln('')
}
ast.GotoLabel { ast.GotoLabel {
f.writeln('$it.name:') f.writeln('$it.name:')
} }
@ -374,12 +363,6 @@ fn (mut f Fmt) stmt(node ast.Stmt) {
f.stmts(it.stmts) f.stmts(it.stmts)
f.writeln('}') f.writeln('}')
} }
else {
eprintln('fmt stmt: unhandled node ' + typeof(node))
if typeof(node) != 'unknown v.ast.Expr' {
exit(1)
}
}
} }
} }
@ -460,15 +443,18 @@ fn (f &Fmt) type_to_str(t table.Type) string {
mut res := f.table.type_to_str(t) mut res := f.table.type_to_str(t)
// type_ptr => &type // type_ptr => &type
if res.ends_with('_ptr') { if res.ends_with('_ptr') {
res = res[0 .. res.len - 4] res = res[0..res.len - 4]
start_pos := 2 * res.count('[]') start_pos := 2 * res.count('[]')
res = res[0 .. start_pos] + '&' + res[start_pos .. res.len] res = res[0..start_pos] + '&' + res[start_pos..res.len]
} }
return res.replace(f.cur_mod + '.', '') return res.replace(f.cur_mod + '.', '')
} }
fn (mut f Fmt) expr(node ast.Expr) { fn (mut f Fmt) expr(node ast.Expr) {
match node { match node {
ast.AnonFn {
f.fn_decl(it.decl)
}
ast.ArrayInit { ast.ArrayInit {
if it.exprs.len == 0 && it.typ != 0 && it.typ != table.void_type { if it.exprs.len == 0 && it.typ != 0 && it.typ != table.void_type {
// `x := []string` // `x := []string`
@ -478,25 +464,29 @@ fn (mut f Fmt) expr(node ast.Expr) {
// type_sym := f.table.get_type_symbol(it.typ) // type_sym := f.table.get_type_symbol(it.typ)
f.write('[') f.write('[')
mut inc_indent := false mut inc_indent := false
mut line_nr := node.position().line_nr // to have the same newlines between array elements mut last_line_nr := node.position().line_nr // to have the same newlines between array elements
for i, expr in it.exprs { for i, expr in it.exprs {
pos := expr.position() line_nr := expr.position().line_nr
if i == 0 && line_nr < pos.line_nr { if last_line_nr < line_nr {
if !inc_indent {
f.indent++
inc_indent = true
}
f.writeln('') f.writeln('')
f.indent++
inc_indent = true
} }
if i > 0 && it.exprs.len > 1 { is_new_line := last_line_nr < line_nr || f.wrap_long_line()
f.wrap_long_line() if !is_new_line && i > 0 {
f.write(' ')
} }
f.expr(expr) f.expr(expr)
if line_nr < pos.line_nr { if i == it.exprs.len - 1 {
// Previous element was on a different line, add a newline if is_new_line {
f.writeln('') f.writeln('')
} else if i < it.exprs.len - 1 { }
f.write(', ') } else {
f.write(',')
} }
line_nr = pos.line_nr last_line_nr = line_nr
} }
if inc_indent { if inc_indent {
f.indent-- f.indent--
@ -541,6 +531,14 @@ fn (mut f Fmt) expr(node ast.Expr) {
ast.CharLiteral { ast.CharLiteral {
f.write('`$it.val`') f.write('`$it.val`')
} }
ast.ConcatExpr {
for i, val in it.vals {
if i != 0 {
f.write(' + ')
}
f.expr(val)
}
}
ast.EnumVal { ast.EnumVal {
name := short_module(it.enum_name) name := short_module(it.enum_name)
f.write(name + '.' + it.val) f.write(name + '.' + it.val)
@ -563,6 +561,10 @@ fn (mut f Fmt) expr(node ast.Expr) {
} }
} }
} }
ast.IfGuardExpr {
f.write(it.var_name + ' := ')
f.expr(it.expr)
}
ast.InfixExpr { ast.InfixExpr {
f.expr(it.left) f.expr(it.left)
f.write(' $it.op.str() ') f.write(' $it.op.str() ')
@ -606,9 +608,10 @@ fn (mut f Fmt) expr(node ast.Expr) {
ast.None { ast.None {
f.write('none') f.write('none')
} }
ast.IfGuardExpr { ast.OrExpr {
f.write(it.var_name + ' := ') // shouldn't happen, an or expression
f.expr(it.expr) // is always linked to a call expr
panic('fmt: OrExpr should to linked to CallExpr')
} }
ast.ParExpr { ast.ParExpr {
f.write('(') f.write('(')
@ -643,7 +646,7 @@ fn (mut f Fmt) expr(node ast.Expr) {
f.write(')') f.write(')')
} }
ast.StringLiteral { ast.StringLiteral {
if it.val.contains("'") { if it.val.contains("'") && !it.val.contains('"') {
f.write('"$it.val"') f.write('"$it.val"')
} else { } else {
f.write("'$it.val'") f.write("'$it.val'")
@ -708,23 +711,19 @@ fn (mut f Fmt) expr(node ast.Expr) {
f.expr(it.expr) f.expr(it.expr)
f.write(')') f.write(')')
} }
else {
eprintln('fmt expr: unhandled node ' + typeof(node))
if typeof(node) != 'unknown v.ast.Expr' {
exit(1)
}
}
} }
} }
fn (mut f Fmt) wrap_long_line() { fn (mut f Fmt) wrap_long_line() bool {
if f.line_len > max_len { if f.line_len <= max_len {
if f.out.buf[f.out.buf.len - 1] == ` ` { return false
f.out.go_back(1)
}
f.write('\n' + tabs[f.indent + 1])
f.line_len = 0
} }
if f.out.buf[f.out.buf.len - 1] == ` ` {
f.out.go_back(1)
}
f.write('\n' + tabs[f.indent + 1])
f.line_len = 0
return true
} }
fn (mut f Fmt) call_args(args []ast.CallArg) { fn (mut f Fmt) call_args(args []ast.CallArg) {
@ -743,7 +742,7 @@ fn (mut f Fmt) call_args(args []ast.CallArg) {
} }
fn (mut f Fmt) or_expr(or_block ast.OrExpr) { fn (mut f Fmt) or_expr(or_block ast.OrExpr) {
if or_block.stmts.len > 0 { if or_block.is_used {
f.writeln(' or {') f.writeln(' or {')
f.stmts(or_block.stmts) f.stmts(or_block.stmts)
f.write('}') f.write('}')
@ -772,9 +771,32 @@ fn (mut f Fmt) comment(node ast.Comment) {
f.writeln(line) f.writeln(line)
f.empty_line = false f.empty_line = false
} }
f.empty_line = true
f.writeln('*/') f.writeln('*/')
} }
fn (mut f Fmt) fn_decl(node ast.FnDecl) {
// println('$it.name find_comment($it.pos.line_nr)')
// f.find_comment(it.pos.line_nr)
s := node.str(f.table)
f.write(s.replace(f.cur_mod + '.', '')) // `Expr` instead of `ast.Expr` in mod ast
if !node.is_c && !node.is_js {
f.writeln(' {')
f.stmts(node.stmts)
f.write('}')
if !node.is_anon {
f.writeln('\n')
}
} else {
f.writeln('\n')
}
// Mark all function's used type so that they are not removed from imports
for arg in node.args {
f.mark_types_module_as_used(arg.typ)
}
f.mark_types_module_as_used(node.return_type)
}
// foo.bar.fn() => bar.fn() // foo.bar.fn() => bar.fn()
fn short_module(name string) string { fn short_module(name string) string {
if !name.contains('.') { if !name.contains('.') {
@ -822,25 +844,23 @@ fn (mut f Fmt) if_expr(it ast.IfExpr) {
fn (mut f Fmt) call_expr(node ast.CallExpr) { fn (mut f Fmt) call_expr(node ast.CallExpr) {
if node.is_method { if node.is_method {
match node.left { if node.left is ast.Ident {
ast.Ident { it := node.left as ast.Ident
// `time.now()` without `time imported` is processed as a method call with `time` being // `time.now()` without `time imported` is processed as a method call with `time` being
// a `node.left` expression. Import `time` automatically. // a `node.left` expression. Import `time` automatically.
// TODO fetch all available modules // TODO fetch all available modules
if it.name in ['time', 'os', 'strings', 'math', 'json', 'base64'] { if it.name in ['time', 'os', 'strings', 'math', 'json', 'base64'] {
if !(it.name in f.auto_imports) { if !(it.name in f.auto_imports) {
f.auto_imports << it.name f.auto_imports << it.name
f.file.imports << ast.Import{ f.file.imports << ast.Import{
mod: it.name mod: it.name
alias: it.name alias: it.name
}
} }
// for imp in f.file.imports {
// println(imp.mod)
// }
} }
// for imp in f.file.imports {
// println(imp.mod)
// }
} }
else {}
} }
f.expr(node.left) f.expr(node.left)
f.write('.' + node.name + '(') f.write('.' + node.name + '(')
@ -882,6 +902,9 @@ fn (mut f Fmt) match_expr(it ast.MatchExpr) {
single_line = false single_line = false
break break
} }
} else if stmt is ast.Comment {
single_line = false
break
} }
} }
for i, branch in it.branches { for i, branch in it.branches {

View File

@ -1,13 +1,11 @@
import ( import os
os import term
term import benchmark
benchmark import v.ast
v.ast import v.fmt
v.fmt import v.parser
v.parser import v.table
v.table import v.pref
v.pref
)
const ( const (
error_missing_vexe = 1 error_missing_vexe = 1
@ -45,7 +43,9 @@ fn test_fmt() {
continue continue
} }
table := table.new_table() table := table.new_table()
file_ast := parser.parse_file(ipath, table, .parse_comments, &pref.Preferences{}, &ast.Scope{parent: 0}) file_ast := parser.parse_file(ipath, table, .parse_comments, &pref.Preferences{}, &ast.Scope{
parent: 0
})
result_ocontent := fmt.fmt(file_ast, table) result_ocontent := fmt.fmt(file_ast, table)
if expected_ocontent != result_ocontent { if expected_ocontent != result_ocontent {
fmt_bench.fail() fmt_bench.fail()
@ -54,7 +54,7 @@ fn test_fmt() {
eprintln('>> sorry, but no working "diff" CLI command can be found') eprintln('>> sorry, but no working "diff" CLI command can be found')
continue 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) os.write_file(vfmt_result_file, result_ocontent)
os.system('$diff_cmd --minimal --text --unified=2 --show-function-line="fn " "$opath" "$vfmt_result_file"') os.system('$diff_cmd --minimal --text --unified=2 --show-function-line="fn " "$opath" "$vfmt_result_file"')
continue continue

View File

@ -1,13 +1,11 @@
import ( import os
os import term
term import benchmark
benchmark import v.ast
v.ast import v.fmt
v.fmt import v.parser
v.parser import v.table
v.table import v.pref
v.pref
)
const ( const (
error_missing_vexe = 1 error_missing_vexe = 1
@ -47,7 +45,9 @@ fn test_fmt() {
continue continue
} }
table := table.new_table() table := table.new_table()
file_ast := parser.parse_file(ipath, table, .parse_comments, &pref.Preferences{}, &ast.Scope{parent: 0}) file_ast := parser.parse_file(ipath, table, .parse_comments, &pref.Preferences{}, &ast.Scope{
parent: 0
})
result_ocontent := fmt.fmt(file_ast, table) result_ocontent := fmt.fmt(file_ast, table)
if expected_ocontent != result_ocontent { if expected_ocontent != result_ocontent {
fmt_bench.fail() fmt_bench.fail()

View File

@ -0,0 +1,24 @@
fn has_anon_fn() {
an_fn := fn () {
println('Hello there !')
}
an_fn_w_param := fn (s string) {
println('I received $s')
}
an_fn_w_multi_params := fn (s1, s2, s3 string) {
println('I received $s1, $s2, $s3')
}
an_fn_w_multi_params2 := fn (s string, i int) {
println('I received $s, $i')
}
fn_w_var_args := fn (ss ...string) {
for s in ss {
println('yo $s')
}
}
an_fn()
an_fn_w_param('a gift')
an_fn_w_multi_params('one', 'two', 'three')
an_fn_w_multi_params2('one', 1)
fn_w_var_args('one arg', 'two args', 'three args')
}

View File

@ -0,0 +1,23 @@
fn has_anon_fn() {
an_fn := fn() {
println('Hello there !')
}
an_fn_w_param := fn ( s string )
{
println('I received $s')
}
an_fn_w_multi_params := fn (s1, s2, s3 string) {
println('I received $s1, $s2, $s3')
}
an_fn_w_multi_params2 :=fn (s string, i int) {
println('I received $s, $i')
}
fn_w_var_args := fn (ss ...string) {
for s in ss {
println('yo $s')
}
} an_fn()
an_fn_w_param('a gift') an_fn_w_multi_params('one', 'two', 'three')
an_fn_w_multi_params2( 'one', 1)
fn_w_var_args('one arg', 'two args', 'three args')
}

View File

@ -5,8 +5,9 @@ fn make_flag(a, b, c string) string {
fn main() { fn main() {
// Set up flags // Set up flags
expected_flags := [ expected_flags := [
make_flag('solaris', '-L', '/opt/local/lib') make_flag('solaris', '-L', '/opt/local/lib'),
make_flag('darwin', '-framework', 'Cocoa') make_flag('darwin', '-framework', 'Cocoa'),
make_flag('windows', '-l', 'gdi32') make_flag('windows', '-l', 'gdi32')
] ]
_ := expected_flags
} }

View File

@ -1,10 +1,12 @@
fn fn_contains_index_expr() { fn fn_contains_index_expr() {
arr := [1, 2, 3, 4, 5] arr := [1, 2, 3, 4, 5]
a := 1 in arr[0..] a := 1 in arr[0..]
b := 1 in arr[..2] _ := a
c := 1 in arr[1..3] _ := 1 in arr[..2]
_ := 1 in arr[1..3]
d := arr[2] d := arr[2]
e := arr[2..] _ := d
f := arr[..2] _ := arr[2..]
g := arr[1..3] _ := arr[..2]
_ := arr[1..3]
} }

View File

@ -3,10 +3,12 @@
fn fn_contains_index_expr() { fn fn_contains_index_expr() {
arr := [1, 2, 3, 4, 5] arr := [1, 2, 3, 4, 5]
a := 1 in arr[ 0.. ] a := 1 in arr[ 0.. ]
b := 1 in arr[ ..2 ] _ := a
c := 1 in arr[1..3] _ := 1 in arr[ ..2 ]
_ := 1 in arr[1..3]
d := arr[2] d := arr[2]
e := arr[2 ..] _ := d
f := arr[.. 2 ] _ := arr[2 ..]
g := arr[ 1 .. 3] _ := arr[.. 2 ]
_ := arr[ 1 .. 3]
} }

View File

@ -1,7 +1,8 @@
fn test_as() { fn test_as() {
a := sum_expr() as Bar a := sum_expr() as Bar
_ := a
} }
fn test_cast() { fn test_cast() {
f := f32(0) _ := f32(0)
} }

View File

@ -1,7 +1,8 @@
fn test_as() { fn test_as() {
a := sum_expr() as Bar a := sum_expr() as Bar
_ := a
} }
fn test_cast() { fn test_cast() {
f := f32(0) _ := f32(0)
} }

View File

@ -0,0 +1,6 @@
fn concatenation_of_strings() {
_ := 'Simple' + 'Concat'
_ := 'Hello' + ' ' + 'World' + '!'
_ := 'There' + ' ' + 'so' + ' ' + 'many' + ' ' + 'words' + ' ' + 'they' + ' ' + "don't" +
' ' + 'fit' + ' ' + 'in' + ' ' + 'one' + ' ' + 'line'
}

View File

@ -0,0 +1,7 @@
fn concatenation_of_strings() {
_ := 'Simple' + 'Concat'
_ := 'Hello'
+ ' ' +
'World' + '!'
_ := 'There' + ' ' + 'so' + ' ' + 'many' + ' ' + 'words' + ' ' + 'they' + ' ' + "don't" + ' ' + 'fit' + ' ' + 'in' + ' ' + 'one' + ' ' + 'line'
}

View File

@ -8,5 +8,5 @@ fn fn_with_if_else() {
} }
fn fn_with_if_else_oneline() { fn fn_with_if_else_oneline() {
x := if true { 1 } else { 2 } _ := if true { 1 } else { 2 }
} }

View File

@ -6,5 +6,5 @@ fn fn_with_if_else() {
} }
fn fn_with_if_else_oneline() { fn fn_with_if_else_oneline() {
x := if true { 1 } else { 2 } _ := if true { 1 } else { 2 }
} }

View File

@ -1,7 +1,22 @@
const ( const (
pi = 3.14 pi = 3.14
phi = 1.618 phi = 1.618
eulers = 2.7182 eulers = 2.7182
supported_platforms = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd',
'netbsd', 'dragonfly', 'android', 'js', 'solaris', 'haiku', 'linux_or_macos']
one_line_supported = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd',
'netbsd', 'dragonfly', 'android', 'js', 'solaris', 'haiku', 'linux_or_macos']
another_const = [
'a', 'b',
'c', 'd', 'e',
'f'
]
)
const (
i_am_a_very_long_constant_name_so_i_stand_alone_and_my_length_is_over_90_characters = [
'testforit'
]
) )
pub const ( pub const (

View File

@ -2,8 +2,22 @@ const (
pi=3.14 pi=3.14
phi=1.618 phi=1.618
eulers=2.7182 eulers=2.7182
supported_platforms = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd',
'netbsd', 'dragonfly', 'android', 'js', 'solaris', 'haiku', 'linux_or_macos']
one_line_supported = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd', 'netbsd', 'dragonfly', 'android', 'js', 'solaris', 'haiku', 'linux_or_macos']
another_const = [
'a', 'b'
'c', 'd', 'e'
'f'
]
)
const (
i_am_a_very_long_constant_name_so_i_stand_alone_and_my_length_is_over_90_characters = ['testforit']
) )
pub const ( pub const (
i_am_pub_const=true i_am_pub_const=true
) )

View File

@ -0,0 +1,13 @@
fn my_thread() {
println('yo')
}
fn my_thread_with_params(s string) {
println(s)
}
fn my_fn_calling_threads() {
go my_thread()
go my_thread_with_params('yay')
go my_thread_with_params('nono')
}

View File

@ -0,0 +1,16 @@
fn my_thread() {
println('yo')
}
fn my_thread_with_params(s string)
{
println(s)
}
fn my_fn_calling_threads () {
go my_thread()
go my_thread_with_params('yay')
go
my_thread_with_params('nono')
}

View File

@ -9,9 +9,24 @@ fn match_expr() {
fn match_expr_assignment() { fn match_expr_assignment() {
a := 20 a := 20
b := match a { _ := match a {
10 { 10 } 10 { 10 }
5 { 5 } 5 { 5 }
else { 2 } else { 2 }
} }
} }
fn match_branch_comment() {
a := 1
match a {
1 {
println('1')
}
2 {
println('2')
}
else {
// do nothing
}
}
}

View File

@ -13,9 +13,24 @@ fn match_expr() {
fn match_expr_assignment() { fn match_expr_assignment() {
a := 20 a := 20
b := match a { _ := match a {
10 { 10 } 10 { 10 }
5 { 5 } 5 { 5 }
else { 2 } else { 2 }
} }
} }
fn match_branch_comment() {
a := 1
match a {
1 { println('1') }
2 {
println('2')
}
else {
// do nothing
}
}
}

View File

@ -7,4 +7,16 @@ that is on multiple lines
*/ */
fn main() { fn main() {
println('hello') println('hello')
/*
this comment also
has mutliple lines
but it's difference
is that it is indented !
*/
if true {
/*
this one is even more
indented !
*/
}
} }

View File

@ -0,0 +1,11 @@
fn main() {
'Hello world !'
'This is correct !'
"It's okay"
'This is "too"'
// TODO
// 'I\'m not correctly formatted' => "I'm not correctly formatted"
// "\"Everything on the internet is true\" - Albert Einstein, 1965" => '"Everything on the internet is true" - Albert Einstein, 1965'
'I\'m out of idea "_"'
// "Definitely out \":'(\"" => 'Definitely out ":\'("'
}

View File

@ -0,0 +1,11 @@
fn main() {
"Hello world !"
'This is correct !'
"It's okay"
'This is "too"'
// TODO
// 'I\'m not correctly formatted' => "I'm not correctly formatted"
// "\"Everything on the internet is true\" - Albert Einstein, 1965" => '"Everything on the internet is true" - Albert Einstein, 1965'
'I\'m out of idea "_"'
// "Definitely out \":'(\"" => 'Definitely out ":\'("'
}

View File

@ -5,9 +5,9 @@ const (
) )
fn test_type_ptr() { fn test_type_ptr() {
a := &Test{} _ := &Test{}
b := []&Test _ := []&Test
c := &[]&Test _ := &[]&Test
} }
struct Test { struct Test {

View File

@ -14,28 +14,28 @@ import term
const ( const (
c_reserved = ['delete', 'exit', 'unix', 'error', 'calloc', 'malloc', 'free', 'panic', 'auto', c_reserved = ['delete', 'exit', 'unix', 'error', 'calloc', 'malloc', 'free', 'panic', 'auto',
'char' 'char',
'default' 'default',
'do' 'do',
'double' 'double',
'extern' 'extern',
'float' 'float',
'inline' 'inline',
'int' 'int',
'long' 'long',
'register' 'register',
'restrict' 'restrict',
'short' 'short',
'signed' 'signed',
'sizeof' 'sizeof',
'static' 'static',
'switch' 'switch',
'typedef' 'typedef',
'union' 'union',
'unsigned' 'unsigned',
'void' 'void',
'volatile' 'volatile',
'while' 'while'
] ]
) )
@ -1420,7 +1420,8 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
g.expr_with_cast(node.right, node.right_type, info.elem_type) g.expr_with_cast(node.right, node.right_type, info.elem_type)
g.write(' })') g.write(' })')
} }
} else if (node.left_type == node.right_type) && node.left_type.is_float() && node.op in [.eq, .ne] { } else if (node.left_type == node.right_type) && node.left_type.is_float() && node.op in
[.eq, .ne] {
// floats should be compared with epsilon // floats should be compared with epsilon
if node.left_type == table.f64_type_idx { if node.left_type == table.f64_type_idx {
if node.op == .eq { if node.op == .eq {
@ -1748,7 +1749,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
} }
else {} else {}
} }
*/ */
if need_wrapper { if need_wrapper {
g.write(', &($elem_type_str[]) { ') g.write(', &($elem_type_str[]) { ')
} else { } else {
@ -1810,7 +1811,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
g.write(', ') g.write(', ')
g.expr(node.index) g.expr(node.index)
g.write('))') g.write('))')
*/ */
zero := g.type_default(info.value_type) zero := g.type_default(info.value_type)
g.write('(*($elem_type_str*)map_get3(') g.write('(*($elem_type_str*)map_get3(')
g.expr(node.left) g.expr(node.left)
@ -1916,7 +1917,7 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
g.const_decl_simple_define(name, val) g.const_decl_simple_define(name, val)
return return
} }
*/ */
/* /*
if table.is_number(field.typ) { if table.is_number(field.typ) {
g.const_decl_simple_define(name, val) g.const_decl_simple_define(name, val)
@ -1926,7 +1927,7 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
g.stringliterals.writeln('\t_const_$name = $val;') g.stringliterals.writeln('\t_const_$name = $val;')
} }
} else { } else {
*/ */
match field.expr { match field.expr {
ast.CharLiteral { ast.CharLiteral {
g.const_decl_simple_define(name, val) g.const_decl_simple_define(name, val)
@ -1992,7 +1993,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
} else { } else {
fields = struct_init.fields fields = struct_init.fields
} }
*/ */
// User set fields // User set fields
for _, field in struct_init.fields { for _, field in struct_init.fields {
field_name := c_name(field.name) field_name := c_name(field.name)
@ -2378,8 +2379,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
g.write('${str_fn_name}(') g.write('${str_fn_name}(')
g.expr(expr) g.expr(expr)
g.write(').str') g.write(').str')
} } else if sym.kind == .enum_ {
else if sym.kind == .enum_ {
is_var := match node.exprs[i] { is_var := match node.exprs[i] {
ast.SelectorExpr { true } ast.SelectorExpr { true }
ast.Ident { true } ast.Ident { true }
@ -2718,7 +2718,7 @@ fn (g Gen) type_default(typ table.Type) string {
} }
else {} else {}
} }
*/ */
match sym.name { match sym.name {
'string' { return 'tos3("")' } 'string' { return 'tos3("")' }
'rune' { return '0' } 'rune' { return '0' }
@ -2747,7 +2747,7 @@ fn (g Gen) type_default(typ table.Type) string {
'voidptr'{ '0'} 'voidptr'{ '0'}
else { '{0} '} else { '{0} '}
} }
*/ */
} }
pub fn (mut g Gen) write_tests_main() { pub fn (mut g Gen) write_tests_main() {
@ -2948,7 +2948,7 @@ fn (mut g Gen) as_cast(node ast.AsCast) {
g.write('/* as */ *($styp*)') g.write('/* as */ *($styp*)')
g.expr(node.expr) g.expr(node.expr)
g.write('.obj') g.write('.obj')
*/ */
g.write('/* as */ *($styp*)__as_cast(') g.write('/* as */ *($styp*)__as_cast(')
g.expr(node.expr) g.expr(node.expr)
g.write('.obj, ') g.write('.obj, ')

View File

@ -1,13 +1,11 @@
import ( import os
os import v.pref
v.pref import v.builder
v.builder import term
term
)
const ( const (
nr_tests = 4 nr_tests = 4
term_ok = term.ok_message('OK') term_ok = term.ok_message('OK')
term_fail = term.fail_message('FAIL') term_fail = term.fail_message('FAIL')
) )
@ -35,8 +33,7 @@ fn test_c_files() {
} }
if compare_texts(res, ctext, path) { if compare_texts(res, ctext, path) {
println('${term_ok} ${i}') println('${term_ok} ${i}')
} } else {
else {
assert false assert false
} }
} }
@ -56,7 +53,6 @@ fn compare_texts(a, b, path string) bool {
return false return false
} }
*/ */
for i, line_a in lines_a { for i, line_a in lines_a {
if i >= lines_b.len { if i >= lines_b.len {
println(line_a) println(line_a)

View File

@ -68,7 +68,7 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
g.definitions.write(', ') g.definitions.write(', ')
} }
} }
*/ */
// //
g.fn_args(it.args, it.is_variadic) g.fn_args(it.args, it.is_variadic)
if it.no_body || (g.pref.is_cache && it.is_builtin) { if it.no_body || (g.pref.is_cache && it.is_builtin) {
@ -102,9 +102,8 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
} }
} }
} }
// Profiling mode? Start counting at the beginning of the function (save current time).
// Profiling mode? Start counting at the beginning of the function (save current time). if g.pref.is_prof {
if g.pref.is_prof {
if is_main { if is_main {
g.writeln('') g.writeln('')
g.writeln('\tatexit(vprint_profile_stats);') g.writeln('\tatexit(vprint_profile_stats);')
@ -112,17 +111,16 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
} }
if it.name == 'time.sys_mono_now' { if it.name == 'time.sys_mono_now' {
g.defer_profile_code = '' g.defer_profile_code = ''
}else{ } else {
fn_profile_counter_name := 'vpc_${g.last_fn_c_name}' fn_profile_counter_name := 'vpc_${g.last_fn_c_name}'
g.writeln('') g.writeln('')
g.writeln('\tdouble _PROF_FN_START = time__sys_mono_now(); ${fn_profile_counter_name}_calls++; // $it.name') g.writeln('\tdouble _PROF_FN_START = time__sys_mono_now(); ${fn_profile_counter_name}_calls++; // $it.name')
g.writeln('') g.writeln('')
g.defer_profile_code = '\t${fn_profile_counter_name} += time__sys_mono_now() - _PROF_FN_START;' g.defer_profile_code = '\t${fn_profile_counter_name} += time__sys_mono_now() - _PROF_FN_START;'
g.pcs_declarations.writeln('double ${fn_profile_counter_name} = 0.0; u64 ${fn_profile_counter_name}_calls = 0;') g.pcs_declarations.writeln('double ${fn_profile_counter_name} = 0.0; u64 ${fn_profile_counter_name}_calls = 0;')
g.pcs[ g.last_fn_c_name ] = fn_profile_counter_name g.pcs[g.last_fn_c_name] = fn_profile_counter_name
} }
} }
g.stmts(it.stmts) g.stmts(it.stmts)
// //////////// // ////////////
if g.autofree { if g.autofree {
@ -145,7 +143,7 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
for pfn_name, pcounter_name in g.pcs { for pfn_name, pcounter_name in g.pcs {
g.pcs_declarations.writeln('\tif (${pcounter_name}_calls) printf("%llu %f %f ${pfn_name} \\n", ${pcounter_name}_calls, $pcounter_name, $pcounter_name / ${pcounter_name}_calls );') g.pcs_declarations.writeln('\tif (${pcounter_name}_calls) printf("%llu %f %f ${pfn_name} \\n", ${pcounter_name}_calls, $pcounter_name, $pcounter_name / ${pcounter_name}_calls );')
} }
}else{ } else {
g.pcs_declarations.writeln('\tFILE * fp;') g.pcs_declarations.writeln('\tFILE * fp;')
g.pcs_declarations.writeln('\tfp = fopen ("${g.pref.profile_file}", "w+");') g.pcs_declarations.writeln('\tfp = fopen ("${g.pref.profile_file}", "w+");')
for pfn_name, pcounter_name in g.pcs { for pfn_name, pcounter_name in g.pcs {
@ -162,11 +160,11 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
g.fn_decl = 0 g.fn_decl = 0
} }
fn (mut g Gen) write_defer_stmts_when_needed(){ fn (mut g Gen) write_defer_stmts_when_needed() {
if g.defer_profile_code.len > 0 { if g.defer_profile_code.len > 0 {
g.writeln('') g.writeln('')
g.writeln('\t// defer_profile_code') g.writeln('\t// defer_profile_code')
g.writeln(g.defer_profile_code ) g.writeln(g.defer_profile_code)
g.writeln('') g.writeln('')
} }
if g.defer_stmts.len > 0 { if g.defer_stmts.len > 0 {
@ -267,12 +265,12 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
} }
// TODO performance, detect `array` method differently // TODO performance, detect `array` method differently
if typ_sym.kind == .array && node.name in ['repeat', 'sort_with_compare', 'free', 'push_many', if typ_sym.kind == .array && node.name in ['repeat', 'sort_with_compare', 'free', 'push_many',
'trim' 'trim',
'first' 'first',
'last' 'last',
'clone' 'clone',
'reverse' 'reverse',
'slice' 'slice'
] { ] {
// && rec_sym.name == 'array' { // && rec_sym.name == 'array' {
// && rec_sym.name == 'array' && receiver_name.starts_with('array') { // && rec_sym.name == 'array' && receiver_name.starts_with('array') {
@ -298,8 +296,8 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
g.write('/*rec*/*') g.write('/*rec*/*')
} }
g.expr(node.left) g.expr(node.left)
is_variadic := node.expected_arg_types.len > 0 && is_variadic := node.expected_arg_types.len > 0 && node.expected_arg_types[node.expected_arg_types.len -
node.expected_arg_types[node.expected_arg_types.len -1].flag_is(.variadic) 1].flag_is(.variadic)
if node.args.len > 0 || is_variadic { if node.args.len > 0 || is_variadic {
g.write(', ') g.write(', ')
} }
@ -313,7 +311,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
} }
println('') println('')
} }
*/ */
// /////// // ///////
g.call_args(node.args, node.expected_arg_types) g.call_args(node.args, node.expected_arg_types)
g.write(')') g.write(')')
@ -368,7 +366,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
g.writeln('; //memory') g.writeln('; //memory')
} }
} }
*/ */
if is_print && node.args[0].typ != table.string_type { if is_print && node.args[0].typ != table.string_type {
typ := node.args[0].typ typ := node.args[0].typ
mut styp := g.typ(typ) mut styp := g.typ(typ)
@ -441,8 +439,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
} }
fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) { fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
is_variadic := expected_types.len > 0 && is_variadic := expected_types.len > 0 && expected_types[expected_types.len - 1].flag_is(.variadic)
expected_types[expected_types.len - 1].flag_is(.variadic)
is_forwarding_varg := args.len > 0 && args[args.len - 1].typ.flag_is(.variadic) is_forwarding_varg := args.len > 0 && args[args.len - 1].typ.flag_is(.variadic)
gen_vargs := is_variadic && !is_forwarding_varg gen_vargs := is_variadic && !is_forwarding_varg
mut arg_no := 0 mut arg_no := 0

View File

@ -1,48 +1,46 @@
module js module js
import ( import strings
strings import v.ast
v.ast
)
struct JsDoc { struct JsDoc {
gen &JsGen gen &JsGen
mut: mut:
out strings.Builder out strings.Builder
empty_line bool empty_line bool
} }
fn new_jsdoc(gen &JsGen) &JsDoc { fn new_jsdoc(gen &JsGen) &JsDoc {
return &JsDoc { return &JsDoc{
out: strings.new_builder(20) out: strings.new_builder(20)
gen: gen gen: gen
} }
} }
fn (d mut JsDoc) gen_indent() { fn (mut d JsDoc) gen_indent() {
if d.gen.indents[d.gen.namespace] > 0 && d.empty_line { if d.gen.indents[d.gen.namespace] > 0 && d.empty_line {
d.out.write(tabs[d.gen.indents[d.gen.namespace]]) d.out.write(tabs[d.gen.indents[d.gen.namespace]])
} }
d.empty_line = false d.empty_line = false
} }
fn (d mut JsDoc) write(s string) { fn (mut d JsDoc) write(s string) {
d.gen_indent() d.gen_indent()
d.out.write(s) d.out.write(s)
} }
fn (d mut JsDoc) writeln(s string) { fn (mut d JsDoc) writeln(s string) {
d.gen_indent() d.gen_indent()
d.out.writeln(s) d.out.writeln(s)
d.empty_line = true d.empty_line = true
} }
fn (d mut JsDoc) reset() { fn (mut d JsDoc) reset() {
d.out = strings.new_builder(20) d.out = strings.new_builder(20)
d.empty_line = false d.empty_line = false
} }
fn (d mut JsDoc) gen_typ(typ string, name string) string { fn (mut d JsDoc) gen_typ(typ, name string) string {
d.reset() d.reset()
d.write('/**') d.write('/**')
d.write(' @type {$typ}') d.write(' @type {$typ}')
@ -53,13 +51,15 @@ fn (d mut JsDoc) gen_typ(typ string, name string) string {
return d.out.str() return d.out.str()
} }
fn (d mut JsDoc) gen_ctor(fields []ast.StructField) string { fn (mut d JsDoc) gen_ctor(fields []ast.StructField) string {
d.reset() d.reset()
d.writeln('/**') d.writeln('/**')
d.write('* @param {{') d.write('* @param {{')
for i, field in fields { for i, field in fields {
d.write('$field.name: ${d.gen.typ(field.typ)}') d.write('$field.name: ${d.gen.typ(field.typ)}')
if i < fields.len-1 { d.write(', ') } if i < fields.len - 1 {
d.write(', ')
}
} }
d.writeln('}} values - values for this class fields') d.writeln('}} values - values for this class fields')
d.writeln('* @constructor') d.writeln('* @constructor')
@ -67,12 +67,14 @@ fn (d mut JsDoc) gen_ctor(fields []ast.StructField) string {
return d.out.str() return d.out.str()
} }
fn (d mut JsDoc) gen_fn(it ast.FnDecl) string { fn (mut d JsDoc) gen_fn(it ast.FnDecl) string {
d.reset() d.reset()
type_name := d.gen.typ(it.return_type) type_name := d.gen.typ(it.return_type)
d.writeln('/**') d.writeln('/**')
for i, arg in it.args { for i, arg in it.args {
if it.is_method && i == 0 { continue } if it.is_method && i == 0 {
continue
}
arg_type_name := d.gen.typ(arg.typ) arg_type_name := d.gen.typ(arg.typ)
is_varg := i == it.args.len - 1 && it.is_variadic is_varg := i == it.args.len - 1 && it.is_variadic
if is_varg { if is_varg {

View File

@ -34,9 +34,10 @@ const (
) )
pub fn (mut g Gen) generate_elf_header() { pub fn (mut g Gen) generate_elf_header() {
g.buf << [byte(mag0), mag1 g.buf << [byte(mag0),
mag2 mag1,
mag3 mag2,
mag3
] ]
g.buf << elfclass64 // file class g.buf << elfclass64 // file class
g.buf << elfdata2lsb // data encoding g.buf << elfdata2lsb // data encoding
@ -83,7 +84,7 @@ pub fn (mut g Gen) generate_elf_footer() {
g.mov(.edi, 0) // ret value g.mov(.edi, 0) // ret value
g.mov(.eax, 60) g.mov(.eax, 60)
g.syscall() g.syscall()
*/ */
// Strings table // Strings table
// Loop thru all strings and set the right addresses // Loop thru all strings and set the right addresses
for i, s in g.strings { for i, s in g.strings {

View File

@ -2,14 +2,13 @@
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module x64 module x64
/* /*
This file is unused right now, since binaries without sections This file is unused right now, since binaries without sections
are generated. are generated.
But it will be necessary once we have dynamic linking. But it will be necessary once we have dynamic linking.
*/ */
enum SectionType { enum SectionType {
null = 0 null = 0
progbits = 1 progbits = 1
@ -31,7 +30,7 @@ struct SectionConfig {
entsize i64 entsize i64
} }
fn (g mut Gen) section_header(c SectionConfig) { fn (mut g Gen) section_header(c SectionConfig) {
g.write32(g.sect_header_name_pos) g.write32(g.sect_header_name_pos)
g.sect_header_name_pos += c.name.len + 1 g.sect_header_name_pos += c.name.len + 1
g.write32(int(c.typ)) g.write32(int(c.typ))
@ -156,4 +155,3 @@ fn genobj() {
}) })
*/ */
} }

View File

@ -348,7 +348,7 @@ pub fn (mut g Gen) push(reg Register) {
.rbp { g.write8(0x55) } .rbp { g.write8(0x55) }
else {} else {}
} }
*/ */
g.println('push $reg') g.println('push $reg')
} }

View File

@ -14,7 +14,7 @@ fn (mut p Parser) assign_stmt() ast.Stmt {
} }
idents := p.parse_assign_lhs() idents := p.parse_assign_lhs()
op := p.tok.kind op := p.tok.kind
p.next() // :=, = p.next() // :=, =
pos := p.tok.position() pos := p.tok.position()
exprs := p.parse_assign_rhs() exprs := p.parse_assign_rhs()
is_decl := op == .decl_assign is_decl := op == .decl_assign

View File

@ -3,11 +3,9 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module parser module parser
import ( import v.ast
v.ast import v.pref
v.pref import v.vmod
v.vmod
)
const ( const (
supported_platforms = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd', supported_platforms = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd',
@ -23,14 +21,13 @@ fn (mut p Parser) hash() ast.HashStmt {
mut flag := val[5..] mut flag := val[5..]
// expand `@VROOT` to its absolute path // expand `@VROOT` to its absolute path
if flag.contains('@VROOT') { if flag.contains('@VROOT') {
vmod_file_location := vmod.mod_file_cacher.get( p.file_name_dir ) vmod_file_location := vmod.mod_file_cacher.get(p.file_name_dir)
if vmod_file_location.vmod_file.len == 0 { if vmod_file_location.vmod_file.len == 0 {
// There was no actual v.mod file found. // There was no actual v.mod file found.
p.error('To use @VROOT, you need' + p.error('To use @VROOT, you need' + ' to have a "v.mod" file in ${p.file_name_dir},' +
' to have a "v.mod" file in ${p.file_name_dir},' +
' or in one of its parent folders.') ' or in one of its parent folders.')
} }
flag = flag.replace('@VROOT', vmod_file_location.vmod_folder ) flag = flag.replace('@VROOT', vmod_file_location.vmod_folder)
} }
for deprecated in ['@VMOD', '@VMODULE', '@VPATH', '@VLIB_PATH'] { for deprecated in ['@VMOD', '@VMODULE', '@VPATH', '@VLIB_PATH'] {
if flag.contains(deprecated) { if flag.contains(deprecated) {
@ -48,7 +45,7 @@ fn (mut p Parser) hash() ast.HashStmt {
p.pref.cflags += val.after('darwin') p.pref.cflags += val.after('darwin')
} }
} }
*/ */
} }
return ast.HashStmt{ return ast.HashStmt{
val: val val: val
@ -72,12 +69,13 @@ fn (mut p Parser) comp_if() ast.CompIf {
// `$if os {` for a different target, skip everything inside // `$if os {` for a different target, skip everything inside
// to avoid compilation errors (like including <windows.h> or calling WinAPI fns // to avoid compilation errors (like including <windows.h> or calling WinAPI fns
// on non-Windows systems) // on non-Windows systems)
if !p.scanner.is_fmt && ((!is_not && os != p.pref.os) || (is_not && os == p.pref.os)) && !p.pref.output_cross_c { if !p.scanner.is_fmt && ((!is_not && os != p.pref.os) || (is_not && os == p.pref.os)) &&
!p.pref.output_cross_c {
skip_os = true skip_os = true
p.check(.lcbr) p.check(.lcbr)
// p.warn('skipping $if $val os=$os p.pref.os=$p.pref.os') // p.warn('skipping $if $val os=$os p.pref.os=$p.pref.os')
mut stack := 1 mut stack := 1
for { for {
if p.tok.kind == .key_return { if p.tok.kind == .key_return {
p.returns = true p.returns = true
} }

View File

@ -270,7 +270,7 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
func.name = name func.name = name
idx := p.table.find_or_register_fn_type(func, true, false) idx := p.table.find_or_register_fn_type(func, true, false)
typ := table.new_type(idx) typ := table.new_type(idx)
//name := p.table.get_type_name(typ) // name := p.table.get_type_name(typ)
return ast.AnonFn{ return ast.AnonFn{
decl: ast.FnDecl{ decl: ast.FnDecl{
name: name name: name

View File

@ -95,7 +95,7 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
mut branches := []ast.MatchBranch mut branches := []ast.MatchBranch
for { for {
branch_first_pos := p.tok.position() branch_first_pos := p.tok.position()
comment := p.check_comment() // comment before {} comment := p.check_comment() // comment before {}
mut exprs := []ast.Expr mut exprs := []ast.Expr
p.open_scope() p.open_scope()
// final else // final else

View File

@ -2,6 +2,7 @@
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module parser module parser
// return true if file being parsed imports `mod` // return true if file being parsed imports `mod`
pub fn (p &Parser) known_import(mod string) bool { pub fn (p &Parser) known_import(mod string) bool {
return mod in p.imports return mod in p.imports

View File

@ -99,7 +99,7 @@ pub fn parse_file(path string, table &table.Table, comments_mode scanner.Comment
for p.tok.kind == .key_import { for p.tok.kind == .key_import {
imports << p.import_stmt() imports << p.import_stmt()
} }
*/ */
// TODO: import only mode // TODO: import only mode
for { for {
// res := s.scan() // res := s.scan()
@ -164,7 +164,7 @@ pub fn parse_files(paths []string, table &table.Table, pref &pref.Preferences, g
} }
time.sleep_ms(100) time.sleep_ms(100)
return q.parsed_ast_files return q.parsed_ast_files
*/ */
// /////////////// // ///////////////
mut files := []ast.File mut files := []ast.File
for path in paths { for path in paths {
@ -187,7 +187,6 @@ pub fn (mut p Parser) read_first_token() {
p.next() p.next()
} }
pub fn (mut p Parser) open_scope() { pub fn (mut p Parser) open_scope() {
p.scope = &ast.Scope{ p.scope = &ast.Scope{
parent: p.scope parent: p.scope
@ -198,7 +197,7 @@ pub fn (mut p Parser) open_scope() {
pub fn (mut p Parser) close_scope() { pub fn (mut p Parser) close_scope() {
if !p.pref.is_repl && !p.scanner.is_fmt { if !p.pref.is_repl && !p.scanner.is_fmt {
for v in p.scope.unused_vars() { for v in p.scope.unused_vars() {
if v.name.len > 0 && v.name[0]==`_` { if v.name.len > 0 && v.name[0] == `_` {
continue continue
} }
if p.pref.is_prod { if p.pref.is_prod {
@ -255,7 +254,7 @@ fn (mut p Parser) next() {
p.comments << ast.Comment{text:p.tok.lit, line_nr:p.tok.line_nr} p.comments << ast.Comment{text:p.tok.lit, line_nr:p.tok.line_nr}
p.next() p.next()
} }
*/ */
} }
fn (mut p Parser) check(expected token.Kind) { fn (mut p Parser) check(expected token.Kind) {
@ -638,9 +637,8 @@ pub fn (mut p Parser) name_expr() ast.Expr {
name_w_mod := p.prepend_mod(name) name_w_mod := p.prepend_mod(name)
// type cast. TODO: finish // type cast. TODO: finish
// if name in table.builtin_type_names { // if name in table.builtin_type_names {
if !known_var && (name in p.table.type_idxs || name_w_mod in p.table.type_idxs) && !(name in ['C.stat', if !known_var && (name in p.table.type_idxs || name_w_mod in p.table.type_idxs) &&
'C.sigaction' !(name in ['C.stat', 'C.sigaction']) {
]) {
// TODO handle C.stat() // TODO handle C.stat()
mut to_typ := p.parse_type() mut to_typ := p.parse_type()
if p.is_amp { if p.is_amp {
@ -1080,7 +1078,7 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
if !p.cgen.nogen { if !p.cgen.nogen {
p.cgen.consts << g p.cgen.consts << g
} }
*/ */
glob := ast.GlobalDecl{ glob := ast.GlobalDecl{
name: name name: name
typ: typ typ: typ
@ -1099,7 +1097,6 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
} }
p.check(.key_enum) p.check(.key_enum)
end_pos := p.tok.position() end_pos := p.tok.position()
enum_name := p.check_name() enum_name := p.check_name()
if enum_name.len > 0 && !enum_name[0].is_capital() { if enum_name.len > 0 && !enum_name[0].is_capital() {
verror('enum name `$enum_name` must begin with a capital letter') verror('enum name `$enum_name` must begin with a capital letter')

View File

@ -162,7 +162,8 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
} }
} else if p.tok.kind.is_infix() { } else if p.tok.kind.is_infix() {
// return early for deref assign `*x = 2` goes to prefix expr // return early for deref assign `*x = 2` goes to prefix expr
if p.tok.kind == .mul && p.tok.line_nr != p.prev_tok.line_nr && p.peek_tok2.kind == .assign { if p.tok.kind == .mul && p.tok.line_nr != p.prev_tok.line_nr && p.peek_tok2.kind ==
.assign {
return node return node
} }
// continue on infix expr // continue on infix expr

View File

@ -71,7 +71,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
s := p.table.get_type_symbol(typ) s := p.table.get_type_symbol(typ)
println('XXXX' + s.str()) println('XXXX' + s.str())
} }
*/ */
mut default_expr := ast.Expr{} mut default_expr := ast.Expr{}
mut has_default_expr := false mut has_default_expr := false
if p.tok.kind == .assign { if p.tok.kind == .assign {

View File

@ -3,10 +3,8 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module pref module pref
import ( import os
os import term
term
)
pub const ( pub const (
default_module_path = mpath() default_module_path = mpath()
@ -22,7 +20,7 @@ pub fn new_preferences() Preferences {
return p return p
} }
pub fn (p mut Preferences) fill_with_defaults() { pub fn (mut p Preferences) fill_with_defaults() {
if p.vroot == '' { if p.vroot == '' {
// Location of all vlib files // Location of all vlib files
p.vroot = os.dir(vexe_path()) p.vroot = os.dir(vexe_path())

View File

@ -171,17 +171,17 @@ 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 u32_type_idx,
u64_type_idx u64_type_idx
] ]
float_type_idxs = [f32_type_idx, f64_type_idx] float_type_idxs = [f32_type_idx, f64_type_idx]
number_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx, number_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 u32_type_idx,
u64_type_idx u64_type_idx,
f32_type_idx f32_type_idx,
f64_type_idx f64_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]
@ -213,11 +213,11 @@ 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' 'u32',
'u64', 'f32', 'f64', 'string', 'ustring', 'char', 'byte', 'bool', 'none', 'array', 'array_fixed' 'u64', 'f32', 'f64', 'string', 'ustring', 'char', 'byte', 'bool', 'none', 'array', 'array_fixed',
'map', 'struct' 'map', 'struct',
'mapnode', 'size_t'] 'mapnode', 'size_t']
) )
pub struct MultiReturn { pub struct MultiReturn {
@ -591,6 +591,6 @@ pub fn (table &Table) type_to_str(t Type) string {
if res.starts_with(cur_mod +'.') { if res.starts_with(cur_mod +'.') {
res = res[cur_mod.len+1.. ] res = res[cur_mod.len+1.. ]
} }
*/ */
return res return res
} }

View File

@ -17,7 +17,7 @@ fn (table &Table) has_cflag(flag cflag.CFlag) bool {
// parse the flags to (table.cflags) []CFlag // parse the flags to (table.cflags) []CFlag
// Note: clean up big time (joe-c) // Note: clean up big time (joe-c)
pub fn (table mut Table) parse_cflag(cflg, mod string, ctimedefines []string) ?bool { pub fn (mut table Table) parse_cflag(cflg, mod string, ctimedefines []string) ?bool {
allowed_flags := ['framework', 'library', 'Wa', 'Wl', 'Wp', 'I', 'l', 'L'] allowed_flags := ['framework', 'library', 'Wa', 'Wl', 'Wp', 'I', 'l', 'L']
flag_orig := cflg.trim_space() flag_orig := cflg.trim_space()
mut flag := flag_orig mut flag := flag_orig

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(t, '-lmysqlclient') parse_valid_flag(t, '-lmysqlclient')
parse_valid_flag(t, '-test') parse_valid_flag(t, '-test')