builder: restore module import cycle detection/topological reorder
parent
04db2d02b8
commit
8a1248b2e7
|
@ -272,6 +272,7 @@ jobs:
|
||||||
.\make.bat -msvc
|
.\make.bat -msvc
|
||||||
- name: Fixed tests
|
- name: Fixed tests
|
||||||
run: |
|
run: |
|
||||||
|
./v -cg cmd\tools\vtest-fixed.v
|
||||||
./v test-fixed
|
./v test-fixed
|
||||||
# - name: Test
|
# - name: Test
|
||||||
# run: |
|
# run: |
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
module builtin
|
module builtin
|
||||||
|
|
||||||
#include <dbghelp.h>
|
// dbghelp.h is already included in cheaders.v
|
||||||
#flag windows -l dbghelp
|
#flag windows -l dbghelp
|
||||||
|
|
||||||
pub struct SymbolInfo {
|
pub struct SymbolInfo {
|
||||||
|
|
|
@ -465,6 +465,7 @@ pub:
|
||||||
pub struct HashStmt {
|
pub struct HashStmt {
|
||||||
pub:
|
pub:
|
||||||
val string
|
val string
|
||||||
|
mod string
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter(), map()
|
// filter(), map()
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
v.gen
|
v.gen
|
||||||
v.gen.js
|
v.gen.js
|
||||||
v.gen.x64
|
v.gen.x64
|
||||||
|
v.depgraph
|
||||||
)
|
)
|
||||||
|
|
||||||
pub struct Builder {
|
pub struct Builder {
|
||||||
|
@ -49,7 +50,9 @@ pub fn new_builder(pref &pref.Preferences) Builder {
|
||||||
// parse all deps from already parsed files
|
// parse all deps from already parsed files
|
||||||
pub fn (b mut Builder) parse_imports() {
|
pub fn (b mut Builder) parse_imports() {
|
||||||
mut done_imports := []string
|
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]
|
ast_file := b.parsed_files[i]
|
||||||
for _, imp in ast_file.imports {
|
for _, imp in ast_file.imports {
|
||||||
mod := imp.mod
|
mod := imp.mod
|
||||||
|
@ -80,6 +83,60 @@ pub fn (b mut Builder) parse_imports() {
|
||||||
done_imports << mod
|
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 {
|
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
|
vlib/v/checker/tests/inout/enum_err.v:4:13: error: default value for enum has to be an integer
|
||||||
1| enum Color {
|
2|
|
||||||
2| green = 'green',
|
3| enum Color {
|
||||||
|
4| green = 'green',
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
3| yellow = 1+1,
|
5| yellow = 1+1,
|
||||||
4| blue,
|
6| blue,
|
||||||
vlib/v/checker/tests/inout/enum_err.v:3:14: error: default value for enum has to be an integer
|
vlib/v/checker/tests/inout/enum_err.v:5:14: error: default value for enum has to be an integer
|
||||||
1| enum Color {
|
3| enum Color {
|
||||||
2| green = 'green',
|
4| green = 'green',
|
||||||
3| yellow = 1+1,
|
5| yellow = 1+1,
|
||||||
~~~
|
~~~
|
||||||
4| blue,
|
6| blue,
|
||||||
5| }
|
7| }
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
|
module main
|
||||||
|
|
||||||
enum Color {
|
enum Color {
|
||||||
green = 'green',
|
green = 'green',
|
||||||
yellow = 1+1,
|
yellow = 1+1,
|
||||||
blue,
|
blue,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn main(){
|
||||||
|
println('hello')
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
struct abc {
|
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() {
|
5| fn main() {
|
||||||
6| t := Test{}
|
6| t := Test{}
|
||||||
7| println(t.sdd)
|
7| println(t.sdd)
|
||||||
~~~
|
~~~
|
||||||
8| }
|
8| }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
module checker
|
module main
|
||||||
|
|
||||||
struct Test {}
|
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() {
|
5| fn main() {
|
||||||
6| t := Test{}
|
6| t := Test{}
|
||||||
7| println(t.sdd())
|
7| println(t.sdd())
|
||||||
~~~~~
|
~~~~~
|
||||||
8| }
|
8| }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
module checker
|
module main
|
||||||
|
|
||||||
struct Test {}
|
struct Test {}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
module checker
|
module main
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
mut a := 'aa'
|
mut a := 'aa'
|
||||||
|
|
|
@ -25,13 +25,14 @@ fn foo(t token.Token) {
|
||||||
|
|
||||||
struct Gen {
|
struct Gen {
|
||||||
out strings.Builder
|
out strings.Builder
|
||||||
|
cheaders strings.Builder
|
||||||
|
includes strings.Builder // all C #includes required by V modules
|
||||||
typedefs strings.Builder
|
typedefs strings.Builder
|
||||||
typedefs2 strings.Builder
|
typedefs2 strings.Builder
|
||||||
definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file)
|
definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file)
|
||||||
inits strings.Builder // contents of `void _vinit(){}`
|
inits strings.Builder // contents of `void _vinit(){}`
|
||||||
gowrappers strings.Builder // all go callsite wrappers
|
gowrappers strings.Builder // all go callsite wrappers
|
||||||
stringliterals strings.Builder // all string literals (they depend on tos3() beeing defined
|
stringliterals strings.Builder // all string literals (they depend on tos3() beeing defined
|
||||||
includes strings.Builder
|
|
||||||
table &table.Table
|
table &table.Table
|
||||||
pref &pref.Preferences
|
pref &pref.Preferences
|
||||||
mut:
|
mut:
|
||||||
|
@ -76,13 +77,14 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||||
// println('start cgen2')
|
// println('start cgen2')
|
||||||
var g := Gen{
|
var g := Gen{
|
||||||
out: strings.new_builder(1000)
|
out: strings.new_builder(1000)
|
||||||
|
cheaders: strings.new_builder(8192)
|
||||||
|
includes: strings.new_builder(100)
|
||||||
typedefs: strings.new_builder(100)
|
typedefs: strings.new_builder(100)
|
||||||
typedefs2: strings.new_builder(100)
|
typedefs2: strings.new_builder(100)
|
||||||
definitions: strings.new_builder(100)
|
definitions: strings.new_builder(100)
|
||||||
gowrappers: strings.new_builder(100)
|
gowrappers: strings.new_builder(100)
|
||||||
stringliterals: strings.new_builder(100)
|
stringliterals: strings.new_builder(100)
|
||||||
inits: strings.new_builder(100)
|
inits: strings.new_builder(100)
|
||||||
includes: strings.new_builder(100)
|
|
||||||
table: table
|
table: table
|
||||||
pref: pref
|
pref: pref
|
||||||
fn_decl: 0
|
fn_decl: 0
|
||||||
|
@ -124,8 +126,15 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
g.finish()
|
g.finish()
|
||||||
return g.hashes() + g.includes.str() + g.typedefs.str() + g.typedefs2.str() + g.definitions.str() +
|
return g.hashes() +
|
||||||
g.gowrappers.str() + g.stringliterals.str() + g.out.str()
|
'\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 {
|
pub fn (g Gen) hashes() string {
|
||||||
|
@ -135,10 +144,10 @@ pub fn (g Gen) hashes() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (g mut Gen) init() {
|
pub fn (g mut Gen) init() {
|
||||||
g.definitions.writeln('// Generated by the V compiler')
|
g.cheaders.writeln('// Generated by the V compiler')
|
||||||
g.definitions.writeln('#include <inttypes.h>') // int64_t etc
|
g.cheaders.writeln('#include <inttypes.h>') // int64_t etc
|
||||||
g.definitions.writeln(c_builtin_types)
|
g.cheaders.writeln(c_builtin_types)
|
||||||
g.definitions.writeln(c_headers)
|
g.cheaders.writeln(c_headers)
|
||||||
g.definitions.writeln('\nstring _STR(const char*, ...);\n')
|
g.definitions.writeln('\nstring _STR(const char*, ...);\n')
|
||||||
g.definitions.writeln('\nstring _STR_TMP(const char*, ...);\n')
|
g.definitions.writeln('\nstring _STR_TMP(const char*, ...);\n')
|
||||||
g.write_builtin_types()
|
g.write_builtin_types()
|
||||||
|
@ -478,7 +487,11 @@ fn (g mut Gen) stmt(node ast.Stmt) {
|
||||||
ast.HashStmt {
|
ast.HashStmt {
|
||||||
// #include etc
|
// #include etc
|
||||||
typ := it.val.all_before(' ')
|
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')
|
g.definitions.writeln('#$it.val')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,6 @@ const (
|
||||||
// c_headers
|
// c_headers
|
||||||
#include <stdio.h> // TODO remove all these includes, define all function signatures and types manually
|
#include <stdio.h> // TODO remove all these includes, define all function signatures and types manually
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <float.h>
|
|
||||||
|
|
||||||
//#include "fns.h"
|
//#include "fns.h"
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
|
@ -52,6 +52,7 @@ fn (p mut Parser) hash() ast.HashStmt {
|
||||||
}
|
}
|
||||||
return ast.HashStmt{
|
return ast.HashStmt{
|
||||||
val: val
|
val: val
|
||||||
|
mod: p.mod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import v.ast
|
||||||
import v.table
|
import v.table
|
||||||
import v.scanner
|
import v.scanner
|
||||||
import v.token
|
import v.token
|
||||||
|
import v.util
|
||||||
|
|
||||||
pub fn (p mut Parser) call_expr(is_c bool, is_js bool, mod string) ast.CallExpr {
|
pub fn (p mut Parser) call_expr(is_c bool, is_js bool, mod string) ast.CallExpr {
|
||||||
first_pos := p.tok.position()
|
first_pos := p.tok.position()
|
||||||
|
@ -227,8 +228,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
|
||||||
is_js: is_js
|
is_js: is_js
|
||||||
no_body: no_body
|
no_body: no_body
|
||||||
pos: pos
|
pos: pos
|
||||||
is_builtin: p.builtin_mod || p.mod in ['math', 'strconv', 'strconv.ftoa', 'hash.wyhash',
|
is_builtin: p.builtin_mod || p.mod in util.builtin_module_parts
|
||||||
'math.bits', 'strings']
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,10 @@ pub const (
|
||||||
v_version = '0.1.26'
|
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 .
|
// vhash() returns the build string C.V_COMMIT_HASH . See cmd/tools/gen_vc.v .
|
||||||
pub fn vhash() string {
|
pub fn vhash() string {
|
||||||
mut buf := [50]byte
|
mut buf := [50]byte
|
||||||
|
|
Loading…
Reference in New Issue