1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

remove duplication by using a new Preferences struct

This commit is contained in:
Archan Patkar 2019-07-01 01:33:17 +05:30 committed by Alexander Medvednikov
parent 42a622c10f
commit 74d234f8cd
4 changed files with 163 additions and 160 deletions

View File

@ -95,7 +95,7 @@ fn (f mut Fn) clear_vars() {
// vlib header file? // vlib header file?
fn (p mut Parser) is_sig() bool { fn (p mut Parser) is_sig() bool {
return (p.build_mode == DEFAULT_MODE || p.build_mode == BUILD) && return (p.pref.build_mode == DEFAULT_MODE || p.pref.build_mode == BUILD) &&
(p.file_path.contains(TmpPath)) (p.file_path.contains(TmpPath))
} }
@ -173,8 +173,8 @@ fn (p mut Parser) fn_decl() {
// C function header def? (fn C.NSMakeRect(int,int,int,int)) // C function header def? (fn C.NSMakeRect(int,int,int,int))
is_c := f.name == 'C' && p.tok == DOT is_c := f.name == 'C' && p.tok == DOT
// Just fn signature? only builtin.v + default build mode // Just fn signature? only builtin.v + default build mode
// is_sig := p.builtin_pkg && p.build_mode == DEFAULT_MODE // is_sig := p.builtin_pkg && p.pref.build_mode == DEFAULT_MODE
// is_sig := p.build_mode == DEFAULT_MODE && (p.builtin_pkg || p.file.contains(LANG_TMP)) // is_sig := p.pref.build_mode == DEFAULT_MODE && (p.builtin_pkg || p.file.contains(LANG_TMP))
is_sig := p.is_sig() is_sig := p.is_sig()
// println('\n\nfn decl !!is_sig=$is_sig name=$f.name $p.builtin_pkg') // println('\n\nfn decl !!is_sig=$is_sig name=$f.name $p.builtin_pkg')
if is_c { if is_c {
@ -182,7 +182,7 @@ fn (p mut Parser) fn_decl() {
f.name = p.check_name() f.name = p.check_name()
f.is_c = true f.is_c = true
} }
else if !p.translated && !p.file_path.contains('view.v') { else if !p.pref.translated && !p.file_path.contains('view.v') {
if contains_capital(f.name) { if contains_capital(f.name) {
p.error('function names cannot contain uppercase letters, use snake_case instead') p.error('function names cannot contain uppercase letters, use snake_case instead')
} }
@ -237,7 +237,7 @@ fn (p mut Parser) fn_decl() {
typ = p.get_type() typ = p.get_type()
} }
// Translated C code can have empty functions (just definitions) // Translated C code can have empty functions (just definitions)
is_fn_header := !is_c && !is_sig && (p.translated || p.is_test) && is_fn_header := !is_c && !is_sig && (p.pref.translated || p.pref.is_test) &&
(p.tok != LCBR)// || (p.tok == NAME && p.peek() != LCBR)) (p.tok != LCBR)// || (p.tok == NAME && p.peek() != LCBR))
if is_fn_header { if is_fn_header {
f.is_decl = true f.is_decl = true
@ -274,10 +274,10 @@ fn (p mut Parser) fn_decl() {
// } // }
mut fn_name_cgen := p.table.cgen_name(f) mut fn_name_cgen := p.table.cgen_name(f)
// Start generation of the function body // Start generation of the function body
is_live := p.is_live && f.name != 'main' && f.name != 'reload_so' is_live := p.pref.is_live && f.name != 'main' && f.name != 'reload_so'
skip_main_in_test := f.name == 'main' && p.is_test skip_main_in_test := f.name == 'main' && p.pref.is_test
if !is_c && !is_live && !is_sig && !is_fn_header && !skip_main_in_test { if !is_c && !is_live && !is_sig && !is_fn_header && !skip_main_in_test {
if p.obfuscate { if p.pref.obfuscate {
p.genln('; // ${f.name}') p.genln('; // ${f.name}')
} }
p.genln('$typ $fn_name_cgen($str_args) {') p.genln('$typ $fn_name_cgen($str_args) {')
@ -332,13 +332,13 @@ fn (p mut Parser) fn_decl() {
} }
// Actual fn declaration! // Actual fn declaration!
mut fn_decl := '$typ $fn_name_cgen($str_args)' mut fn_decl := '$typ $fn_name_cgen($str_args)'
if p.obfuscate { if p.pref.obfuscate {
fn_decl += '; // ${f.name}' fn_decl += '; // ${f.name}'
} }
// Add function definition to the top // Add function definition to the top
if !is_c && f.name != 'main' && p.first_run() { if !is_c && f.name != 'main' && p.first_run() {
// TODO hack to make Volt compile without -embed_vlib // TODO hack to make Volt compile without -embed_vlib
if f.name == 'darwin__nsstring' && p.build_mode == DEFAULT_MODE { if f.name == 'darwin__nsstring' && p.pref.build_mode == DEFAULT_MODE {
return return
} }
p.cgen.fns << fn_decl + ';' p.cgen.fns << fn_decl + ';'
@ -357,13 +357,13 @@ fn (p mut Parser) fn_decl() {
} }
} }
// We are in live code reload mode, call the .so loader in bg // We are in live code reload mode, call the .so loader in bg
if p.is_live { if p.pref.is_live {
p.genln(' p.genln('
load_so("bounce.so"); load_so("bounce.so");
pthread_t _thread_so; pthread_t _thread_so;
pthread_create(&_thread_so , NULL, &reload_so, NULL); ') pthread_create(&_thread_so , NULL, &reload_so, NULL); ')
} }
if p.is_test && !p.scanner.file_path.contains('/volt') { if p.pref.is_test && !p.scanner.file_path.contains('/volt') {
p.error('tests cannot have function `main`') p.error('tests cannot have function `main`')
} }
} }
@ -374,14 +374,14 @@ pthread_create(&_thread_so , NULL, &reload_so, NULL); ')
return return
} }
// We are in profile mode? Start counting at the beginning of the function (save current time). // We are in profile mode? Start counting at the beginning of the function (save current time).
if p.is_prof && f.name != 'main' && f.name != 'time__ticks' { if p.pref.is_prof && f.name != 'main' && f.name != 'time__ticks' {
p.genln('double _PROF_START = time__ticks();//$f.name') p.genln('double _PROF_START = time__ticks();//$f.name')
cgen_name := p.table.cgen_name(f) cgen_name := p.table.cgen_name(f)
f.defer = ' ${cgen_name}_time += time__ticks() - _PROF_START;' f.defer = ' ${cgen_name}_time += time__ticks() - _PROF_START;'
} }
p.statements_no_curly_end() p.statements_no_curly_end()
// Print counting result after all statements in main // Print counting result after all statements in main
if p.is_prof && f.name == 'main' { if p.pref.is_prof && f.name == 'main' {
p.genln(p.print_prof_counters()) p.genln(p.print_prof_counters())
} }
// Counting or not, always need to add defer before the end // Counting or not, always need to add defer before the end
@ -414,14 +414,14 @@ fn (p mut Parser) check_unused_variables() {
if var.name == '' { if var.name == '' {
break break
} }
if !var.is_used && !var.is_arg && !p.translated && var.name != '_' { if !var.is_used && !var.is_arg && !p.pref.translated && var.name != '_' {
p.scanner.line_nr = var.line_nr - 1 p.scanner.line_nr = var.line_nr - 1
p.error('`$var.name` declared and not used') p.error('`$var.name` declared and not used')
} }
// Very basic automatic memory management at the end of the function. // Very basic automatic memory management at the end of the function.
// This is inserted right before the final `}`, so if the object is being returned, // This is inserted right before the final `}`, so if the object is being returned,
// the free method will not be called. // the free method will not be called.
if p.is_test && var.typ.contains('array_') { if p.pref.is_test && var.typ.contains('array_') {
// p.genln('v_${var.typ}_free($var.name); // !!!! XAXA') // p.genln('v_${var.typ}_free($var.name); // !!!! XAXA')
// p.genln('free(${var.name}.data); // !!!! XAXA') // p.genln('free(${var.name}.data); // !!!! XAXA')
} }
@ -500,19 +500,19 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
} }
fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type string) { fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type string) {
if !f.is_public && !f.is_c && !p.is_test && f.pkg != p.pkg { if !f.is_public && !f.is_c && !p.pref.is_test && f.pkg != p.pkg {
p.error('function `$f.name` is private') p.error('function `$f.name` is private')
} }
p.calling_c = f.is_c p.calling_c = f.is_c
is_print := p.is_prod &&// Hide prints only in prod is_print := p.pref.is_prod &&// Hide prints only in prod
!p.is_test && !p.pref.is_test &&
!p.builtin_pkg &&// Allow prints in builtin pkgs !p.builtin_pkg &&// Allow prints in builtin pkgs
f.is_c && f.name == 'printf' f.is_c && f.name == 'printf'
if !p.cgen.nogen { if !p.cgen.nogen {
p.cgen.nogen = is_print p.cgen.nogen = is_print
} }
cgen_name := p.table.cgen_name(f) cgen_name := p.table.cgen_name(f)
// if p.is_prof { // if p.pref.is_prof {
// p.cur_fn.called_fns << cgen_name // p.cur_fn.called_fns << cgen_name
// } // }
// Normal function call // Normal function call
@ -853,4 +853,3 @@ fn (f &Fn) str_args(table *Table) string {
} }
return s return s
} }

