From adb8fb1dc6953e48959a0a816a2ea408a9904ad3 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Thu, 23 Apr 2020 17:52:44 +0300 Subject: [PATCH] comptime: fix custom -d flags and `$if x? {}`. Fixes ftp_test.v . --- cmd/tools/vtest-fixed.v | 1 - cmd/v/v.v | 44 +++++++++++++++++++++++++++++++++++----- vlib/net/ftp/ftp.v | 5 +---- vlib/v/ast/ast.v | 9 ++++++++ vlib/v/gen/cgen.v | 29 +++++++++++++++++++++----- vlib/v/parser/comptime.v | 3 +++ 6 files changed, 76 insertions(+), 15 deletions(-) diff --git a/cmd/tools/vtest-fixed.v b/cmd/tools/vtest-fixed.v index bfb1bf950f..6e037e962f 100644 --- a/cmd/tools/vtest-fixed.v +++ b/cmd/tools/vtest-fixed.v @@ -9,7 +9,6 @@ const ( 'vlib/arrays/arrays_test.v', 'vlib/eventbus/eventbus_test.v', 'vlib/json/json_test.v', - 'vlib/net/ftp/ftp_test.v', 'vlib/net/http/http_httpbin_test.v', 'vlib/net/http/http_test.v', 'vlib/regex/regex_test.v', diff --git a/cmd/v/v.v b/cmd/v/v.v index 241be0d91b..48c9d671a2 100644 --- a/cmd/v/v.v +++ b/cmd/v/v.v @@ -115,6 +115,7 @@ fn parse_args(args []string) (&pref.Preferences, string) { // for i, arg in args { for i := 0; i < args.len; i++ { arg := args[i] + current_args := args[i..] match arg { '-v' { res.is_verbose = true @@ -170,7 +171,7 @@ fn parse_args(args []string) (&pref.Preferences, string) { } '-os' { // TODO Remove `tmp` variable when it doesn't error out in C. - target_os := cmdline.option(args, '-os', '') + target_os := cmdline.option(current_args, '-os', '') tmp := pref.os_from_string(target_os) or { println('unknown operating system target `$target_os`') exit(1) @@ -179,19 +180,26 @@ fn parse_args(args []string) (&pref.Preferences, string) { i++ } '-cflags' { - res.cflags = cmdline.option(args, '-cflags', '') + res.cflags = cmdline.option(current_args, '-cflags', '') + i++ + } + '-define', '-d' { + if current_args.len > 1 { + define := current_args[1] + parse_define(mut res, define) + } i++ } '-cc' { - res.ccompiler = cmdline.option(args, '-cc', 'cc') + res.ccompiler = cmdline.option(current_args, '-cc', 'cc') i++ } '-o' { - res.out_name = cmdline.option(args, '-o', '') + res.out_name = cmdline.option(current_args, '-o', '') i++ } '-b' { - b := pref.backend_from_string(cmdline.option(args, '-b', 'c')) or { + b := pref.backend_from_string(cmdline.option(current_args, '-b', 'c')) or { continue } res.backend = b @@ -275,3 +283,29 @@ fn create_symlink() { println('Failed to create symlink "$link_path". Try again with sudo.') } } + +fn parse_define(prefs mut pref.Preferences, define string) { + define_parts := define.split('=') + if define_parts.len == 1 { + prefs.compile_defines << define + prefs.compile_defines_all << define + return + } + if define_parts.len == 2 { + prefs.compile_defines_all << define_parts[0] + match define_parts[1] { + '0' {} + '1' { + prefs.compile_defines << define_parts[0] + } + else { + println('V error: Unknown define argument value `${define_parts[1]}` for ${define_parts[0]}.' + + 'Expected `0` or `1`.') + exit(1) + } + } + return + } + println('V error: Unknown define argument: ${define}. Expected at most one `=`.') + exit(1) +} diff --git a/vlib/net/ftp/ftp.v b/vlib/net/ftp/ftp.v index 3706d15d3f..a66d00ccea 100644 --- a/vlib/net/ftp/ftp.v +++ b/vlib/net/ftp/ftp.v @@ -127,10 +127,7 @@ pub fn (ftp FTP) login(user, passwd string) bool { return false } - mut data := '' - mut code := 0 - - code, data = ftp.read() + mut code, data := ftp.read() if code == LoggedIn { return true } diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index a829a547e9..2382a75dc4 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -433,6 +433,15 @@ pub: is_not bool pos token.Position mut: +/* +`$if xyz? {}` => this compile time `if` is optional, +and .is_opt reflects the presence of ? at the end. +When .is_opt is true, the code should compile, even +if `xyz` is NOT defined. +If .is_opt is false, then when `xyz` is not defined, +the compilation will fail. +*/ + is_opt bool has_else bool else_stmts []Stmt } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index ac1d171daa..8ff633efc6 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -54,6 +54,7 @@ struct Gen { gowrappers strings.Builder // all go callsite wrappers stringliterals strings.Builder // all string literals (they depend on tos3() beeing defined auto_str_funcs strings.Builder // function bodies of all auto generated _str funcs + comptime_defines strings.Builder // custom defines, given by -d/-define flags on the CLI table &table.Table pref &pref.Preferences mut: @@ -109,6 +110,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string gowrappers: strings.new_builder(100) stringliterals: strings.new_builder(100) auto_str_funcs: strings.new_builder(100) + comptime_defines: strings.new_builder(100) inits: strings.new_builder(100) table: table pref: pref @@ -151,7 +153,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string } // g.finish() - return g.hashes() + '\n// V typedefs:\n' + g.typedefs.str() + '\n// V typedefs2:\n' + g.typedefs2.str() + + return g.hashes() + g.comptime_defines.str() + '\n// V typedefs:\n' + g.typedefs.str() + '\n// V typedefs2:\n' + g.typedefs2.str() + '\n// V cheaders:\n' + g.cheaders.str() + '\n// V includes:\n' + g.includes.str() + '\n// V definitions:\n' + g.definitions.str() + g.interface_table() + '\n// V gowrappers:\n' + g.gowrappers.str() + '\n// V stringliterals:\n' + g.stringliterals.str() + '\n// V auto str functions:\n' + g.auto_str_funcs.str() + '\n// V out\n' + @@ -187,6 +189,18 @@ pub fn (mut g Gen) init() { if g.pref.build_mode != .build_module { g.stringliterals.writeln('void vinit_string_literals(){') } + + if g.pref.compile_defines_all.len > 0 { + g.comptime_defines.writeln('// V compile time defines by -d or -define flags:') + g.comptime_defines.writeln('// All custom defines : ' + g.pref.compile_defines_all.join(',')) + g.comptime_defines.writeln('// Turned ON custom defines: ' + g.pref.compile_defines.join(',')) + for cdefine in g.pref.compile_defines { + g.comptime_defines.writeln('#define CUSTOM_DEFINE_${cdefine}') + } + g.comptime_defines.writeln('') + } + + } pub fn (mut g Gen) finish() { @@ -2536,7 +2550,7 @@ fn op_to_fn_name(name string) string { } } -fn comp_if_to_ifdef(name string) string { +fn (mut g Gen) comp_if_to_ifdef(name string, is_comptime_optional bool) string { match name { // platforms/os-es: 'windows' { return '_WIN32' } @@ -2563,12 +2577,17 @@ fn comp_if_to_ifdef(name string) string { 'debug' { return '_VDEBUG' } 'glibc' { return '__GLIBC__' } 'prealloc' { return 'VPREALLOC' } - 'no_bounds_checking' { return 'NO_BOUNDS_CHECK' } + 'no_bounds_checking' { return 'CUSTOM_DEFINE_no_bounds_checking' } 'x64' { return 'TARGET_IS_64BIT' } 'x32' { return 'TARGET_IS_32BIT' } 'little_endian' { return 'TARGET_ORDER_IS_LITTLE' } 'big_endian' { return 'TARGET_ORDER_IS_BIG' } - else { verror('bad os ifdef name "$name"') } + else { + if is_comptime_optional || g.pref.compile_defines_all.len > 0 && name in g.pref.compile_defines_all { + return 'CUSTOM_DEFINE_${name}' + } + verror('bad os ifdef name "$name"') + } } // verror('bad os ifdef name "$name"') return '' @@ -2738,7 +2757,7 @@ fn (g Gen) is_importing_os() bool { } fn (mut g Gen) comp_if(it ast.CompIf) { - ifdef := comp_if_to_ifdef(it.val) + ifdef := g.comp_if_to_ifdef(it.val, it.is_opt) if it.is_not { g.writeln('\n#ifndef ' + ifdef) g.writeln('// #if not $it.val') diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index d4ca59d116..1fbdec064f 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -98,14 +98,17 @@ fn (mut p Parser) comp_if() ast.CompIf { } } } + mut is_opt := false if p.tok.kind == .question { p.next() + is_opt = true } if !skip_os { stmts = p.parse_block() } mut node := ast.CompIf{ is_not: is_not + is_opt: is_opt pos: pos val: val stmts: stmts