2020-01-18 23:26:14 +01:00
module builder
import (
os
time
2020-02-03 07:31:54 +01:00
v . ast
2020-01-18 23:26:14 +01:00
v . table
2020-02-03 12:09:17 +01:00
v . pref
2020-01-18 23:26:14 +01:00
v . checker
v . parser
v . gen
v . gen . x64
)
pub struct Builder {
pub :
2020-03-31 23:42:30 +02:00
mod_file_cacher & ModFileCacher // used during lookup for v.mod to support @VROOT
2020-02-03 12:09:17 +01:00
pref & pref . Preferences
2020-02-07 18:46:42 +01:00
table & table . Table
checker checker . Checker
os pref . OS // the OS to build for
2020-03-20 16:41:18 +01:00
compiled_dir string // contains os.real_path() of the dir of the final file beeing compiled, or the dir itself when doing `v .`
2020-02-07 18:46:42 +01:00
module_path string
2020-02-03 07:31:54 +01:00
mut :
2020-03-01 21:56:07 +01:00
module_search_paths [ ] string
2020-02-03 12:09:17 +01:00
parsed_files [ ] ast . File
2020-01-18 23:26:14 +01:00
}
2020-02-03 12:09:17 +01:00
pub fn new_builder ( pref & pref . Preferences ) Builder {
2020-01-18 23:26:14 +01:00
table := table . new_table ( )
2020-02-03 12:09:17 +01:00
return Builder {
2020-03-31 23:42:30 +02:00
mod_file_cacher : new_mod_file_cacher ( )
2020-02-03 12:09:17 +01:00
pref : pref
2020-01-18 23:26:14 +01:00
table : table
checker : checker . new_checker ( table )
}
}
pub fn ( b mut Builder ) gen_c ( v_files [ ] string ) string {
2020-03-04 20:17:29 +01:00
t0 := time . ticks ( )
2020-03-27 14:44:30 +01:00
b . parsed_files = parser . parse_files ( v_files , b . table , b . pref )
2020-02-03 07:31:54 +01:00
b . parse_imports ( )
2020-03-04 20:17:29 +01:00
t1 := time . ticks ( )
parse_time := t1 - t0
2020-03-31 19:58:44 +02:00
b . info ( ' P A R S E : $ { parse_time } m s ' )
2020-03-04 20:17:29 +01:00
//
2020-02-03 07:31:54 +01:00
b . checker . check_files ( b . parsed_files )
2020-03-04 20:17:29 +01:00
t2 := time . ticks ( )
check_time := t2 - t1
2020-03-31 19:58:44 +02:00
b . info ( ' C H E C K : $ { check_time } m s ' )
2020-03-03 18:37:38 +01:00
if b . checker . nr_errors > 0 {
exit ( 1 )
}
2020-03-04 15:48:43 +01:00
// println('starting cgen...')
2020-03-30 17:21:32 +02:00
res := gen . cgen ( b . parsed_files , b . table , b . pref )
2020-03-04 20:17:29 +01:00
t3 := time . ticks ( )
gen_time := t3 - t2
2020-03-31 19:58:44 +02:00
b . info ( ' C G E N : $ { gen_time } m s ' )
// println('cgen done')
2020-03-04 15:48:43 +01:00
// println(res)
return res
2020-01-18 23:26:14 +01:00
}
pub fn ( b mut Builder ) build_c ( v_files [ ] string , out_file string ) {
2020-03-31 19:58:44 +02:00
b . info ( ' b u i l d _ c ( $ out_file ) ' )
2020-03-04 17:08:28 +01:00
mut f := os . create ( out_file ) or {
panic ( err )
}
f . writeln ( b . gen_c ( v_files ) )
f . close ( )
// os.write_file(out_file, b.gen_c(v_files))
2020-01-18 23:26:14 +01:00
}
pub fn ( b mut Builder ) build_x64 ( v_files [ ] string , out_file string ) {
2020-02-07 18:46:42 +01:00
t0 := time . ticks ( )
2020-03-27 14:44:30 +01:00
b . parsed_files = parser . parse_files ( v_files , b . table , b . pref )
2020-02-03 07:31:54 +01:00
b . parse_imports ( )
2020-02-07 18:46:42 +01:00
t1 := time . ticks ( )
parse_time := t1 - t0
2020-03-31 19:58:44 +02:00
b . info ( ' P A R S E : $ { parse_time } m s ' )
2020-02-03 07:31:54 +01:00
b . checker . check_files ( b . parsed_files )
2020-02-07 18:46:42 +01:00
t2 := time . ticks ( )
check_time := t2 - t1
2020-03-31 19:58:44 +02:00
b . info ( ' C H E C K : $ { check_time } m s ' )
2020-02-03 07:31:54 +01:00
x64 . gen ( b . parsed_files , out_file )
2020-02-07 18:46:42 +01:00
t3 := time . ticks ( )
gen_time := t3 - t2
2020-03-31 19:58:44 +02:00
b . info ( ' x 6 4 G E N : $ { gen_time } m s ' )
2020-01-18 23:26:14 +01:00
}
2020-02-03 07:31:54 +01:00
// 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 {
ast_file := b . parsed_files [ i ]
for _ , imp in ast_file . imports {
mod := imp . mod
if mod in done_imports {
continue
}
import_path := b . find_module_path ( mod ) or {
2020-02-07 18:46:42 +01:00
// v.parsers[i].error_with_token_index('cannot import module "$mod" (not found)', v.parsers[i].import_table.get_import_tok_idx(mod))
// break
2020-03-01 21:56:07 +01:00
// println('module_search_paths:')
// println(b.module_search_paths)
2020-02-03 07:31:54 +01:00
panic ( ' c a n n o t i m p o r t m o d u l e " $ mod " ( n o t f o u n d ) ' )
}
v_files := b . v_files_from_dir ( import_path )
if v_files . len == 0 {
2020-02-07 18:46:42 +01:00
// v.parsers[i].error_with_token_index('cannot import module "$mod" (no .v files in "$import_path")', v.parsers[i].import_table.get_import_tok_idx(mod))
2020-02-03 07:31:54 +01:00
panic ( ' c a n n o t i m p o r t m o d u l e " $ mod " ( n o . v f i l e s i n " $ import_path " ) ' )
}
// Add all imports referenced by these libs
2020-03-27 14:44:30 +01:00
parsed_files := parser . parse_files ( v_files , b . table , b . pref )
2020-02-03 07:31:54 +01:00
for file in parsed_files {
if file . mod . name != mod {
2020-02-07 18:46:42 +01:00
// v.parsers[pidx].error_with_token_index('bad module definition: ${v.parsers[pidx].file_path} imports module "$mod" but $file is defined as module `$p_mod`', 1
2020-02-19 03:08:10 +01:00
panic ( ' b a d m o d u l e d e f i n i t i o n : $ { ast_file . path } i m p o r t s m o d u l e " $ mod " b u t $ file . path i s d e f i n e d a s m o d u l e ` $ file . mod . name ` ' )
2020-02-03 07:31:54 +01:00
}
}
b . parsed_files << parsed_files
done_imports << mod
}
}
}
pub fn ( b & Builder ) v_files_from_dir ( dir string ) [ ] string {
mut res := [ ] string
if ! os . exists ( dir ) {
if dir == ' c o m p i l e r ' && os . is_dir ( ' v l i b ' ) {
println ( ' l o o k s l i k e y o u a r e t r y i n g t o b u i l d V w i t h a n o l d c o m m a n d ' )
2020-02-09 10:08:04 +01:00
println ( ' u s e ` v - o v c m d / v ` i n s t e a d o f ` v - o v c o m p i l e r ` ' )
2020-02-03 07:31:54 +01:00
}
verror ( " $ dir d o e s n ' t e x i s t " )
}
else if ! os . is_dir ( dir ) {
2020-03-24 11:14:11 +01:00
verror ( " $ dir i s n ' t a d i r e c t o r y ! " )
2020-02-03 07:31:54 +01:00
}
2020-02-07 18:46:42 +01:00
mut files := os . ls ( dir ) or {
2020-02-03 07:31:54 +01:00
panic ( err )
}
2020-03-06 18:53:29 +01:00
if b . pref . verbosity . is_higher_or_equal ( . level_one ) {
2020-02-03 07:31:54 +01:00
println ( ' v _ f i l e s _ f r o m _ d i r ( " $ dir " ) ' )
}
files . sort ( )
for file in files {
if ! file . ends_with ( ' . v ' ) && ! file . ends_with ( ' . v h ' ) {
continue
}
if file . ends_with ( ' _ t e s t . v ' ) {
continue
}
2020-02-03 12:09:17 +01:00
if ( file . ends_with ( ' _ w i n . v ' ) || file . ends_with ( ' _ w i n d o w s . v ' ) ) && b . os != . windows {
2020-02-03 07:31:54 +01:00
continue
}
2020-02-03 12:09:17 +01:00
if ( file . ends_with ( ' _ l i n . v ' ) || file . ends_with ( ' _ l i n u x . v ' ) ) && b . os != . linux {
2020-02-03 07:31:54 +01:00
continue
}
2020-02-03 12:09:17 +01:00
if ( file . ends_with ( ' _ m a c . v ' ) || file . ends_with ( ' _ d a r w i n . v ' ) ) && b . os != . mac {
2020-02-03 07:31:54 +01:00
continue
}
2020-02-03 12:09:17 +01:00
if file . ends_with ( ' _ n i x . v ' ) && b . os == . windows {
2020-02-03 07:31:54 +01:00
continue
}
2020-03-31 23:42:30 +02:00
if file . ends_with ( ' _ a n d r o i d . v ' ) && b . pref . os != . android {
continue
}
if file . ends_with ( ' _ f r e e b s d . v ' ) && b . pref . os != . freebsd {
continue
}
if file . ends_with ( ' _ s o l a r i s . v ' ) && b . pref . os != . solaris {
continue
}
2020-02-03 12:09:17 +01:00
if file . ends_with ( ' _ j s . v ' ) && b . os != . js {
2020-02-03 07:31:54 +01:00
continue
}
2020-02-03 12:09:17 +01:00
if file . ends_with ( ' _ c . v ' ) && b . os == . js {
2020-02-03 07:31:54 +01:00
continue
}
2020-03-31 23:42:30 +02:00
if b . pref . compile_defines_all . len > 0 && file . contains ( ' _ d _ ' ) {
2020-02-03 07:31:54 +01:00
mut allowed := false
2020-03-31 23:42:30 +02:00
for cdefine in b . pref . compile_defines {
2020-02-03 07:31:54 +01:00
file_postfix := ' _ d _ $ { cdefine } . v '
if file . ends_with ( file_postfix ) {
allowed = true
break
}
}
if ! allowed {
continue
}
}
2020-03-09 02:23:34 +01:00
res << os . join_path ( dir , file )
2020-02-03 07:31:54 +01:00
}
return res
}
fn verror ( err string ) {
panic ( ' v e r r o r : $ err ' )
}
pub fn ( b & Builder ) log ( s string ) {
2020-03-06 18:53:29 +01:00
if b . pref . verbosity . is_higher_or_equal ( . level_two ) {
2020-02-03 07:31:54 +01:00
println ( s )
}
}
2020-03-01 21:56:07 +01:00
2020-03-31 19:58:44 +02:00
pub fn ( b & Builder ) info ( s string ) {
if b . pref . verbosity . is_higher_or_equal ( . level_one ) {
println ( s )
}
}
2020-03-01 21:56:07 +01:00
[ inline ]
fn module_path ( mod string ) string {
// submodule support
2020-03-07 22:26:26 +01:00
return mod . replace ( ' . ' , os . path_separator )
2020-03-01 21:56:07 +01:00
}
pub fn ( b & Builder ) find_module_path ( mod string ) ? string {
mod_path := module_path ( mod )
for search_path in b . module_search_paths {
2020-03-24 11:14:11 +01:00
try_path := os . join_path ( search_path , mod_path )
2020-03-06 18:53:29 +01:00
if b . pref . verbosity . is_higher_or_equal ( . level_three ) {
2020-03-01 21:56:07 +01:00
println ( ' > > t r y i n g t o f i n d $ mod i n $ try_path . . ' )
}
if os . is_dir ( try_path ) {
2020-03-06 18:53:29 +01:00
if b . pref . verbosity . is_higher_or_equal ( . level_three ) {
2020-03-01 21:56:07 +01:00
println ( ' < < f o u n d $ try_path . ' )
}
return try_path
}
}
return error ( ' m o d u l e " $ mod " n o t f o u n d ' )
}