View File

@ -58,32 +58,38 @@ enum Pass {
main main
} }
*/ */
struct Preferences {
mut:
build_mode BuildMode
nofmt bool // disable vfmt
is_test bool // `v test string_test.v`
is_script bool // single file mode (`v program.v`), `fn main(){}` can be skipped
is_live bool // for hot code reloading
is_so bool
is_prof bool // benchmark every function
translated bool // `v translate doom.v` are we running V code translated from C? allow globals, ++ expressions, etc
is_prod bool // use "-O2"
is_verbose bool // print extra information with `v.log()`
obfuscate bool // `v -obf program.v`, renames functions to "f_XXX"
is_play bool // playground mode
is_repl bool
is_run bool
show_c_cmd bool // `v -show_c_cmd` prints the C command to build program.v.c
sanitize bool // use Clang's new "-fsanitize" option
}
struct V { struct V {
mut: mut:
build_mode BuildMode
os Os // the OS to build for os Os // the OS to build for
nofmt bool // disable vfmt
out_name_c string // name of the temporary C file out_name_c string // name of the temporary C file
files []string // all V files that need to be parsed and compiled files []string // all V files that need to be parsed and compiled
dir string // directory (or file) being compiled (TODO rename to path?) dir string // directory (or file) being compiled (TODO rename to path?)
table *Table // table with types, vars, functions etc table *Table // table with types, vars, functions etc
cgen *CGen // C code generator cgen *CGen // C code generator
is_test bool // `v test string_test.v` pref *Preferences // all the prefrences and settings extracted to a struct for reusability
is_script bool // single file mode (`v program.v`), `fn main(){}` can be skipped lang_dir string // "~/code/v"
is_so bool
is_live bool // for hot code reloading
is_prof bool // benchmark every function
translated bool // `v translate doom.v` are we running V code translated from C? allow globals, ++ expressions, etc
obfuscate bool // `v -obf program.v`, renames functions to "f_XXX"
lang_dir string // path to V repo
is_verbose bool // print extra information with `v.log()`
is_run bool // `v run program.v`
is_play bool // playground mode
show_c_cmd bool // `v -show_c_cmd` prints the C command to build program.v.c
sanitize bool // use Clang's new "-fsanitize" option
out_name string // "program.exe" out_name string // "program.exe"
is_prod bool // use "-O2"
is_repl bool
vroot string vroot string
} }
@ -137,7 +143,7 @@ fn main() {
} }
// Construct the V object from command line arguments // Construct the V object from command line arguments
mut c := new_v(args) mut c := new_v(args)
if c.is_verbose { if c.pref.is_verbose {
println(args) println(args)
} }
// Generate the docs and exit // Generate the docs and exit
@ -153,7 +159,7 @@ fn (c mut V) compile() {
cgen.genln('// Generated by V') cgen.genln('// Generated by V')
// Add user files to compile // Add user files to compile
c.add_user_v_files() c.add_user_v_files()
if c.is_verbose { if c.pref.is_verbose {
println('all .v files:') println('all .v files:')
println(c.files) println(c.files)
} }
@ -164,7 +170,7 @@ fn (c mut V) compile() {
} }
// Main pass // Main pass
cgen.run = RUN_MAIN cgen.run = RUN_MAIN
if c.is_play { if c.pref.is_play {
cgen.genln('#define VPLAY (1) ') cgen.genln('#define VPLAY (1) ')
} }
cgen.genln(' cgen.genln('
@ -238,23 +244,23 @@ void reload_so();
void init_consts();') void init_consts();')
imports_json := c.table.imports.contains('json') imports_json := c.table.imports.contains('json')
// TODO remove global UI hack // TODO remove global UI hack
if c.os == MAC && ((c.build_mode == EMBED_VLIB && c.table.imports.contains('ui')) || if c.os == MAC && ((c.pref.build_mode == EMBED_VLIB && c.table.imports.contains('ui')) ||
(c.build_mode == BUILD && c.dir.contains('/ui'))) { (c.pref.build_mode == BUILD && c.dir.contains('/ui'))) {
cgen.genln('id defaultFont = 0; // main.v') cgen.genln('id defaultFont = 0; // main.v')
} }
// TODO remove ugly .c include once V has its own json parser // TODO remove ugly .c include once V has its own json parser
// Embed cjson either in embedvlib or in json.o // Embed cjson either in embedvlib or in json.o
if imports_json && c.build_mode == EMBED_VLIB || if imports_json && c.pref.build_mode == EMBED_VLIB ||
(c.build_mode == BUILD && c.out_name.contains('json.o')) { (c.pref.build_mode == BUILD && c.out_name.contains('json.o')) {
cgen.genln('#include "cJSON.c" ') cgen.genln('#include "cJSON.c" ')
} }
// We need the cjson header for all the json decoding user will do in default mode // We need the cjson header for all the json decoding user will do in default mode
if c.build_mode == DEFAULT_MODE { if c.pref.build_mode == DEFAULT_MODE {
if imports_json { if imports_json {
cgen.genln('#include "cJSON.h"') cgen.genln('#include "cJSON.h"')
} }
} }
if c.build_mode == EMBED_VLIB || c.build_mode == DEFAULT_MODE { if c.pref.build_mode == EMBED_VLIB || c.pref.build_mode == DEFAULT_MODE {
// If we declare these for all modes, then when running `v a.v` we'll get // If we declare these for all modes, then when running `v a.v` we'll get
// `/usr/bin/ld: multiple definition of 'total_m'` // `/usr/bin/ld: multiple definition of 'total_m'`
// TODO // TODO
@ -277,7 +283,7 @@ void init_consts();')
p.parse() p.parse()
// p.g.gen_x64() // p.g.gen_x64()
// Format all files (don't format automatically generated vlib headers) // Format all files (don't format automatically generated vlib headers)
if !c.nofmt && !file.contains('/vlib/') { if !c.pref.nofmt && !file.contains('/vlib/') {
// new vfmt is not ready yet // new vfmt is not ready yet
} }
} }
@ -292,14 +298,14 @@ void init_consts();')
d.writeln(cgen.fns.join_lines()) d.writeln(cgen.fns.join_lines())
d.writeln(cgen.consts.join_lines()) d.writeln(cgen.consts.join_lines())
d.writeln(cgen.thread_args.join_lines()) d.writeln(cgen.thread_args.join_lines())
if c.is_prof { if c.pref.is_prof {
d.writeln('; // Prof counters:') d.writeln('; // Prof counters:')
d.writeln(c.prof_counters()) d.writeln(c.prof_counters())
} }
dd := d.str() dd := d.str()
cgen.lines.set(defs_pos, dd)// TODO `def.str()` doesn't compile cgen.lines.set(defs_pos, dd)// TODO `def.str()` doesn't compile
// if c.build_mode in [.default, .embed_vlib] { // if c.build_mode in [.default, .embed_vlib] {
if c.build_mode == DEFAULT_MODE || c.build_mode == EMBED_VLIB { if c.pref.build_mode == DEFAULT_MODE || c.pref.build_mode == EMBED_VLIB {
// vlib can't have `init_consts()` // vlib can't have `init_consts()`
cgen.genln('void init_consts() { g_str_buf=malloc(1000); ${cgen.consts_init.join_lines()} }') cgen.genln('void init_consts() { g_str_buf=malloc(1000); ${cgen.consts_init.join_lines()} }')
// _STR function can't be defined in vlib // _STR function can't be defined in vlib
@ -339,10 +345,10 @@ string _STR_TMP(const char *fmt, ...) {
} }
// Make sure the main function exists // Make sure the main function exists
// Obviously we don't need it in libraries // Obviously we don't need it in libraries
if c.build_mode != BUILD { if c.pref.build_mode != BUILD {
if !c.table.main_exists() && !c.is_test { if !c.table.main_exists() && !c.pref.is_test {
// It can be skipped in single file programs // It can be skipped in single file programs
if c.is_script { if c.pref.is_script {
//println('Generating main()...') //println('Generating main()...')
cgen.genln('int main() { $cgen.fn_main; return 0; }') cgen.genln('int main() { $cgen.fn_main; return 0; }')
} }
@ -351,7 +357,7 @@ string _STR_TMP(const char *fmt, ...) {
} }
} }
// Generate `main` which calls every single test function // Generate `main` which calls every single test function
else if c.is_test { else if c.pref.is_test {
cgen.genln('int main() { init_consts();') cgen.genln('int main() { init_consts();')
for v in c.table.fns { for v in c.table.fns {
if v.name.starts_with('test_') { if v.name.starts_with('test_') {
@ -361,7 +367,7 @@ string _STR_TMP(const char *fmt, ...) {
cgen.genln('return g_test_ok == 0; }') cgen.genln('return g_test_ok == 0; }')
} }
} }
if c.is_live { if c.pref.is_live {
cgen.genln(' int load_so(byteptr path) { cgen.genln(' int load_so(byteptr path) {
printf("load_so %s\\n", path); dlclose(live_lib); live_lib = dlopen(path, RTLD_LAZY); printf("load_so %s\\n", path); dlclose(live_lib); live_lib = dlopen(path, RTLD_LAZY);
if (!live_lib) {puts("open failed"); exit(1); return 0;} if (!live_lib) {puts("open failed"); exit(1); return 0;}
@ -372,13 +378,13 @@ string _STR_TMP(const char *fmt, ...) {
cgen.genln('return 1; }') cgen.genln('return 1; }')
} }
cgen.save() cgen.save()
if c.is_verbose { if c.pref.is_verbose {
c.log('flags=') c.log('flags=')
println(c.table.flags) println(c.table.flags)
} }
c.cc() c.cc()
if c.is_test || c.is_run { if c.pref.is_test || c.pref.is_run {
if true || c.is_verbose { if true || c.pref.is_verbose {
println('============ running $c.out_name ============') println('============ running $c.out_name ============')
} }
mut cmd := if c.out_name.starts_with('/') { mut cmd := if c.out_name.starts_with('/') {
@ -405,32 +411,31 @@ string _STR_TMP(const char *fmt, ...) {
} }
fn (c mut V) cc() { fn (c mut V) cc() {
ticks := time.ticks()
linux_host := os.user_os() == 'linux' linux_host := os.user_os() == 'linux'
c.log('cc() isprod=$c.is_prod outname=$c.out_name') c.log('cc() isprod=$c.pref.is_prod outname=$c.out_name')
mut a := ['-w']// arguments for the C compiler mut a := ['-w']// arguments for the C compiler
flags := c.table.flags.join(' ') flags := c.table.flags.join(' ')
/* /*
mut shared := '' mut shared := ''
if c.is_so { if c.pref.is_so {
a << '-shared'// -Wl,-z,defs' a << '-shared'// -Wl,-z,defs'
c.out_name = c.out_name + '.so' c.out_name = c.out_name + '.so'
} }
*/ */
if c.is_prod { if c.pref.is_prod {
a << '-O2' a << '-O2'
} }
else { else {
a << '-g' a << '-g'
} }
mut libs := ''// builtin.o os.o http.o etc mut libs := ''// builtin.o os.o http.o etc
if c.build_mode == BUILD { if c.pref.build_mode == BUILD {
a << '-c' a << '-c'
} }
else if c.build_mode == EMBED_VLIB { else if c.pref.build_mode == EMBED_VLIB {
// //
} }
else if c.build_mode == DEFAULT_MODE { else if c.pref.build_mode == DEFAULT_MODE {
libs = '$TmpPath/vlib/builtin.o' libs = '$TmpPath/vlib/builtin.o'
if !os.file_exists(libs) { if !os.file_exists(libs) {
println('`builtin.o` not found') println('`builtin.o` not found')
@ -453,7 +458,7 @@ mut args := ''
} }
} }
*/ */
if c.sanitize { if c.pref.sanitize {
a << '-fsanitize=leak' a << '-fsanitize=leak'
} }
// Cross compiling linux // Cross compiling linux
@ -485,11 +490,11 @@ mut args := ''
a << '-x objective-c' a << '-x objective-c'
} }
// Without these libs compilation will fail on Linux // Without these libs compilation will fail on Linux
if c.os == LINUX && c.build_mode != BUILD { if c.os == LINUX && c.pref.build_mode != BUILD {
a << '-lm -ldl -lpthread' a << '-lm -ldl -lpthread'
} }
// Find clang executable // Find clang executable
fast_clang := 'ff'///usr/local/Cellar/llvm/8.0.0/bin/clang' fast_clang := '/usr/local/Cellar/llvm/8.0.0/bin/clang'
args := a.join(' ') args := a.join(' ')
mut cmd := if os.file_exists(fast_clang) { mut cmd := if os.file_exists(fast_clang) {
'$fast_clang $args' '$fast_clang $args'
@ -501,7 +506,7 @@ mut args := ''
cmd = 'gcc $args' cmd = 'gcc $args'
} }
// Print the C command // Print the C command
if c.show_c_cmd || c.is_verbose { if c.pref.show_c_cmd || c.pref.is_verbose {
println('\n==========\n$cmd\n=========\n') println('\n==========\n$cmd\n=========\n')
} }
// Run // Run
@ -512,7 +517,7 @@ mut args := ''
panic('clang error') panic('clang error')
} }
// Link it if we are cross compiling and need an executable // Link it if we are cross compiling and need an executable
if c.os == LINUX && !linux_host && c.build_mode != BUILD { if c.os == LINUX && !linux_host && c.pref.build_mode != BUILD {
c.out_name = c.out_name.replace('.o', '') c.out_name = c.out_name.replace('.o', '')
obj_file := c.out_name + '.o' obj_file := c.out_name + '.o'
println('linux obj_file=$obj_file out_name=$c.out_name') println('linux obj_file=$obj_file out_name=$c.out_name')
@ -531,10 +536,6 @@ mut args := ''
} }
println('linux cross compilation done. resulting binary: "$c.out_name"') println('linux cross compilation done. resulting binary: "$c.out_name"')
} }
if c.show_c_cmd {
diff := time.ticks() - ticks
println('cc() took $diff ms ')
}
//os.rm('$TmpPath/$c.out_name_c') //os.rm('$TmpPath/$c.out_name_c')
} }
@ -546,7 +547,7 @@ fn (c &V) v_files_from_dir(dir string) []string {
panic('$dir isn\'t a directory') panic('$dir isn\'t a directory')
} }
mut files := os.ls(dir) mut files := os.ls(dir)
if c.is_verbose { if c.pref.is_verbose {
println('v_files_from_dir ("$dir")') println('v_files_from_dir ("$dir")')
} }
// println(files.len) // println(files.len)
@ -617,7 +618,7 @@ fn (c mut V) add_user_v_files() {
println('No input .v files') println('No input .v files')
exit(1) exit(1)
} }
if c.is_verbose { if c.pref.is_verbose {
c.log('user_files:') c.log('user_files:')
println(user_files) println(user_files)
} }
@ -627,7 +628,7 @@ fn (c mut V) add_user_v_files() {
p.parse() p.parse()
} }
// Parse lib imports // Parse lib imports
if c.build_mode == DEFAULT_MODE { if c.pref.build_mode == DEFAULT_MODE {
for i := 0; i < c.table.imports.len; i++ { for i := 0; i < c.table.imports.len; i++ {
pkg := c.table.imports[i] pkg := c.table.imports[i]
vfiles := c.v_files_from_dir('$TmpPath/vlib/$pkg') vfiles := c.v_files_from_dir('$TmpPath/vlib/$pkg')
@ -652,7 +653,7 @@ fn (c mut V) add_user_v_files() {
} }
} }
} }
if c.is_verbose { if c.pref.is_verbose {
c.log('imports:') c.log('imports:')
println(c.table.imports) println(c.table.imports)
} }
@ -662,7 +663,7 @@ fn (c mut V) add_user_v_files() {
// If we are in default mode, we don't parse vlib .v files, but header .vh files in // If we are in default mode, we don't parse vlib .v files, but header .vh files in
// TmpPath/vlib // TmpPath/vlib
// These were generated by vfmt // These were generated by vfmt
if c.build_mode == DEFAULT_MODE || c.build_mode == BUILD { if c.pref.build_mode == DEFAULT_MODE || c.pref.build_mode == BUILD {
module_path = '$TmpPath/vlib/$pkg' module_path = '$TmpPath/vlib/$pkg'
} }
vfiles := c.v_files_from_dir(module_path) vfiles := c.v_files_from_dir(module_path)
@ -695,13 +696,13 @@ fn get_arg(joined_args, arg, def string) string {
} }
fn (c &V) log(s string) { fn (c &V) log(s string) {
if !c.is_verbose { if !c.pref.is_verbose {
return return
} }
println(s) println(s)
} }
fn new_v(args []string) *V { fn new_v(args[]string) *V {
mut dir := args.last() mut dir := args.last()
if args.contains('run') { if args.contains('run') {
dir = args[2] dir = args[2]
@ -823,7 +824,25 @@ fn new_v(args []string) *V {
files << f files << f
} }
} }
obfuscate := args.contains('-obf') obfuscate := args.contains('-obf')
pref := &Preferences {
is_test: is_test
is_script: is_script
is_so: args.contains('-shared')
is_play: args.contains('play')
is_prod: args.contains('-prod')
is_verbose: args.contains('-verbose')
obfuscate: obfuscate
is_prof: args.contains('-prof')
is_live: args.contains('-live')
sanitize: args.contains('-sanitize')
nofmt: args.contains('-nofmt')
show_c_cmd: args.contains('-show_c_cmd')
translated: args.contains('translated')
is_run: args.contains('run')
is_repl: args.contains('-repl')
build_mode: build_mode
}
return &V { return &V {
os: _os os: _os
out_name: out_name out_name: out_name
@ -833,24 +852,9 @@ fn new_v(args []string) *V {
table: new_table(obfuscate) table: new_table(obfuscate)
out_name: out_name out_name: out_name
out_name_c: out_name_c out_name_c: out_name_c
is_test: is_test
is_script: is_script
is_so: args.contains('-shared')
is_play: args.contains('play')
is_prod: args.contains('-prod')
is_verbose: args.contains('-verbose')
obfuscate: args.contains('-obf')
is_prof: args.contains('-prof')
is_live: args.contains('-live')
sanitize: args.contains('-sanitize')
nofmt: args.contains('-nofmt')
show_c_cmd: args.contains('-show_c_cmd')
translated: args.contains('translated')
cgen: new_cgen(out_name_c) cgen: new_cgen(out_name_c)
build_mode: build_mode
is_run: args.contains('run')
is_repl: args.contains('-repl')
vroot: lang_dir vroot: lang_dir
pref: pref
} }
} }

View File

@ -48,19 +48,20 @@ mut:
assigned_type string assigned_type string
tmp_cnt int tmp_cnt int
// TODO all these options are copy-pasted from the V struct. Create a Settings struct instead? // TODO all these options are copy-pasted from the V struct. Create a Settings struct instead?
is_test bool // is_test bool
is_script bool is_script bool
is_live bool pref *Preferences // Setting and Preferences shared from V struct
is_so bool // is_live bool
is_prof bool // is_so bool
translated bool // is_prof bool
is_prod bool // translated bool
is_verbose bool // is_prod bool
obfuscate bool // is_verbose bool
is_play bool // obfuscate bool
is_repl bool // is_play bool
// is_repl bool
builtin_pkg bool builtin_pkg bool
build_mode BuildMode // build_mode BuildMode
vh_lines []string vh_lines []string
inside_if_expr bool inside_if_expr bool
is_struct_init bool is_struct_init bool
@ -90,18 +91,19 @@ fn (c mut V) new_parser(path string, run Pass) Parser {
table: c.table table: c.table
cur_fn: EmptyFn cur_fn: EmptyFn
cgen: c.cgen cgen: c.cgen
is_test: c.is_test // is_test: c.pref.is_test
is_script: (c.is_script && path == c.dir) is_script: (c.pref.is_script && path == c.dir)
is_so: c.is_so pref: c.pref
// is_so: c.is_so
os: c.os os: c.os
is_prof: c.is_prof // is_prof: c.is_prof
is_prod: c.is_prod // is_prod: c.is_prod
is_play: c.is_play // is_play: c.is_play
translated: c.translated // translated: c.translated
obfuscate: c.obfuscate // obfuscate: c.obfuscate
is_verbose: c.is_verbose // is_verbose: c.is_verbose
build_mode: c.build_mode // build_mode: c.build_mode
is_repl: c.is_repl // is_repl: c.is_repl
run: run run: run
vroot: c.vroot vroot: c.vroot
} }
@ -119,7 +121,7 @@ fn (p mut Parser) next() {
} }
fn (p &Parser) log(s string) { fn (p &Parser) log(s string) {
if !p.is_verbose { if !p.pref.is_verbose {
return return
} }
println(s) println(s)
@ -128,7 +130,7 @@ fn (p &Parser) log(s string) {
fn (p mut Parser) parse() { fn (p mut Parser) parse() {
p.log('\nparse() run=$p.run file=$p.file_name tok=${p.strtok()}')// , "script_file=", script_file) p.log('\nparse() run=$p.run file=$p.file_name tok=${p.strtok()}')// , "script_file=", script_file)
// `module main` is not required if it's a single file program // `module main` is not required if it's a single file program
if p.is_script || p.is_test { if p.is_script || p.pref.is_test {
p.pkg = 'main' p.pkg = 'main'
// User may still specify `module main` // User may still specify `module main`
if p.tok == PACKAGE { if p.tok == PACKAGE {
@ -175,7 +177,7 @@ fn (p mut Parser) parse() {
// enum without a name, only allowed in code, translated from C // enum without a name, only allowed in code, translated from C
// it's a very bad practice in C as well, but is used unfortunately (for example, by DOOM) // it's a very bad practice in C as well, but is used unfortunately (for example, by DOOM)
// such fields are basically int consts // such fields are basically int consts
else if p.translated { else if p.pref.translated {
p.enum_decl('int') p.enum_decl('int')
} }
else { else {
@ -207,7 +209,7 @@ fn (p mut Parser) parse() {
// $if, $else // $if, $else
p.comp_time() p.comp_time()
case GLOBAL: case GLOBAL:
if !p.translated && !p.builtin_pkg && !p.building_v() { if !p.pref.translated && !p.builtin_pkg && !p.building_v() {
p.error('__global is only allowed in translated code') p.error('__global is only allowed in translated code')
} }
p.next() p.next()
@ -230,7 +232,7 @@ fn (p mut Parser) parse() {
p.cgen.consts << g p.cgen.consts << g
case EOF: case EOF:
p.log('end of parse()') p.log('end of parse()')
if p.is_script && !p.is_test { if p.is_script && !p.pref.is_test {
p.cur_fn = MainFn p.cur_fn = MainFn
p.check_unused_variables() p.check_unused_variables()
} }
@ -242,7 +244,7 @@ fn (p mut Parser) parse() {
return return
default: default:
// no `fn main`, add this "global" statement to cgen.fn_main // no `fn main`, add this "global" statement to cgen.fn_main
if p.is_script && !p.is_test { if p.is_script && !p.pref.is_test {
// cur_fn is empty since there was no fn main declared // cur_fn is empty since there was no fn main declared
// we need to set it to save and find variables // we need to set it to save and find variables
if p.first_run() { if p.first_run() {
@ -253,7 +255,7 @@ fn (p mut Parser) parse() {
} }
if p.cur_fn.name == '' { if p.cur_fn.name == '' {
p.cur_fn = MainFn p.cur_fn = MainFn
if p.is_repl { if p.pref.is_repl {
p.cur_fn.clear_vars() p.cur_fn.clear_vars()
} }
} }
@ -324,7 +326,7 @@ fn (p mut Parser) const_decl() {
for p.tok == NAME { for p.tok == NAME {
// `Age = 20` // `Age = 20`
mut name := p.check_name() mut name := p.check_name()
if p.is_play && ! (name[0] >= `A` && name[0] <= `Z`) { if p.pref.is_play && ! (name[0] >= `A` && name[0] <= `Z`) {
p.error('const name must be capitalized') p.error('const name must be capitalized')
} }
// Imported consts (like GL_TRIANGLES) dont need pkg prepended (gl__GL_TRIANGLES) // Imported consts (like GL_TRIANGLES) dont need pkg prepended (gl__GL_TRIANGLES)
@ -407,7 +409,7 @@ fn (p mut Parser) struct_decl() {
// Get type name // Get type name
p.next() p.next()
mut name := p.check_name() mut name := p.check_name()
if name.contains('_') && !p.translated { if name.contains('_') && !p.pref.translated {
p.error('type names cannot contain `_`') p.error('type names cannot contain `_`')
} }
if is_interface && !name.ends_with('er') { if is_interface && !name.ends_with('er') {
@ -521,7 +523,7 @@ fn (p mut Parser) struct_decl() {
is_method: true is_method: true
receiver_typ: name receiver_typ: name
} }
//println('is interface. field=$field_name run=$p.run') println('is interface. field=$field_name run=$p.run')
p.fn_args(mut interface_method) p.fn_args(mut interface_method)
p.fspace() p.fspace()
interface_method.typ = p.get_type()// method return type interface_method.typ = p.get_type()// method return type
@ -670,13 +672,13 @@ fn (p mut Parser) error(s string) {
file_types.close() file_types.close()
file_vars.close() file_vars.close()
} }
if !p.is_repl { if !p.pref.is_repl {
println('pass=$p.run fn=`$p.cur_fn.name`') println('pass=$p.run fn=`$p.cur_fn.name`')
} }
p.cgen.save() p.cgen.save()
// V git pull hint // V git pull hint
cur_path := os.getwd() cur_path := os.getwd()
if !p.is_repl && ( p.file_path.contains('v/compiler') || cur_path.contains('v/compiler') ){ if !p.pref.is_repl && ( p.file_path.contains('v/compiler') || cur_path.contains('v/compiler') ){
println('\n=========================') println('\n=========================')
println('It looks like you are building V. It is being frequently updated every day.') println('It looks like you are building V. It is being frequently updated every day.')
println('If you didn\'t modify the compiler\'s code, most likely there was a change that ') println('If you didn\'t modify the compiler\'s code, most likely there was a change that ')
@ -797,7 +799,7 @@ fn (p mut Parser) get_type() string {
typ = p.prepend_pkg(typ) typ = p.prepend_pkg(typ)
} }
t = p.table.find_type(typ) t = p.table.find_type(typ)
if t.name == '' && !p.translated && !p.first_run() && !typ.starts_with('[') { if t.name == '' && !p.pref.translated && !p.first_run() && !typ.starts_with('[') {
println('get_type() bad type') println('get_type() bad type')
// println('all registered types:') // println('all registered types:')
// for q in p.table.types { // for q in p.table.types {
@ -837,7 +839,7 @@ fn (p mut Parser) get_type() string {
return 'byte*' return 'byte*'
} }
if typ == 'voidptr' { if typ == 'voidptr' {
//if !p.builtin_pkg && p.pkg != 'os' && p.pkg != 'gx' && p.pkg != 'gg' && !p.translated { //if !p.builtin_pkg && p.pkg != 'os' && p.pkg != 'gx' && p.pkg != 'gg' && !p.pref.translated {
//p.error('voidptr can only be used in unsafe code') //p.error('voidptr can only be used in unsafe code')
//} //}
return 'void*' return 'void*'
@ -936,7 +938,7 @@ fn (p mut Parser) statement(add_semi bool) string {
switch tok { switch tok {
case NAME: case NAME:
next := p.peek() next := p.peek()
if p.is_verbose { if p.pref.is_verbose {
println(next.str()) println(next.str())
} }
// goto_label: // goto_label:
@ -1028,7 +1030,7 @@ fn (p mut Parser) statement(add_semi bool) string {
fn (p mut Parser) assign_statement(v Var, ph int, is_map bool) { fn (p mut Parser) assign_statement(v Var, ph int, is_map bool) {
p.log('assign_statement() name=$v.name tok=') p.log('assign_statement() name=$v.name tok=')
tok := p.tok tok := p.tok
if !v.is_mut && !v.is_arg && !p.translated && !v.is_global{ if !v.is_mut && !v.is_arg && !p.pref.translated && !v.is_global{
p.error('`$v.name` is immutable') p.error('`$v.name` is immutable')
} }
is_str := v.typ == 'string' is_str := v.typ == 'string'
@ -1202,7 +1204,7 @@ fn (p mut Parser) name_expr() string {
p.next() p.next()
} }
if deref { if deref {
if p.is_play && !p.builtin_pkg { if p.pref.is_play && !p.builtin_pkg {
p.error('dereferencing is temporarily disabled on the playground, will be fixed soon') p.error('dereferencing is temporarily disabled on the playground, will be fixed soon')
} }
} }
@ -1428,11 +1430,11 @@ fn (p mut Parser) var_expr(v Var) string {
} }
// a++ and a-- // a++ and a--
if p.tok == INC || p.tok == DEC { if p.tok == INC || p.tok == DEC {
if !v.is_mut && !v.is_arg && !p.translated { if !v.is_mut && !v.is_arg && !p.pref.translated {
p.error('`$v.name` is immutable') p.error('`$v.name` is immutable')
} }
if typ != 'int' { if typ != 'int' {
if !p.translated && !is_number_type(typ) { if !p.pref.translated && !is_number_type(typ) {
// if T.parent != 'int' { // if T.parent != 'int' {
p.error('cannot ++/-- value of type `$typ`') p.error('cannot ++/-- value of type `$typ`')
} }
@ -1441,7 +1443,7 @@ fn (p mut Parser) var_expr(v Var) string {
p.fgen(p.tok.str()) p.fgen(p.tok.str())
p.next()// ++ p.next()// ++
// allow a := c++ in translated // allow a := c++ in translated
if p.translated { if p.pref.translated {
return p.index_expr(typ, fn_ph) return p.index_expr(typ, fn_ph)
// return typ // return typ
} }
@ -1502,14 +1504,14 @@ fn (p mut Parser) dot(str_typ string, method_ph int) string {
next := p.peek() next := p.peek()
modifying := next.is_assign() || next == INC || next == DEC modifying := next.is_assign() || next == INC || next == DEC
is_vi := p.fileis('vi') is_vi := p.fileis('vi')
if !p.builtin_pkg && !p.translated && modifying && !field.is_mut && !is_vi { if !p.builtin_pkg && !p.pref.translated && modifying && !field.is_mut && !is_vi {
p.error('cannot modify immutable field `$field_name` (type `$typ.name`)') p.error('cannot modify immutable field `$field_name` (type `$typ.name`)')
} }
if !p.builtin_pkg && p.pkg != typ.pkg { if !p.builtin_pkg && p.pkg != typ.pkg {
} }
// if p.is_play && field.access_mod == PRIVATE && !p.builtin_pkg && p.pkg != typ.pkg { // if p.pref.is_play && field.access_mod == PRIVATE && !p.builtin_pkg && p.pkg != typ.pkg {
// Don't allow `arr.data` // Don't allow `arr.data`
if field.access_mod == PRIVATE && !p.builtin_pkg && !p.translated && p.pkg != typ.pkg { if field.access_mod == PRIVATE && !p.builtin_pkg && !p.pref.translated && p.pkg != typ.pkg {
// println('$typ.name :: $field.name ') // println('$typ.name :: $field.name ')
// println(field.access_mod) // println(field.access_mod)
p.error('cannot refer to unexported field `$field_name` (type `$typ.name`)') p.error('cannot refer to unexported field `$field_name` (type `$typ.name`)')
@ -1521,7 +1523,7 @@ fn (p mut Parser) dot(str_typ string, method_ph int) string {
// println('HOHOH') // println('HOHOH')
// println(next.str()) // println(next.str())
// } // }
if !field.is_mut && !p.translated && modifying { if !field.is_mut && !p.pref.translated && modifying {
p.error('cannot modify public immutable field `$field_name` (type `$typ.name`)') p.error('cannot modify public immutable field `$field_name` (type `$typ.name`)')
} }
} }
@ -1624,7 +1626,7 @@ fn (p mut Parser) index_expr(typ string, fn_ph int) string {
typ = 'void*' typ = 'void*'
} }
// No bounds check in translated from C code // No bounds check in translated from C code
if p.translated { if p.pref.translated {
// Cast void* to typ*: add (typ*) to the beginning of the assignment : // Cast void* to typ*: add (typ*) to the beginning of the assignment :
// ((int*)a.data = ... // ((int*)a.data = ...
p.cgen.set_placeholder(fn_ph, '(($typ*)(') p.cgen.set_placeholder(fn_ph, '(($typ*)(')
@ -1705,7 +1707,7 @@ fn (p mut Parser) index_expr(typ string, fn_ph int) string {
return typ return typ
return 'void' return 'void'
} }
// else if p.is_verbose && p.assigned_var != '' { // else if p.pref.is_verbose && p.assigned_var != '' {
// p.error('didnt assign') // p.error('didnt assign')
// } // }
// m[key]. no =, just a getter // m[key]. no =, just a getter
@ -1724,7 +1726,7 @@ fn (p mut Parser) index_expr(typ string, fn_ph int) string {
p.cgen.insert_before('$typ $tmp = $def; bool $tmp_ok = map_get($index_expr, & $tmp);') p.cgen.insert_before('$typ $tmp = $def; bool $tmp_ok = map_get($index_expr, & $tmp);')
} }
else if is_arr { else if is_arr {
if p.translated { if p.pref.translated {
p.gen('$index_expr ]') p.gen('$index_expr ]')
} }
else { else {
@ -1768,7 +1770,7 @@ fn (p mut Parser) expression() string {
// Get the value we are pushing // Get the value we are pushing
p.gen(', (') p.gen(', (')
// Immutable? Can we push? // Immutable? Can we push?
if !p.expr_var.is_mut && !p.translated { if !p.expr_var.is_mut && !p.pref.translated {
p.error('`$p.expr_var.name` is immutable (can\'t <<)') p.error('`$p.expr_var.name` is immutable (can\'t <<)')
} }
p.check_types(p.expression(), tmp_typ) p.check_types(p.expression(), tmp_typ)
@ -1833,7 +1835,7 @@ fn (p mut Parser) expression() string {
} }
// Vec + Vec // Vec + Vec
else { else {
if p.translated { if p.pref.translated {
p.gen(tok_op.str() + ' /*doom hack*/')// TODO hack to fix DOOM's angle_t p.gen(tok_op.str() + ' /*doom hack*/')// TODO hack to fix DOOM's angle_t
} }
else { else {
@ -1845,7 +1847,7 @@ fn (p mut Parser) expression() string {
p.gen(')') p.gen(')')
} }
// Make sure operators are used with correct types // Make sure operators are used with correct types
if !p.translated && !is_str && !is_num { if !p.pref.translated && !is_str && !is_num {
T := p.table.find_type(typ) T := p.table.find_type(typ)
if tok_op == PLUS { if tok_op == PLUS {
if T.has_method('+') { if T.has_method('+') {
@ -2122,7 +2124,7 @@ fn (p mut Parser) string_expr() {
// println('before format: "$str"') // println('before format: "$str"')
f := format_str(str) f := format_str(str)
// println('after format: "$str"') // println('after format: "$str"')
if p.calling_c || p.translated { if p.calling_c || p.pref.translated {
p.gen('"$f"') p.gen('"$f"')
} }
else { else {
@ -2182,7 +2184,7 @@ fn (p mut Parser) string_expr() {
} }
// Don't allocate a new string, just print it. TODO HACK PRINT OPT // Don't allocate a new string, just print it. TODO HACK PRINT OPT
cur_line := p.cgen.cur_line.trim_space() cur_line := p.cgen.cur_line.trim_space()
if cur_line.contains('println(') && p.tok != PLUS && !p.is_prod && !cur_line.contains('string_add') { if cur_line.contains('println(') && p.tok != PLUS && !p.pref.is_prod && !cur_line.contains('string_add') {
p.cgen.cur_line = cur_line.replace('println(', 'printf(') p.cgen.cur_line = cur_line.replace('println(', 'printf(')
p.gen('$format\\n$args') p.gen('$format\\n$args')
return return
@ -2587,10 +2589,10 @@ fn (p mut Parser) chash() {
// p.cgen.nogen = true // p.cgen.nogen = true
} }
if hash == 'live' { if hash == 'live' {
if p.is_so { if p.pref.is_so {
return return
} }
p.is_live = true p.pref.is_live = true
return return
} }
if hash.starts_with('flag ') { if hash.starts_with('flag ') {
@ -2635,7 +2637,7 @@ fn (p mut Parser) chash() {
else if hash.contains('embed') { else if hash.contains('embed') {
pos := hash.index('embed') + 5 pos := hash.index('embed') + 5
file := hash.right(pos) file := hash.right(pos)
if p.build_mode != DEFAULT_MODE { if p.pref.build_mode != DEFAULT_MODE {
p.genln('#include $file') p.genln('#include $file')
} }
} }
@ -3142,5 +3144,3 @@ fn (p mut Parser) fspace() {
fn (p mut Parser) fgenln(s string) { fn (p mut Parser) fgenln(s string) {
//p.scanner.fgenln(s) //p.scanner.fgenln(s)
} }

View File

@ -414,7 +414,7 @@ fn (t &Table) find_type(name string) *Type {
fn (p mut Parser) _check_types(got, expected string, throw bool) bool { fn (p mut Parser) _check_types(got, expected string, throw bool) bool {
p.log('check types got="$got" exp="$expected" ') p.log('check types got="$got" exp="$expected" ')
if p.translated { if p.pref.translated {
return true return true
} }
// Allow ints to be used as floats // Allow ints to be used as floats
@ -443,7 +443,7 @@ fn (p mut Parser) _check_types(got, expected string, throw bool) bool {
// Todo void* allows everything right now // Todo void* allows everything right now
if got=='void*' || expected=='void*' { if got=='void*' || expected=='void*' {
// if !p.builtin_pkg { // if !p.builtin_pkg {
if p.is_play { if p.pref.is_play {
return false return false
} }
return true return true
@ -475,7 +475,7 @@ fn (p mut Parser) _check_types(got, expected string, throw bool) bool {
return true return true
} }
// NsColor* return 0 // NsColor* return 0
if !p.is_play { if !p.pref.is_play {
if expected.ends_with('*') && got == 'int' { if expected.ends_with('*') && got == 'int' {
return true return true
} }