diff --git a/compiler/compile_errors.v b/compiler/compile_errors.v index 790f60d8ac..82745dc945 100644 --- a/compiler/compile_errors.v +++ b/compiler/compile_errors.v @@ -154,7 +154,7 @@ fn (p mut Parser) print_error_context(){ p.cgen.save() // V up hint cur_path := os.getwd() - if !p.pref.is_repl && !p.pref.is_test && ( p.file_path.contains('v/compiler') || cur_path.contains('v/compiler') ){ + if !p.pref.is_repl && !p.pref.is_test && ( p.file_path_id.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 V\'s code, most likely there was a change that ') diff --git a/compiler/fn.v b/compiler/fn.v index b4d820429f..1b3089fd52 100644 --- a/compiler/fn.v +++ b/compiler/fn.v @@ -183,7 +183,7 @@ fn (p mut Parser) fn_decl() { } // Don't allow modifying types from a different module if !p.first_pass() && !p.builtin_mod && T.mod != p.mod && - p.id != 'vgen' { // allow .str() on builtin arrays + p.file_path_id != 'vgen' { // allow .str() on builtin arrays println('T.mod=$T.mod') println('p.mod=$p.mod') p.error('cannot define new methods on non-local type `$receiver_typ`') @@ -814,7 +814,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) &Fn { if p.v.pref.is_debug && f.name == 'panic' && !p.is_js { mod_name := p.mod.replace('_dot_', '.') fn_name := p.cur_fn.name.replace('${p.mod}__', '') - file_path := cescaped_path(p.file_path) + file_path := cescaped_path(p.file_path_id) p.cgen.resetln(p.cgen.cur_line.replace( 'v_panic (', 'panic_debug ($p.scanner.line_nr, tos3("$file_path"), tos3("$mod_name"), tos2((byte *)"$fn_name"), ' diff --git a/compiler/main.v b/compiler/main.v index 19b071c7b2..6c8a046a5f 100644 --- a/compiler/main.v +++ b/compiler/main.v @@ -221,7 +221,7 @@ fn (v mut V) add_parser(parser Parser) { fn (v &V) get_file_parser_index(file string) ?int { for i, p in v.parsers { - if os.realpath(p.file_path) == os.realpath(file) { + if os.realpath(p.file_path_id) == os.realpath(file) { return i } } @@ -636,11 +636,6 @@ fn (v mut V) add_v_files_to_compile() { // Parse user imports for file in v.get_user_files() { mut p := v.new_parser_from_file(file) - // set mod so we dont have to resolve submodule - if v.pref.build_mode == .build_module && - file.contains(v.mod.replace('.', os.path_separator)) { - p.mod = v.mod - } p.parse(.imports) //if p.pref.autofree { p.scanner.text.free() free(p.scanner) } v.add_parser(p) @@ -681,7 +676,7 @@ fn (v mut V) add_v_files_to_compile() { // add remaining main files last for _, fit in v.table.file_imports { if fit.module_name != 'main' { continue } - v.files << fit.file_path + v.files << fit.file_path_id } } @@ -744,16 +739,16 @@ fn (v mut V) parse_lib_imports() { mut done_imports := []string for { for _, fit in v.table.file_imports { - if fit.file_path in done_fits { continue } + if fit.file_path_id in done_fits { continue } for _, mod in fit.imports { import_path := v.find_module_path(mod) or { - pidx := v.get_file_parser_index(fit.file_path) or { verror(err) break } + pidx := v.get_file_parser_index(fit.file_path_id) or { verror(err) break } v.parsers[pidx].error_with_token_index('cannot import module "$mod" (not found)', fit.get_import_tok_idx(mod)) break } vfiles := v.v_files_from_dir(import_path) if vfiles.len == 0 { - pidx := v.get_file_parser_index(fit.file_path) or { verror(err) break } + pidx := v.get_file_parser_index(fit.file_path_id) or { verror(err) break } v.parsers[pidx].error_with_token_index('cannot import module "$mod" (no .v files in "$import_path")', fit.get_import_tok_idx(mod)) } // Add all imports referenced by these libs @@ -763,11 +758,11 @@ fn (v mut V) parse_lib_imports() { done_imports << file p_mod := v.parsers[pid].import_table.module_name if p_mod != mod { - v.parsers[pid].error_with_token_index('bad module definition: $fit.file_path imports module "$mod" but $file is defined as module `$p_mod`', 1) + v.parsers[pid].error_with_token_index('bad module definition: $fit.file_path_id imports module "$mod" but $file is defined as module `$p_mod`', 1) } } } - done_fits << fit.file_path + done_fits << fit.file_path_id } if v.table.file_imports.size == done_fits.len { break} } diff --git a/compiler/module_header.v b/compiler/module_header.v index bee7d6a9b7..0972d0426f 100644 --- a/compiler/module_header.v +++ b/compiler/module_header.v @@ -72,18 +72,31 @@ fn v_type_str(typ_ string) string { typ_ } typ = typ.replace('Option_', '?') + // fn parent/alias? + if typ.starts_with('fn ') { + mut types := []string + fi_lpar := typ.index_byte(`(`) + li_rpar := typ.last_index_byte(`)`) + ret_type := typ.right(li_rpar+1) + for t in typ.substr(fi_lpar+1, li_rpar).split(',') { + types << v_type_str(t) + } + return 'fn (' + types.join(', ') + ')$ret_type' + } + typ = typ.replace('Option_', '?') + // multiple return if typ.contains('_V_MulRet') { - words := typ.replace('_V_MulRet_', '').split('_V_') + words := typ.replace('_V_MulRet_', '').replace('_PTR_', '*').split('_V_') typ = '(' for i in 0 .. words.len { - typ += words[i] + typ += v_type_str(words[i]) if i != words.len - 1 { typ += ',' } } typ += ')' return typ - } + } //println('"$typ"') if typ == '*void' { return 'voidptr' @@ -130,7 +143,7 @@ fn (v &V) generate_vh() { if c.mod != v.mod { continue } - println('$i $c.name') + // println('$i $c.name') //if !c.name.contains('__') { //continue //} @@ -158,7 +171,7 @@ fn (v &V) generate_vh() { for _, typ in v.table.typesmap { //println(typ.name) if typ.mod != v.mod && typ.mod != ''{ // int, string etc mod == '' - //println('skipping type "$typ.name"') + // println('skipping type "$typ.name"') continue } if typ.name.contains('_V_MulRet') { @@ -229,7 +242,7 @@ fn (v &V) generate_vh() { file.writeln('\n// Methods //////////////////') for _, typ in v.table.typesmap { if typ.mod != v.mod && !(v.mod == 'builtin' && typ.mod == '') { - //println('skipping method typ $typ.name mod=$typ.mod') + // println('skipping method typ $typ.name mod=$typ.mod') continue } for method in typ.methods { diff --git a/compiler/modules.v b/compiler/modules.v index 5e1f272ae8..6cd140e1a9 100644 --- a/compiler/modules.v +++ b/compiler/modules.v @@ -61,10 +61,10 @@ fn (v &V) find_module_path(mod string) ?string { return import_path } -fn mod_gen_name(mod string) string { +[inline] fn mod_gen_name(mod string) string { return mod.replace('.', '_dot_') } -fn mod_gen_name_rev(mod string) string { +[inline] fn mod_gen_name_rev(mod string) string { return mod.replace('_dot_', '.') } diff --git a/compiler/parser.v b/compiler/parser.v index 7d775a9623..3feebcbf41 100644 --- a/compiler/parser.v +++ b/compiler/parser.v @@ -18,8 +18,7 @@ struct Token { } struct Parser { - id string // unique id. if parsing file will be same as file_path - file_path string // "/home/user/hello.v" + file_path_id string // unique id. if parsing file will be path eg, "/home/user/hello.v" file_name string // "hello.v" file_platform string // ".v", "_win.v", "_nix.v", "_mac.v", "_lin.v" ... // When p.file_pcguard != '', it contains a @@ -49,7 +48,6 @@ mut: assigned_type string // non-empty if we are in an assignment expression expected_type string tmp_cnt int - is_script bool builtin_mod bool inside_if_expr bool inside_unwrapping_match_statement bool @@ -121,11 +119,9 @@ fn (v mut V) new_parser_from_file(path string) Parser { mut p := v.new_parser(new_scanner_file(path), path) p = { p| - file_path: path, file_name: path.all_after(os.path_separator), file_platform: path_platform, file_pcguard: path_pcguard, - is_script: (v.pref.is_script && os.realpath(path) == os.realpath(path)), is_vh: path.ends_with('.vh') } if p.pref.building_v { @@ -141,13 +137,12 @@ fn (v mut V) new_parser_from_file(path string) Parser { fn (v mut V) new_parser(scanner &Scanner, id string) Parser { v.reset_cgen_file_line_parameters() mut p := Parser { - id: id + file_path_id: id scanner: scanner v: v table: v.table cur_fn: EmptyFn cgen: v.cgen - is_script: false pref: v.pref os: v.os vroot: v.vroot @@ -215,7 +210,6 @@ fn (p & Parser) peek() TokenKind { [inline] fn (p &Parser) prev_token() Token { return p.tokens[p.token_idx - 2] } - [inline] fn (p &Parser) cur_tok() Token { return p.tokens[p.token_idx - 1] } @@ -237,22 +231,19 @@ fn (p &Parser) log(s string) { fn (p mut Parser) parse(pass Pass) { p.cgen.line = 0 - p.cgen.file = cescaped_path(os.realpath(p.file_path)) + p.cgen.file = cescaped_path(os.realpath(p.file_path_id)) ///////////////////////////////////// p.pass = pass p.token_idx = 0 p.next() //p.log('\nparse() run=$p.pass 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.pref.is_test { + if p.pref.is_script || p.pref.is_test { // User may still specify `module main` if p.tok == .key_module { p.next() p.fgen('module ') - mod := p.check_name() - if p.mod == '' { - p.mod = mod - } + p.mod = p.check_name() } else { p.mod = 'main' } @@ -260,11 +251,7 @@ fn (p mut Parser) parse(pass Pass) { else { p.check(.key_module) p.fspace() - // setting mod manually for mod init parsers - mod := p.check_name() - if p.mod == '' { - p.mod = mod - } + p.mod = p.check_name() } // @@ -278,12 +265,17 @@ fn (p mut Parser) parse(pass Pass) { p.builtin_mod = p.mod == 'builtin' p.can_chash = p.mod=='ui' || p.mod == 'darwin'// TODO tmp remove // Import pass - the first and the smallest pass that only analyzes imports + // if we are a building module get the full module name from v.mod + fq_mod := if p.pref.build_mode == .build_module && p.v.mod.ends_with(p.mod) { + p.v.mod + } // fully qualify the module name, eg base64 to encoding.base64 - fq_mod := p.table.qualify_module(p.mod, p.file_path) + else { + p.table.qualify_module(p.mod, p.file_path_id) + } p.import_table.module_name = fq_mod p.table.register_module(fq_mod) - // replace "." with "_dot_" in module name for C variable names - p.mod = mod_gen_name(fq_mod) + p.mod = fq_mod if p.pass == .imports { for p.tok == .key_import && p.peek() != .key_const { @@ -293,7 +285,7 @@ fn (p mut Parser) parse(pass Pass) { p.error('module `builtin` cannot be imported') } // save file import table - p.table.file_imports[p.id] = p.import_table + p.table.file_imports[p.file_path_id] = p.import_table return } // Go through every top level token or throw a compilation error if a non-top level token is met @@ -382,7 +374,7 @@ fn (p mut Parser) parse(pass Pass) { //p.log('end of parse()') // TODO: check why this was added? everything seems to work // without it, and it's already happening in fn_decl - // if p.is_script && !p.pref.is_test { + // if p.pref.is_script && !p.pref.is_test { // p.set_current_fn( MainFn ) // p.check_unused_variables() // } @@ -400,7 +392,7 @@ fn (p mut Parser) parse(pass Pass) { return default: // no `fn main`, add this "global" statement to cgen.fn_main - if p.is_script && !p.pref.is_test { + if p.pref.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.cur_fn.name == '' { @@ -848,7 +840,7 @@ fn (p mut Parser) enum_decl(_enum_name string) { field := p.check_name() fields << field p.fgenln('') - name := '${p.mod}__${enum_name}_$field' + name := '${mod_gen_name(p.mod)}__${enum_name}_$field' if p.pass == .main { p.cgen.consts << '#define $name $val' } @@ -856,7 +848,9 @@ fn (p mut Parser) enum_decl(_enum_name string) { p.next() } // !!!! NAME free - p.table.register_const(name, enum_name, p.mod) + if p.first_pass() { + p.table.register_const(name, enum_name, p.mod) + } val++ } p.table.register_type2(Type { @@ -1748,7 +1742,7 @@ fn (p mut Parser) name_expr() string { if !T.has_enum_val(val) { p.error('enum `$T.name` does not have value `$val`') } - p.gen(T.mod + '__' + p.expected_type + '_' + val) + p.gen(mod_gen_name(T.mod) + '__' + p.expected_type + '_' + val) } return p.expected_type } @@ -1800,15 +1794,13 @@ fn (p mut Parser) name_expr() string { // must be aliased module if name != p.mod && p.import_table.known_alias(name) { p.import_table.register_used_import(name) - // we replaced "." with "_dot_" in p.mod for C variable names, - // do same here. - mod = mod_gen_name(p.import_table.resolve_alias(name)) + mod = p.import_table.resolve_alias(name) } p.next() p.check(.dot) name = p.lit p.fgen(name) - name = prepend_mod(mod, name) + name = prepend_mod(mod_gen_name(mod), name) } // Unknown name, try prepending the module name to it // TODO perf @@ -1890,7 +1882,7 @@ fn (p mut Parser) name_expr() string { p.check(.dot) val := p.lit // println('enum val $val') - p.gen(enum_type.mod + '__' + enum_type.name + '_' + val)// `color = main__Color_green` + p.gen(mod_gen_name(enum_type.mod) + '__' + enum_type.name + '_' + val)// `color = main__Color_green` p.next() return enum_type.name } @@ -1967,7 +1959,7 @@ fn (p mut Parser) name_expr() string { // If orig_name is a mod, then printing undefined: `mod` tells us nothing // if p.table.known_mod(orig_name) { if p.table.known_mod(orig_name) || p.import_table.known_alias(orig_name) { - name = mod_gen_name_rev(name.replace('__', '.')) + name = name.replace('__', '.') p.error('undefined: `$name`') } else { @@ -3073,7 +3065,7 @@ fn (p mut Parser) array_init() string { //p.gen('{0}') p.is_alloc = false if is_const_len { - return '[${p.mod}__$lit]$array_elem_typ' + return '[${mod_gen_name(p.mod)}__$lit]$array_elem_typ' } return '[$lit]$array_elem_typ' } else { @@ -3864,7 +3856,7 @@ fn (p mut Parser) assert_statement() { p.gen('bool $tmp = ') p.check_types(p.bool_expression(), 'bool') // TODO print "expected: got" for failed tests - filename := cescaped_path(p.file_path) + filename := cescaped_path(p.file_path_id) p.genln('; \n @@ -3988,7 +3980,7 @@ fn prepend_mod(mod, name string) string { } fn (p &Parser) prepend_mod(name string) string { - return prepend_mod(p.mod, name) + return prepend_mod(mod_gen_name(p.mod), name) } fn (p mut Parser) go_statement() { @@ -4152,7 +4144,7 @@ fn (p mut Parser) check_and_register_used_imported_type(typ_name string) { fn (p mut Parser) check_unused_imports() { // Don't run in the generated V file with `.str()` - if p.id == 'vgen' { + if p.file_path_id == 'vgen' { return } mut output := '' diff --git a/compiler/table.v b/compiler/table.v index 5119bd53d1..aeb5cb812b 100644 --- a/compiler/table.v +++ b/compiler/table.v @@ -53,7 +53,7 @@ mut: struct FileImportTable { mut: module_name string - file_path string + file_path_id string // file path or id imports map[string]string // alias => module used_imports []string // alias import_tok_idx map[string]int // module => idx @@ -879,16 +879,16 @@ fn (table &Table) qualify_module(mod string, file_path string) string { return mod } -fn (table &Table) get_file_import_table(id string) FileImportTable { - if id in table.file_imports { - return table.file_imports[id] +fn (table &Table) get_file_import_table(file_path_id string) FileImportTable { + if file_path_id in table.file_imports { + return table.file_imports[file_path_id] } - return new_file_import_table(id) + return new_file_import_table(file_path_id) } -fn new_file_import_table(file_path string) FileImportTable { +fn new_file_import_table(file_path_id string) FileImportTable { return FileImportTable{ - file_path: file_path + file_path_id: file_path_id imports: map[string]string } } @@ -905,7 +905,7 @@ fn (fit mut FileImportTable) register_alias(alias string, mod string, tok_idx in // NOTE: come back here // if alias in fit.imports && fit.imports[alias] == mod {} if alias in fit.imports && fit.imports[alias] != mod { - verror('cannot import $mod as $alias: import name $alias already in use in "${fit.file_path}"') + verror('cannot import $mod as $alias: import name $alias already in use in "${fit.file_path_id}"') } if mod.contains('.internal.') { mod_parts := mod.split('.') @@ -971,7 +971,7 @@ fn (p &Parser) identify_typo(name string, fit &FileImportTable) string { // dont check if so short if name.len < 2 { return '' } min_match := 0.50 // for dice coefficient between 0.0 - 1.0 - name_orig := name.replace('__', '.').replace('_dot_', '.') + name_orig := mod_gen_name_rev(name.replace('__', '.')) mut output := '' // check functions mut n := p.table.find_misspelled_fn(name, fit, min_match)