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