diff --git a/compiler/fn.v b/compiler/fn.v index 625b2b7103..061e6c71f2 100644 --- a/compiler/fn.v +++ b/compiler/fn.v @@ -95,7 +95,7 @@ fn (f mut Fn) clear_vars() { // vlib header file? 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)) } @@ -173,8 +173,8 @@ fn (p mut Parser) fn_decl() { // C function header def? (fn C.NSMakeRect(int,int,int,int)) is_c := f.name == 'C' && p.tok == DOT // Just fn signature? only builtin.v + default build mode - // is_sig := p.builtin_pkg && p.build_mode == DEFAULT_MODE - // is_sig := p.build_mode == DEFAULT_MODE && (p.builtin_pkg || p.file.contains(LANG_TMP)) + // is_sig := p.builtin_pkg && p.pref.build_mode == DEFAULT_MODE + // is_sig := p.pref.build_mode == DEFAULT_MODE && (p.builtin_pkg || p.file.contains(LANG_TMP)) is_sig := p.is_sig() // println('\n\nfn decl !!is_sig=$is_sig name=$f.name $p.builtin_pkg') if is_c { @@ -182,7 +182,7 @@ fn (p mut Parser) fn_decl() { f.name = p.check_name() 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) { 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() } // 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)) if is_fn_header { f.is_decl = true @@ -274,10 +274,10 @@ fn (p mut Parser) fn_decl() { // } mut fn_name_cgen := p.table.cgen_name(f) // Start generation of the function body - is_live := p.is_live && f.name != 'main' && f.name != 'reload_so' - skip_main_in_test := f.name == 'main' && p.is_test + is_live := p.pref.is_live && f.name != 'main' && f.name != 'reload_so' + 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 p.obfuscate { + if p.pref.obfuscate { p.genln('; // ${f.name}') } p.genln('$typ $fn_name_cgen($str_args) {') @@ -332,13 +332,13 @@ fn (p mut Parser) fn_decl() { } // Actual fn declaration! mut fn_decl := '$typ $fn_name_cgen($str_args)' - if p.obfuscate { + if p.pref.obfuscate { fn_decl += '; // ${f.name}' } // Add function definition to the top if !is_c && f.name != 'main' && p.first_run() { // 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 } 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 - if p.is_live { + if p.pref.is_live { p.genln(' load_so("bounce.so"); pthread_t _thread_so; 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`') } } @@ -374,14 +374,14 @@ pthread_create(&_thread_so , NULL, &reload_so, NULL); ') return } // 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') cgen_name := p.table.cgen_name(f) f.defer = ' ${cgen_name}_time += time__ticks() - _PROF_START;' } p.statements_no_curly_end() // 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()) } // 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 == '' { 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.error('`$var.name` declared and not used') } // 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, // 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('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) { - 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.calling_c = f.is_c - is_print := p.is_prod &&// Hide prints only in prod - !p.is_test && + is_print := p.pref.is_prod &&// Hide prints only in prod + !p.pref.is_test && !p.builtin_pkg &&// Allow prints in builtin pkgs f.is_c && f.name == 'printf' if !p.cgen.nogen { p.cgen.nogen = is_print } cgen_name := p.table.cgen_name(f) - // if p.is_prof { + // if p.pref.is_prof { // p.cur_fn.called_fns << cgen_name // } // Normal function call @@ -853,4 +853,3 @@ fn (f &Fn) str_args(table *Table) string { } return s } - diff --git a/compiler/main.v b/compiler/main.v index 4b247ae72d..978e53988e 100644 --- a/compiler/main.v +++ b/compiler/main.v @@ -58,32 +58,38 @@ enum Pass { 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 { mut: - build_mode BuildMode os Os // the OS to build for - nofmt bool // disable vfmt out_name_c string // name of the temporary C file files []string // all V files that need to be parsed and compiled dir string // directory (or file) being compiled (TODO rename to path?) table *Table // table with types, vars, functions etc cgen *CGen // C code generator - is_test bool // `v test string_test.v` - is_script bool // single file mode (`v program.v`), `fn main(){}` can be skipped - 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 + pref *Preferences // all the prefrences and settings extracted to a struct for reusability + lang_dir string // "~/code/v" out_name string // "program.exe" - is_prod bool // use "-O2" - is_repl bool vroot string } @@ -137,7 +143,7 @@ fn main() { } // Construct the V object from command line arguments mut c := new_v(args) - if c.is_verbose { + if c.pref.is_verbose { println(args) } // Generate the docs and exit @@ -153,7 +159,7 @@ fn (c mut V) compile() { cgen.genln('// Generated by V') // Add user files to compile c.add_user_v_files() - if c.is_verbose { + if c.pref.is_verbose { println('all .v files:') println(c.files) } @@ -164,7 +170,7 @@ fn (c mut V) compile() { } // Main pass cgen.run = RUN_MAIN - if c.is_play { + if c.pref.is_play { cgen.genln('#define VPLAY (1) ') } cgen.genln(' @@ -238,23 +244,23 @@ void reload_so(); void init_consts();') imports_json := c.table.imports.contains('json') // TODO remove global UI hack - if c.os == MAC && ((c.build_mode == EMBED_VLIB && c.table.imports.contains('ui')) || - (c.build_mode == BUILD && c.dir.contains('/ui'))) { + if c.os == MAC && ((c.pref.build_mode == EMBED_VLIB && c.table.imports.contains('ui')) || + (c.pref.build_mode == BUILD && c.dir.contains('/ui'))) { cgen.genln('id defaultFont = 0; // main.v') } // TODO remove ugly .c include once V has its own json parser // Embed cjson either in embedvlib or in json.o - if imports_json && c.build_mode == EMBED_VLIB || - (c.build_mode == BUILD && c.out_name.contains('json.o')) { + if imports_json && c.pref.build_mode == EMBED_VLIB || + (c.pref.build_mode == BUILD && c.out_name.contains('json.o')) { cgen.genln('#include "cJSON.c" ') } // 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 { 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 // `/usr/bin/ld: multiple definition of 'total_m'` // TODO @@ -277,7 +283,7 @@ void init_consts();') p.parse() // p.g.gen_x64() // 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 } } @@ -292,14 +298,14 @@ void init_consts();') d.writeln(cgen.fns.join_lines()) d.writeln(cgen.consts.join_lines()) d.writeln(cgen.thread_args.join_lines()) - if c.is_prof { + if c.pref.is_prof { d.writeln('; // Prof counters:') d.writeln(c.prof_counters()) } dd := d.str() cgen.lines.set(defs_pos, dd)// TODO `def.str()` doesn't compile // 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()` cgen.genln('void init_consts() { g_str_buf=malloc(1000); ${cgen.consts_init.join_lines()} }') // _STR function can't be defined in vlib @@ -339,10 +345,10 @@ string _STR_TMP(const char *fmt, ...) { } // Make sure the main function exists // Obviously we don't need it in libraries - if c.build_mode != BUILD { - if !c.table.main_exists() && !c.is_test { + if c.pref.build_mode != BUILD { + if !c.table.main_exists() && !c.pref.is_test { // It can be skipped in single file programs - if c.is_script { + if c.pref.is_script { //println('Generating main()...') 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 - else if c.is_test { + else if c.pref.is_test { cgen.genln('int main() { init_consts();') for v in c.table.fns { if v.name.starts_with('test_') { @@ -361,7 +367,7 @@ string _STR_TMP(const char *fmt, ...) { cgen.genln('return g_test_ok == 0; }') } } - if c.is_live { + if c.pref.is_live { cgen.genln(' int load_so(byteptr path) { 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;} @@ -372,13 +378,13 @@ string _STR_TMP(const char *fmt, ...) { cgen.genln('return 1; }') } cgen.save() - if c.is_verbose { + if c.pref.is_verbose { c.log('flags=') println(c.table.flags) } c.cc() - if c.is_test || c.is_run { - if true || c.is_verbose { + if c.pref.is_test || c.pref.is_run { + if true || c.pref.is_verbose { println('============ running $c.out_name ============') } mut cmd := if c.out_name.starts_with('/') { @@ -405,32 +411,31 @@ string _STR_TMP(const char *fmt, ...) { } fn (c mut V) cc() { - ticks := time.ticks() 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 flags := c.table.flags.join(' ') /* mut shared := '' - if c.is_so { + if c.pref.is_so { a << '-shared'// -Wl,-z,defs' c.out_name = c.out_name + '.so' } */ - if c.is_prod { + if c.pref.is_prod { a << '-O2' } else { a << '-g' } mut libs := ''// builtin.o os.o http.o etc - if c.build_mode == BUILD { + if c.pref.build_mode == BUILD { 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' if !os.file_exists(libs) { println('`builtin.o` not found') @@ -453,7 +458,7 @@ mut args := '' } } */ - if c.sanitize { + if c.pref.sanitize { a << '-fsanitize=leak' } // Cross compiling linux @@ -485,11 +490,11 @@ mut args := '' a << '-x objective-c' } // 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' } // 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(' ') mut cmd := if os.file_exists(fast_clang) { '$fast_clang $args' @@ -501,7 +506,7 @@ mut args := '' cmd = 'gcc $args' } // 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') } // Run @@ -512,7 +517,7 @@ mut args := '' panic('clang error') } // 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', '') obj_file := c.out_name + '.o' 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"') } - if c.show_c_cmd { - diff := time.ticks() - ticks - println('cc() took $diff ms ') - } //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') } mut files := os.ls(dir) - if c.is_verbose { + if c.pref.is_verbose { println('v_files_from_dir ("$dir")') } // println(files.len) @@ -617,7 +618,7 @@ fn (c mut V) add_user_v_files() { println('No input .v files') exit(1) } - if c.is_verbose { + if c.pref.is_verbose { c.log('user_files:') println(user_files) } @@ -627,7 +628,7 @@ fn (c mut V) add_user_v_files() { p.parse() } // 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++ { pkg := c.table.imports[i] 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:') 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 // TmpPath/vlib // 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' } 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) { - if !c.is_verbose { + if !c.pref.is_verbose { return } println(s) } -fn new_v(args []string) *V { +fn new_v(args[]string) *V { mut dir := args.last() if args.contains('run') { dir = args[2] @@ -823,7 +824,25 @@ fn new_v(args []string) *V { 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 { os: _os out_name: out_name @@ -833,24 +852,9 @@ fn new_v(args []string) *V { table: new_table(obfuscate) out_name: out_name 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) - build_mode: build_mode - is_run: args.contains('run') - is_repl: args.contains('-repl') vroot: lang_dir + pref: pref } } diff --git a/compiler/parser.v b/compiler/parser.v index bc77ca9241..b6444b2f51 100644 --- a/compiler/parser.v +++ b/compiler/parser.v @@ -48,19 +48,20 @@ mut: assigned_type string tmp_cnt int // 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_live bool - is_so bool - is_prof bool - translated bool - is_prod bool - is_verbose bool - obfuscate bool - is_play bool - is_repl bool + pref *Preferences // Setting and Preferences shared from V struct + // is_live bool + // is_so bool + // is_prof bool + // translated bool + // is_prod bool + // is_verbose bool + // obfuscate bool + // is_play bool + // is_repl bool builtin_pkg bool - build_mode BuildMode + // build_mode BuildMode vh_lines []string inside_if_expr bool is_struct_init bool @@ -90,18 +91,19 @@ fn (c mut V) new_parser(path string, run Pass) Parser { table: c.table cur_fn: EmptyFn cgen: c.cgen - is_test: c.is_test - is_script: (c.is_script && path == c.dir) - is_so: c.is_so + // is_test: c.pref.is_test + is_script: (c.pref.is_script && path == c.dir) + pref: c.pref + // is_so: c.is_so os: c.os - is_prof: c.is_prof - is_prod: c.is_prod - is_play: c.is_play - translated: c.translated - obfuscate: c.obfuscate - is_verbose: c.is_verbose - build_mode: c.build_mode - is_repl: c.is_repl + // is_prof: c.is_prof + // is_prod: c.is_prod + // is_play: c.is_play + // translated: c.translated + // obfuscate: c.obfuscate + // is_verbose: c.is_verbose + // build_mode: c.build_mode + // is_repl: c.is_repl run: run vroot: c.vroot } @@ -119,7 +121,7 @@ fn (p mut Parser) next() { } fn (p &Parser) log(s string) { - if !p.is_verbose { + if !p.pref.is_verbose { return } println(s) @@ -128,7 +130,7 @@ fn (p &Parser) log(s string) { fn (p mut Parser) parse() { 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 - if p.is_script || p.is_test { + if p.is_script || p.pref.is_test { p.pkg = 'main' // User may still specify `module main` if p.tok == PACKAGE { @@ -175,7 +177,7 @@ fn (p mut Parser) parse() { // 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) // such fields are basically int consts - else if p.translated { + else if p.pref.translated { p.enum_decl('int') } else { @@ -207,7 +209,7 @@ fn (p mut Parser) parse() { // $if, $else p.comp_time() 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.next() @@ -230,7 +232,7 @@ fn (p mut Parser) parse() { p.cgen.consts << g case EOF: 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.check_unused_variables() } @@ -242,7 +244,7 @@ fn (p mut Parser) parse() { return default: // 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 // we need to set it to save and find variables if p.first_run() { @@ -253,7 +255,7 @@ fn (p mut Parser) parse() { } if p.cur_fn.name == '' { p.cur_fn = MainFn - if p.is_repl { + if p.pref.is_repl { p.cur_fn.clear_vars() } } @@ -324,7 +326,7 @@ fn (p mut Parser) const_decl() { for p.tok == NAME { // `Age = 20` 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') } // 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 p.next() mut name := p.check_name() - if name.contains('_') && !p.translated { + if name.contains('_') && !p.pref.translated { p.error('type names cannot contain `_`') } if is_interface && !name.ends_with('er') { @@ -521,7 +523,7 @@ fn (p mut Parser) struct_decl() { is_method: true 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.fspace() interface_method.typ = p.get_type()// method return type @@ -670,13 +672,13 @@ fn (p mut Parser) error(s string) { file_types.close() file_vars.close() } - if !p.is_repl { + if !p.pref.is_repl { println('pass=$p.run fn=`$p.cur_fn.name`') } p.cgen.save() // V git pull hint 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('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 ') @@ -797,7 +799,7 @@ fn (p mut Parser) get_type() string { typ = p.prepend_pkg(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('all registered types:') // for q in p.table.types { @@ -837,7 +839,7 @@ fn (p mut Parser) get_type() string { return 'byte*' } 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') //} return 'void*' @@ -936,7 +938,7 @@ fn (p mut Parser) statement(add_semi bool) string { switch tok { case NAME: next := p.peek() - if p.is_verbose { + if p.pref.is_verbose { println(next.str()) } // 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) { p.log('assign_statement() name=$v.name 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') } is_str := v.typ == 'string' @@ -1202,7 +1204,7 @@ fn (p mut Parser) name_expr() string { p.next() } 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') } } @@ -1428,11 +1430,11 @@ fn (p mut Parser) var_expr(v Var) string { } // a++ and a-- 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') } if typ != 'int' { - if !p.translated && !is_number_type(typ) { + if !p.pref.translated && !is_number_type(typ) { // if T.parent != 'int' { 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.next()// ++ // allow a := c++ in translated - if p.translated { + if p.pref.translated { return p.index_expr(typ, fn_ph) // return typ } @@ -1502,14 +1504,14 @@ fn (p mut Parser) dot(str_typ string, method_ph int) string { next := p.peek() modifying := next.is_assign() || next == INC || next == DEC 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`)') } 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` - 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(field.access_mod) 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(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`)') } } @@ -1624,7 +1626,7 @@ fn (p mut Parser) index_expr(typ string, fn_ph int) string { typ = 'void*' } // 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 : // ((int*)a.data = ... 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 'void' } - // else if p.is_verbose && p.assigned_var != '' { + // else if p.pref.is_verbose && p.assigned_var != '' { // p.error('didnt assign') // } // 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);') } else if is_arr { - if p.translated { + if p.pref.translated { p.gen('$index_expr ]') } else { @@ -1768,7 +1770,7 @@ fn (p mut Parser) expression() string { // Get the value we are pushing p.gen(', (') // 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.check_types(p.expression(), tmp_typ) @@ -1833,7 +1835,7 @@ fn (p mut Parser) expression() string { } // Vec + Vec else { - if p.translated { + if p.pref.translated { p.gen(tok_op.str() + ' /*doom hack*/')// TODO hack to fix DOOM's angle_t } else { @@ -1845,7 +1847,7 @@ fn (p mut Parser) expression() string { p.gen(')') } // 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) if tok_op == PLUS { if T.has_method('+') { @@ -2122,7 +2124,7 @@ fn (p mut Parser) string_expr() { // println('before format: "$str"') f := format_str(str) // println('after format: "$str"') - if p.calling_c || p.translated { + if p.calling_c || p.pref.translated { p.gen('"$f"') } else { @@ -2182,7 +2184,7 @@ fn (p mut Parser) string_expr() { } // Don't allocate a new string, just print it. TODO HACK PRINT OPT 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.gen('$format\\n$args') return @@ -2587,10 +2589,10 @@ fn (p mut Parser) chash() { // p.cgen.nogen = true } if hash == 'live' { - if p.is_so { + if p.pref.is_so { return } - p.is_live = true + p.pref.is_live = true return } if hash.starts_with('flag ') { @@ -2635,7 +2637,7 @@ fn (p mut Parser) chash() { else if hash.contains('embed') { pos := hash.index('embed') + 5 file := hash.right(pos) - if p.build_mode != DEFAULT_MODE { + if p.pref.build_mode != DEFAULT_MODE { p.genln('#include $file') } } @@ -3142,5 +3144,3 @@ fn (p mut Parser) fspace() { fn (p mut Parser) fgenln(s string) { //p.scanner.fgenln(s) } - - diff --git a/compiler/table.v b/compiler/table.v index d067c91f09..5c9f5dbdfb 100644 --- a/compiler/table.v +++ b/compiler/table.v @@ -414,7 +414,7 @@ fn (t &Table) find_type(name string) *Type { fn (p mut Parser) _check_types(got, expected string, throw bool) bool { p.log('check types got="$got" exp="$expected" ') - if p.translated { + if p.pref.translated { return true } // 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 if got=='void*' || expected=='void*' { // if !p.builtin_pkg { - if p.is_play { + if p.pref.is_play { return false } return true @@ -475,7 +475,7 @@ fn (p mut Parser) _check_types(got, expected string, throw bool) bool { return true } // NsColor* return 0 - if !p.is_play { + if !p.pref.is_play { if expected.ends_with('*') && got == 'int' { return true }