2020-02-03 07:00:36 +03:00
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
2019-10-04 15:48:09 +03:00
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
2019-10-13 16:37:43 +03:00
module compiler
2019-10-04 15:48:09 +03:00
import (
strings
os
2019-11-09 23:49:15 +03:00
filepath
2020-02-09 12:08:04 +03:00
v . pref
2019-10-04 15:48:09 +03:00
)
2019-10-07 01:31:01 +03:00
/ *
. vh generation logic .
2019-10-10 02:59:33 +03:00
. vh files contain only function signatures , consts , and types .
2019-10-07 01:31:01 +03:00
They are used together with pre - compiled modules .
2019-10-04 15:48:09 +03:00
* /
2019-12-20 00:29:37 +03:00
2019-11-01 16:10:28 +03:00
struct VhGen {
mut :
2019-12-20 00:29:37 +03:00
i int // token index
2019-11-01 16:10:28 +03:00
consts strings . Builder
2019-12-20 00:29:37 +03:00
fns strings . Builder
types strings . Builder
2019-11-01 16:10:28 +03:00
tokens [ ] Token
2019-12-06 15:24:53 +03:00
}
2019-11-01 16:10:28 +03:00
2019-10-21 14:21:30 +03:00
// `mod` == "vlib/os"
fn generate_vh ( mod string ) {
2019-11-09 23:49:15 +03:00
println ( ' \n \n \n \n G e n e r a t i n g a V h e a d e r f i l e f o r m o d u l e ` $ mod ` ' )
2019-11-21 04:34:08 +03:00
vexe := vexe_path ( )
2019-12-23 13:09:22 +03:00
full_mod_path := filepath . join ( filepath . dir ( vexe ) , mod )
2019-11-09 23:49:15 +03:00
dir := if mod . starts_with ( ' v l i b ' ) { ' $ compiler . v_modules_path $ { os . path_separator } $ mod ' } else { mod }
2019-10-21 14:21:30 +03:00
path := dir + ' . v h '
pdir := dir . all_before_last ( os . path_separator )
2019-12-04 23:03:12 +03:00
if ! os . is_dir ( pdir ) {
2019-10-21 14:21:30 +03:00
os . mkdir_all ( pdir )
2019-11-23 19:55:18 +03:00
// os.mkdir(os.realpath(dir)) or { panic(err) }
2019-10-21 14:21:30 +03:00
}
2019-12-20 00:29:37 +03:00
mut out := os . create ( path ) or {
panic ( err )
}
mod_path := mod . replace ( ' \\ ' , ' / ' )
2019-11-09 23:49:15 +03:00
out . writeln ( ' / / $ mod_path m o d u l e h e a d e r \n ' )
mod_def := if mod_path . contains ( ' / ' ) { mod_path . all_after ( ' / ' ) } else { mod_path } // "os"
2019-10-23 15:55:14 +03:00
out . writeln ( ' m o d u l e $ mod_def \n ' )
2019-10-21 14:21:30 +03:00
// Consts
println ( full_mod_path )
2019-12-06 15:24:53 +03:00
vfiles := os . walk_ext ( full_mod_path , ' . v ' )
2019-12-20 00:29:37 +03:00
// mut vfiles := os.ls(full_mod_path) or {
// exit(1)
// }
filtered := vfiles . filter ( it . ends_with ( ' . v ' ) && ! it . ends_with ( ' t e s t . v ' ) && ! it . ends_with ( ' _ w i n d o w s . v ' ) && ! it . ends_with ( ' _ w i n . v ' ) && ! it . ends_with ( ' _ l i n . v ' ) && ! it . contains ( ' $ { os . path_separator } e x a m p l e s ' ) && ! it . contains ( ' _ j s . v ' ) && ! it . contains ( ' _ b a r e . v ' ) && ! it . contains ( ' $ { os . path_separator } j s ' ) ) // TODO merge once filter allows it
// println('f:')
// println(filtered)
2020-02-09 12:08:04 +03:00
mut pref := & pref . Preferences {
path : ' f o o . v '
}
pref . fill_with_defaults ( )
mut v := new_v ( pref )
2019-12-20 00:29:37 +03:00
// v.pref.generating_vh = true
2019-11-01 16:10:28 +03:00
mut g := VhGen {
2019-12-20 00:29:37 +03:00
consts : strings . new_builder ( 1000 )
fns : strings . new_builder ( 1000 )
types : strings . new_builder ( 1000 )
2019-11-01 16:10:28 +03:00
}
2019-10-21 14:21:30 +03:00
for file in filtered {
mut p := v . new_parser_from_file ( file )
2019-10-23 08:18:44 +03:00
p . scanner . is_vh = true
2019-10-21 14:21:30 +03:00
p . parse ( . decl )
2019-11-01 16:10:28 +03:00
g . tokens = p . tokens
g . i = 0
for ; g . i < p . tokens . len ; g . i ++ {
if ! p . tokens [ g . i ] . tok . is_decl ( ) {
2019-10-21 14:21:30 +03:00
continue
2019-12-06 15:24:53 +03:00
}
2019-11-01 16:10:28 +03:00
match g . tokens [ g . i ] . tok {
2019-12-20 00:29:37 +03:00
. key_fn {
g . generate_fn ( )
}
. key_const {
g . generate_const ( )
}
. key_struct {
g . generate_type ( )
}
. key_type {
g . generate_alias ( )
}
else {
} }
2019-12-06 15:24:53 +03:00
}
}
2019-12-20 00:29:37 +03:00
result := g . types . str ( ) + g . consts . str ( ) + g . fns . str ( ) . replace ( ' \n \n \n ' , ' \n ' ) . replace ( ' \n \n ' , ' \n ' )
2019-10-23 12:54:35 +03:00
out . writeln ( result . replace ( ' [ ] ' , ' [ ] ' ) . replace ( ' ? ' , ' ? ' ) )
2019-10-23 12:35:51 +03:00
out . close ( )
2019-10-21 14:21:30 +03:00
}
2019-11-01 16:10:28 +03:00
fn ( g mut VhGen ) generate_fn ( ) {
if g . i >= g . tokens . len - 2 {
return
2019-12-06 15:24:53 +03:00
}
2019-12-20 00:29:37 +03:00
mut next := g . tokens [ g . i + 1 ]
if g . i > 0 && g . tokens [ g . i - 1 ] . tok != . key_pub {
2019-10-21 14:21:30 +03:00
// Skip private fns
2019-12-20 00:29:37 +03:00
// return ''
2019-10-21 14:21:30 +03:00
}
if next . tok == . name && next . lit == ' C ' {
2019-12-20 00:29:37 +03:00
// println('skipping C')
2019-11-01 16:10:28 +03:00
return
2019-12-06 15:24:53 +03:00
}
2019-12-20 00:29:37 +03:00
// out.write('pub ')
2019-11-01 16:10:28 +03:00
mut tok := g . tokens [ g . i ]
for g . i < g . tokens . len - 1 && tok . tok != . lcbr {
2019-12-20 00:29:37 +03:00
next = g . tokens [ g . i + 1 ]
2019-11-01 16:10:28 +03:00
g . fns . write ( tok . str ( ) )
2019-12-20 00:29:37 +03:00
if tok . tok != . lpar && ! ( next . tok in [ . comma , . rpar ] ) {
2019-10-21 14:21:30 +03:00
// No space after (), [], etc
2019-11-01 16:10:28 +03:00
g . fns . write ( ' ' )
2019-10-21 14:21:30 +03:00
}
2019-11-01 16:10:28 +03:00
g . i ++
tok = g . tokens [ g . i ]
2019-12-06 15:24:53 +03:00
}
2019-11-01 16:10:28 +03:00
g . fns . writeln ( ' ' )
2019-12-20 00:29:37 +03:00
// g.i--
2019-12-06 15:24:53 +03:00
}
2019-10-21 14:21:30 +03:00
2019-11-01 16:10:28 +03:00
fn ( g mut VhGen ) generate_alias ( ) {
mut tok := g . tokens [ g . i ]
2019-12-20 00:29:37 +03:00
for g . i < g . tokens . len - 1 {
2019-11-01 16:10:28 +03:00
g . types . write ( tok . str ( ) )
g . types . write ( ' ' )
2019-12-20 00:29:37 +03:00
if tok . line_nr != g . tokens [ g . i + 1 ] . line_nr {
2019-10-31 13:08:01 +03:00
break
2019-12-06 15:24:53 +03:00
}
2019-11-01 16:10:28 +03:00
g . i ++
tok = g . tokens [ g . i ]
2019-10-31 13:08:01 +03:00
}
2019-11-01 16:10:28 +03:00
g . types . writeln ( ' \n ' )
2019-12-20 00:29:37 +03:00
// g.i--
2019-10-31 13:08:01 +03:00
}
2019-11-01 16:10:28 +03:00
fn ( g mut VhGen ) generate_const ( ) {
mut tok := g . tokens [ g . i ]
for g . i < g . tokens . len && tok . tok != . rpar {
g . consts . write ( tok . str ( ) )
g . consts . write ( ' ' )
2019-12-20 00:29:37 +03:00
if g . tokens [ g . i + 2 ] . tok == . assign {
2019-11-01 16:10:28 +03:00
g . consts . write ( ' \n \t ' )
2019-12-06 15:24:53 +03:00
}
2019-11-01 16:10:28 +03:00
g . i ++
tok = g . tokens [ g . i ]
2019-10-23 08:18:44 +03:00
}
2019-11-01 16:10:28 +03:00
g . consts . writeln ( ' \n ) ' )
2019-12-20 00:29:37 +03:00
// g.i--
2019-10-21 14:21:30 +03:00
}
2019-11-01 16:10:28 +03:00
fn ( g mut VhGen ) generate_type ( ) {
2019-12-20 00:29:37 +03:00
// old := g.i
2019-11-01 16:10:28 +03:00
mut tok := g . tokens [ g . i ]
for g . i < g . tokens . len && tok . tok != . rcbr {
g . types . write ( tok . str ( ) )
g . types . write ( ' ' )
2019-12-20 00:29:37 +03:00
if g . tokens [ g . i + 1 ] . line_nr != g . tokens [ g . i ] . line_nr {
2019-11-01 16:10:28 +03:00
g . types . write ( ' \n \t ' )
2019-12-06 15:24:53 +03:00
}
2019-11-01 16:10:28 +03:00
g . i ++
tok = g . tokens [ g . i ]
2019-10-23 13:03:14 +03:00
}
2019-11-01 16:10:28 +03:00
g . types . writeln ( ' \n } ' )
2019-12-20 00:29:37 +03:00
// g.i = old
// g.i--
2019-10-23 13:03:14 +03:00
}