v/vlib/compiler/module_header.v

174 lines
4.1 KiB
V
Raw Normal View History

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.
module compiler
2019-10-04 14:48:09 +02:00
import (
strings
os
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.
.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-11-01 14:10:28 +01:00
// `mod` == "vlib/os"
fn generate_vh(mod string) {
println('\n\n\n\nGenerating a V header file for module `$mod`')
2020-02-20 11:33:01 +01:00
vexe := pref.vexe_path()
2019-12-23 11:09:22 +01:00
full_mod_path := filepath.join(filepath.dir(vexe),mod)
2020-02-17 20:31:23 +01:00
dir := if mod.starts_with('vlib') { '$compiler.v_modules_path${filepath.separator}$mod' } else { mod }
path := dir + '.vh'
2020-02-17 20:31:23 +01:00
pdir := dir.all_before_last(filepath.separator)
if !os.is_dir(pdir) {
os.mkdir_all(pdir)
2019-11-23 17:55:18 +01:00
// os.mkdir(os.realpath(dir)) or { panic(err) }
}
2019-12-19 22:29:37 +01:00
mut out := os.create(path)or{
panic(err)
}
mod_path := mod.replace('\\', '/')
out.writeln('// $mod_path module header\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('module $mod_def\n')
// Consts
println(full_mod_path)
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)
// }
2020-02-17 20:31:23 +01:00
filtered := vfiles.filter(it.ends_with('.v') && !it.ends_with('test.v') && !it.ends_with('_windows.v') && !it.ends_with('_win.v') && !it.ends_with('_lin.v') && !it.contains('${filepath.separator}examples') && !it.contains('_js.v') && !it.contains('_bare.v') && !it.contains('${filepath.separator}js')) // TODO merge once filter allows it
2019-12-19 22:29:37 +01:00
// println('f:')
// println(filtered)
2020-02-09 10:08:04 +01:00
mut pref := &pref.Preferences {
path: 'foo.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
}
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
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() {
continue
}
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-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-11-01 14:10:28 +01:00
fn (g mut VhGen) generate_fn() {
if g.i >= g.tokens.len - 2 {
return
}
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 {
// Skip private fns
2019-12-19 22:29:37 +01:00
// return ''
}
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-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]) {
// No space after (), [], etc
2019-11-01 14:10:28 +01:00
g.fns.write(' ')
}
2019-11-01 14:10:28 +01:00
g.i++
tok = g.tokens[g.i]
}
2019-11-01 14:10:28 +01:00
g.fns.writeln('')
2019-12-19 22:29:37 +01:00
// g.i--
}
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-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-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-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-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
}