builder: restore module import cycle detection/topological reorder
parent
04db2d02b8
commit
8a1248b2e7
|
@ -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: |
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
module builtin
|
||||
|
||||
#include <dbghelp.h>
|
||||
// dbghelp.h is already included in cheaders.v
|
||||
#flag windows -l dbghelp
|
||||
|
||||
pub struct SymbolInfo {
|
||||
|
|
|
@ -465,6 +465,7 @@ pub:
|
|||
pub struct HashStmt {
|
||||
pub:
|
||||
val string
|
||||
mod string
|
||||
}
|
||||
|
||||
// filter(), map()
|
||||
|
|
|
@ -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<b.parsed_files.len; i++ {
|
||||
ast_file := b.parsed_files[i]
|
||||
for _, imp in ast_file.imports {
|
||||
mod := imp.mod
|
||||
|
@ -80,6 +83,60 @@ pub fn (b mut Builder) parse_imports() {
|
|||
done_imports << mod
|
||||
}
|
||||
}
|
||||
b.resolve_deps()
|
||||
}
|
||||
|
||||
|
||||
pub fn (b mut Builder) resolve_deps() {
|
||||
graph := b.import_graph()
|
||||
deps_resolved := graph.resolve()
|
||||
if !deps_resolved.acyclic {
|
||||
eprintln('import cycle detected between the following modules: \n' + deps_resolved.display_cycles())
|
||||
// TODO: error, when v itself does not have v.table -> 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 {
|
||||
|
|
|
@ -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| }
|
||||
6| blue,
|
||||
7| }
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
module main
|
||||
|
||||
enum Color {
|
||||
green = 'green',
|
||||
yellow = 1+1,
|
||||
blue,
|
||||
}
|
||||
|
||||
fn main(){
|
||||
println('hello')
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
struct abc {
|
||||
|
||||
}
|
||||
|
||||
fn main(){}
|
||||
|
|
|
@ -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| }
|
||||
8| }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
module checker
|
||||
module main
|
||||
|
||||
struct Test {}
|
||||
|
||||
|
|
|
@ -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| }
|
||||
8| }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
module checker
|
||||
module main
|
||||
|
||||
struct Test {}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
module checker
|
||||
module main
|
||||
|
||||
fn main() {
|
||||
mut a := 'aa'
|
||||
|
|
|
@ -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 <inttypes.h>') // 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 <inttypes.h>') // 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')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,7 +67,6 @@ const (
|
|||
// c_headers
|
||||
#include <stdio.h> // TODO remove all these includes, define all function signatures and types manually
|
||||
#include <stdlib.h>
|
||||
#include <float.h>
|
||||
|
||||
//#include "fns.h"
|
||||
#include <signal.h>
|
||||
|
|
|
@ -52,6 +52,7 @@ fn (p mut Parser) hash() ast.HashStmt {
|
|||
}
|
||||
return ast.HashStmt{
|
||||
val: val
|
||||
mod: p.mod
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue