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-04-03 17:38:41 +02:00
v . util
2020-04-11 08:57:31 +02:00
v . vmod
2020-01-18 23:26:14 +01:00
v . checker
v . parser
v . gen
v . gen . x64
)
pub struct Builder {
pub :
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
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-04-04 05:14:40 +02:00
global_scope & ast . Scope
2020-04-07 00:44:19 +02:00
out_name_c string
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-04-07 00:44:19 +02:00
rdir := os . real_path ( pref . path )
compiled_dir := if os . is_dir ( rdir ) { rdir } else { os . dir ( rdir ) }
2020-01-18 23:26:14 +01:00
table := table . new_table ( )
2020-04-07 00:44:19 +02:00
return builder . Builder {
2020-02-03 12:09:17 +01:00
pref : pref
2020-01-18 23:26:14 +01:00
table : table
2020-04-03 11:01:09 +02:00
checker : checker . new_checker ( table , pref )
2020-04-04 05:14:40 +02:00
global_scope : & ast . Scope {
parent : 0
}
2020-04-07 00:44:19 +02:00
compiled_dir : compiled_dir
2020-01-18 23:26:14 +01:00
}
}
pub fn ( b mut Builder ) gen_c ( v_files [ ] string ) string {
2020-03-04 20:17:29 +01:00
t0 := time . ticks ( )
2020-04-04 05:14:40 +02:00
b . parsed_files = parser . parse_files ( v_files , b . table , b . pref , b . global_scope )
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-04-07 00:44:19 +02:00
b . out_name_c = out_file
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-04-07 00:44:19 +02:00
$ if ! linux {
println ( ' v - x 6 4 c a n o n l y g e n e r a t e L i n u x b i n a r i e s f o r n o w ' )
println ( ' Y o u a r e n o t o n a L i n u x s y s t e m , s o y o u w i l l n o t ' + ' b e a b l e t o r u n t h e r e s u l t i n g e x e c u t a b l e ' )
}
2020-02-07 18:46:42 +01:00
t0 := time . ticks ( )
2020-04-04 05:14:40 +02:00
b . parsed_files = parser . parse_files ( v_files , b . table , b . pref , b . global_scope )
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
}
2020-04-11 08:57:31 +02:00
import_path := b . find_module_path ( mod , ast_file . path ) 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-04-04 05:14:40 +02:00
parsed_files := parser . parse_files ( v_files , b . table , b . pref , b . global_scope )
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
}
}
}
2020-04-07 00:44:19 +02:00
pub fn ( b Builder ) v_files_from_dir ( dir string ) [ ] string {
2020-02-03 07:31:54 +01:00
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 " )
2020-04-07 00:44:19 +02:00
} 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-04-07 00:44:19 +02:00
if b . pref . is_verbose {
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-04-10 18:25:23 +02:00
if b . pref . backend == . c && ! b . should_compile_c ( file ) {
2020-02-03 07:31:54 +01:00
continue
}
2020-04-10 18:25:23 +02:00
if b . pref . backend == . js && ! b . should_compile_js ( file ) {
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-04-07 00:44:19 +02:00
res << os . join_path ( dir , file )
2020-02-03 07:31:54 +01:00
}
return res
}
2020-04-10 18:25:23 +02:00
[ inline ]
fn ( b Builder ) should_compile_c ( file string ) bool {
if ! file . ends_with ( ' . c . v ' ) && file . split ( ' . ' ) . len > 2 {
// Probably something like `a.js.v`.
return false
}
if file . ends_with ( ' _ w i n d o w s . c . v ' ) && b . pref . os != . windows {
return false
}
if file . ends_with ( ' _ l i n u x . c . v ' ) && b . pref . os != . linux {
return false
}
if file . ends_with ( ' _ d a r w i n . c . v ' ) && b . pref . os != . mac {
return false
}
if file . ends_with ( ' _ n i x . c . v ' ) && b . pref . os == . windows {
return false
}
if file . ends_with ( ' _ a n d r o i d . c . v ' ) && b . pref . os != . android {
return false
}
if file . ends_with ( ' _ f r e e b s d . c . v ' ) && b . pref . os != . freebsd {
return false
}
if file . ends_with ( ' _ s o l a r i s . c . v ' ) && b . pref . os != . solaris {
return false
}
return true
}
[ inline ]
fn ( b Builder ) should_compile_js ( file string ) bool {
if ! file . ends_with ( ' . j s . v ' ) && file . split ( ' . ' ) . len > 2 {
// Probably something like `a.c.v`.
return false
}
return true
}
2020-04-07 00:44:19 +02:00
pub fn ( b Builder ) log ( s string ) {
if b . pref . is_verbose {
2020-02-03 07:31:54 +01:00
println ( s )
}
}
2020-03-01 21:56:07 +01:00
2020-04-07 00:44:19 +02:00
pub fn ( b Builder ) info ( s string ) {
if b . pref . is_verbose {
2020-03-31 19:58:44 +02:00
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
}
2020-04-11 08:57:31 +02:00
pub fn ( b Builder ) find_module_path ( mod string , fpath string ) ? string {
// support @VROOT/v.mod relative paths:
vmod_file_location := vmod . mod_file_cacher . get ( fpath )
2020-03-01 21:56:07 +01:00
mod_path := module_path ( mod )
2020-04-11 08:57:31 +02:00
mut module_lookup_paths := [ ] string
if vmod_file_location . vmod_file . len != 0 && ! ( vmod_file_location . vmod_folder in b . module_search_paths ) {
module_lookup_paths << vmod_file_location . vmod_folder
}
module_lookup_paths << b . module_search_paths
for search_path in module_lookup_paths {
2020-04-07 00:44:19 +02:00
try_path := os . join_path ( search_path , mod_path )
if b . pref . is_verbose {
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-04-07 00:44:19 +02:00
if b . pref . is_verbose {
2020-03-01 21:56:07 +01:00
println ( ' < < f o u n d $ try_path . ' )
}
return try_path
}
}
2020-04-11 08:57:31 +02:00
smodule_lookup_paths := module_lookup_paths . join ( ' , ' )
return error ( ' m o d u l e " $ mod " n o t f o u n d i n : \n $ smodule_lookup_paths ' )
2020-03-01 21:56:07 +01:00
}
2020-04-03 17:38:41 +02:00
fn verror ( s string ) {
util . verror ( ' b u i l d e r e r r o r ' , s )
}