From 8a1248b2e796191debf6b59918fbac46101ab5a6 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Thu, 16 Apr 2020 12:29:36 +0300 Subject: [PATCH] builder: restore module import cycle detection/topological reorder --- .github/workflows/ci.yml | 1 + vlib/builtin/builtin_windows.c.v | 2 +- vlib/v/ast/ast.v | 1 + vlib/v/builder/builder.v | 59 ++++++++++++++++++- vlib/v/checker/tests/inout/enum_err.out | 23 ++++---- vlib/v/checker/tests/inout/enum_err.vv | 6 ++ vlib/v/checker/tests/inout/struct_name.vv | 2 + vlib/v/checker/tests/inout/unknown_field.out | 4 +- vlib/v/checker/tests/inout/unknown_field.vv | 2 +- vlib/v/checker/tests/inout/unknown_method.out | 4 +- vlib/v/checker/tests/inout/unknown_method.vv | 2 +- .../v/checker/tests/inout/void_fn_as_value.vv | 2 +- vlib/v/gen/cgen.v | 31 +++++++--- vlib/v/gen/cheaders.v | 1 - vlib/v/parser/comptime.v | 1 + vlib/v/parser/fn.v | 4 +- vlib/v/util/util.v | 4 ++ 17 files changed, 117 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 926d0730e6..f15f3fd8fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -272,6 +272,7 @@ jobs: .\make.bat -msvc - name: Fixed tests run: | + ./v -cg cmd\tools\vtest-fixed.v ./v test-fixed # - name: Test # run: | diff --git a/vlib/builtin/builtin_windows.c.v b/vlib/builtin/builtin_windows.c.v index cd72e05802..feea154583 100644 --- a/vlib/builtin/builtin_windows.c.v +++ b/vlib/builtin/builtin_windows.c.v @@ -4,7 +4,7 @@ module builtin -#include +// dbghelp.h is already included in cheaders.v #flag windows -l dbghelp pub struct SymbolInfo { diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 32e816fd6c..dd65d49f64 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -465,6 +465,7 @@ pub: pub struct HashStmt { pub: val string + mod string } // filter(), map() diff --git a/vlib/v/builder/builder.v b/vlib/v/builder/builder.v index d3dfc1c35c..5c23e57a70 100644 --- a/vlib/v/builder/builder.v +++ b/vlib/v/builder/builder.v @@ -14,6 +14,7 @@ import ( v.gen v.gen.js v.gen.x64 + v.depgraph ) pub struct Builder { @@ -49,7 +50,9 @@ pub fn new_builder(pref &pref.Preferences) Builder { // parse all deps from already parsed files pub fn (b mut Builder) parse_imports() { mut done_imports := []string - for i in 0 .. b.parsed_files.len { + // NB: b.parsed_files is appended in the loop, + // so we can not use the shorter `for in` form. + for i := 0; i v.ast -> v.table cycles anymore + return + } + if b.pref.is_verbose { + eprintln('------ resolved dependencies graph: ------') + eprintln(deps_resolved.display()) + eprintln('------------------------------------------') + } + mut mods := []string + for node in deps_resolved.nodes { + mods << node.name + } + if b.pref.is_verbose { + eprintln('------ imported modules: ------') + eprintln(mods.str()) + eprintln('-------------------------------') + } + mut reordered_parsed_files := []ast.File + for m in mods { + for pf in b.parsed_files { + if m == pf.mod.name { + reordered_parsed_files << pf + //eprintln('pf.mod.name: $pf.mod.name | pf.path: $pf.path') + } + } + } + b.parsed_files = reordered_parsed_files +} + +// graph of all imported modules +pub fn (b &Builder) import_graph() &depgraph.DepGraph { + mut builtins := util.builtin_module_parts + builtins << 'builtin' + mut graph := depgraph.new_dep_graph() + for p in b.parsed_files { + mut deps := []string + if p.mod.name !in builtins { + deps << 'builtin' + } + for _, m in p.imports { + deps << m.mod + } + graph.add(p.mod.name, deps) + } + return graph } pub fn (b Builder) v_files_from_dir(dir string) []string { diff --git a/vlib/v/checker/tests/inout/enum_err.out b/vlib/v/checker/tests/inout/enum_err.out index 2e3b665fe4..ec4c36f31e 100644 --- a/vlib/v/checker/tests/inout/enum_err.out +++ b/vlib/v/checker/tests/inout/enum_err.out @@ -1,13 +1,14 @@ -vlib/v/checker/tests/inout/enum_err.v:2:13: error: default value for enum has to be an integer - 1| enum Color { - 2| green = 'green', +vlib/v/checker/tests/inout/enum_err.v:4:13: error: default value for enum has to be an integer + 2| + 3| enum Color { + 4| green = 'green', ~~~~~~~ - 3| yellow = 1+1, - 4| blue, -vlib/v/checker/tests/inout/enum_err.v:3:14: error: default value for enum has to be an integer - 1| enum Color { - 2| green = 'green', - 3| yellow = 1+1, + 5| yellow = 1+1, + 6| blue, +vlib/v/checker/tests/inout/enum_err.v:5:14: error: default value for enum has to be an integer + 3| enum Color { + 4| green = 'green', + 5| yellow = 1+1, ~~~ - 4| blue, - 5| } \ No newline at end of file + 6| blue, + 7| } diff --git a/vlib/v/checker/tests/inout/enum_err.vv b/vlib/v/checker/tests/inout/enum_err.vv index 35d7a7df3f..17ee4e7366 100644 --- a/vlib/v/checker/tests/inout/enum_err.vv +++ b/vlib/v/checker/tests/inout/enum_err.vv @@ -1,5 +1,11 @@ +module main + enum Color { green = 'green', yellow = 1+1, blue, } + +fn main(){ + println('hello') +} diff --git a/vlib/v/checker/tests/inout/struct_name.vv b/vlib/v/checker/tests/inout/struct_name.vv index ee903a2252..4cd9b723b8 100644 --- a/vlib/v/checker/tests/inout/struct_name.vv +++ b/vlib/v/checker/tests/inout/struct_name.vv @@ -1,3 +1,5 @@ struct abc { } + +fn main(){} diff --git a/vlib/v/checker/tests/inout/unknown_field.out b/vlib/v/checker/tests/inout/unknown_field.out index 0720562d80..3b5100ea55 100644 --- a/vlib/v/checker/tests/inout/unknown_field.out +++ b/vlib/v/checker/tests/inout/unknown_field.out @@ -1,6 +1,6 @@ -vlib/v/checker/tests/inout/unknown_field.v:7:12: error: unknown field `checker.Test.sdd` +vlib/v/checker/tests/inout/unknown_field.v:7:12: error: unknown field `Test.sdd` 5| fn main() { 6| t := Test{} 7| println(t.sdd) ~~~ - 8| } \ No newline at end of file + 8| } diff --git a/vlib/v/checker/tests/inout/unknown_field.vv b/vlib/v/checker/tests/inout/unknown_field.vv index 53de9927f4..8cf14a98fa 100644 --- a/vlib/v/checker/tests/inout/unknown_field.vv +++ b/vlib/v/checker/tests/inout/unknown_field.vv @@ -1,4 +1,4 @@ -module checker +module main struct Test {} diff --git a/vlib/v/checker/tests/inout/unknown_method.out b/vlib/v/checker/tests/inout/unknown_method.out index 2b5fd93c6a..ad5f480fa5 100644 --- a/vlib/v/checker/tests/inout/unknown_method.out +++ b/vlib/v/checker/tests/inout/unknown_method.out @@ -1,6 +1,6 @@ -vlib/v/checker/tests/inout/unknown_method.v:7:12: error: unknown method: checker.Test.sdd +vlib/v/checker/tests/inout/unknown_method.v:7:12: error: unknown method: Test.sdd 5| fn main() { 6| t := Test{} 7| println(t.sdd()) ~~~~~ - 8| } \ No newline at end of file + 8| } diff --git a/vlib/v/checker/tests/inout/unknown_method.vv b/vlib/v/checker/tests/inout/unknown_method.vv index 68a0699058..879b372923 100644 --- a/vlib/v/checker/tests/inout/unknown_method.vv +++ b/vlib/v/checker/tests/inout/unknown_method.vv @@ -1,4 +1,4 @@ -module checker +module main struct Test {} diff --git a/vlib/v/checker/tests/inout/void_fn_as_value.vv b/vlib/v/checker/tests/inout/void_fn_as_value.vv index f5f301df0e..d88cc2d871 100644 --- a/vlib/v/checker/tests/inout/void_fn_as_value.vv +++ b/vlib/v/checker/tests/inout/void_fn_as_value.vv @@ -1,4 +1,4 @@ -module checker +module main fn main() { mut a := 'aa' diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index e138e62d1a..d8b3519606 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -25,13 +25,14 @@ fn foo(t token.Token) { struct Gen { out strings.Builder + cheaders strings.Builder + includes strings.Builder // all C #includes required by V modules typedefs strings.Builder typedefs2 strings.Builder definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file) inits strings.Builder // contents of `void _vinit(){}` gowrappers strings.Builder // all go callsite wrappers stringliterals strings.Builder // all string literals (they depend on tos3() beeing defined - includes strings.Builder table &table.Table pref &pref.Preferences mut: @@ -76,13 +77,14 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string // println('start cgen2') var g := Gen{ out: strings.new_builder(1000) + cheaders: strings.new_builder(8192) + includes: strings.new_builder(100) typedefs: strings.new_builder(100) typedefs2: strings.new_builder(100) definitions: strings.new_builder(100) gowrappers: strings.new_builder(100) stringliterals: strings.new_builder(100) inits: strings.new_builder(100) - includes: strings.new_builder(100) table: table pref: pref fn_decl: 0 @@ -124,8 +126,15 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string } // g.finish() - return g.hashes() + g.includes.str() + g.typedefs.str() + g.typedefs2.str() + g.definitions.str() + - g.gowrappers.str() + g.stringliterals.str() + g.out.str() + return g.hashes() + + '\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() + + '\n// V gowrappers:\n' + g.gowrappers.str() + + '\n// V stringliterals:\n' + g.stringliterals.str() + + '\n// V out\n' + g.out.str() } pub fn (g Gen) hashes() string { @@ -135,10 +144,10 @@ pub fn (g Gen) hashes() string { } pub fn (g mut Gen) init() { - g.definitions.writeln('// Generated by the V compiler') - g.definitions.writeln('#include ') // int64_t etc - g.definitions.writeln(c_builtin_types) - g.definitions.writeln(c_headers) + g.cheaders.writeln('// Generated by the V compiler') + g.cheaders.writeln('#include ') // int64_t etc + g.cheaders.writeln(c_builtin_types) + g.cheaders.writeln(c_headers) g.definitions.writeln('\nstring _STR(const char*, ...);\n') g.definitions.writeln('\nstring _STR_TMP(const char*, ...);\n') g.write_builtin_types() @@ -478,7 +487,11 @@ fn (g mut Gen) stmt(node ast.Stmt) { ast.HashStmt { // #include etc typ := it.val.all_before(' ') - if typ in ['include', 'define'] { + if typ == 'include' { + g.includes.writeln('// added by module `$it.mod`:') + g.includes.writeln('#$it.val') + } + if typ == 'define' { g.definitions.writeln('#$it.val') } } diff --git a/vlib/v/gen/cheaders.v b/vlib/v/gen/cheaders.v index 0f01601352..ca84173a31 100644 --- a/vlib/v/gen/cheaders.v +++ b/vlib/v/gen/cheaders.v @@ -67,7 +67,6 @@ const ( // c_headers #include // TODO remove all these includes, define all function signatures and types manually #include -#include //#include "fns.h" #include diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index 0520b1b09d..1be5d9623c 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -52,6 +52,7 @@ fn (p mut Parser) hash() ast.HashStmt { } return ast.HashStmt{ val: val + mod: p.mod } } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 60c6975530..22a8037470 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -7,6 +7,7 @@ import v.ast import v.table import v.scanner import v.token +import v.util pub fn (p mut Parser) call_expr(is_c bool, is_js bool, mod string) ast.CallExpr { first_pos := p.tok.position() @@ -227,8 +228,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl { is_js: is_js no_body: no_body pos: pos - is_builtin: p.builtin_mod || p.mod in ['math', 'strconv', 'strconv.ftoa', 'hash.wyhash', - 'math.bits', 'strings'] + is_builtin: p.builtin_mod || p.mod in util.builtin_module_parts } } diff --git a/vlib/v/util/util.v b/vlib/v/util/util.v index e8e0d7aaea..012d3252d2 100644 --- a/vlib/v/util/util.v +++ b/vlib/v/util/util.v @@ -12,6 +12,10 @@ pub const ( v_version = '0.1.26' ) +pub const ( + builtin_module_parts = ['math.bits' /* needed by strconv.ftoa */, 'strconv', 'strconv.ftoa', 'hash.wyhash', 'strings'] +) + // vhash() returns the build string C.V_COMMIT_HASH . See cmd/tools/gen_vc.v . pub fn vhash() string { mut buf := [50]byte