compiler: module init function & init consts for cached modules
parent
c7e47e6884
commit
51388fea75
|
@ -66,7 +66,15 @@ fn (v mut V) cc() {
|
|||
// Create the modules & out directory if it's not there.
|
||||
out_dir := '$v_modules_path${os.PathSeparator}$v.dir'
|
||||
if !os.dir_exists(out_dir) {
|
||||
os.mkdir(out_dir)
|
||||
// create recursive
|
||||
mut mkpath := v_modules_path
|
||||
for subdir in v.dir.split(os.PathSeparator) {
|
||||
mkpath += os.PathSeparator + subdir
|
||||
if !os.dir_exists(mkpath) {
|
||||
os.mkdir(mkpath)
|
||||
}
|
||||
}
|
||||
//os.mkdir(out_dir)
|
||||
}
|
||||
v.out_name = '${out_dir}.o' //v.out_name
|
||||
println('Building ${v.out_name}...')
|
||||
|
@ -120,16 +128,17 @@ fn (v mut V) cc() {
|
|||
os.system('$vexe build module vlib/builtin')
|
||||
}
|
||||
for imp in v.table.imports {
|
||||
if imp == 'webview' {
|
||||
continue
|
||||
}
|
||||
path := '$v_modules_path/vlib/${imp}.o'
|
||||
println('adding ${imp}.o')
|
||||
if imp.contains('vweb') { continue } // not working
|
||||
if imp == 'webview' { continue }
|
||||
|
||||
imp_path := imp.replace('.', os.PathSeparator)
|
||||
path := '$v_modules_path/vlib/${imp_path}.o'
|
||||
println('adding ${imp_path}.o')
|
||||
if os.file_exists(path) {
|
||||
libs += ' ' + path
|
||||
} else {
|
||||
println('$path not found... building module $imp')
|
||||
os.system('$vexe build module vlib/$imp')
|
||||
os.system('$vexe build module vlib/$imp_path')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -150,7 +150,6 @@ typedef map map_string;
|
|||
byteptr g_str_buf;
|
||||
int load_so(byteptr);
|
||||
void reload_so();
|
||||
void init_consts();
|
||||
'
|
||||
|
||||
js_headers = '
|
||||
|
@ -176,10 +175,5 @@ var rune = function() {}
|
|||
var map_string = function() {}
|
||||
var map_int = function() {}
|
||||
|
||||
function init_consts() {
|
||||
|
||||
}
|
||||
|
||||
'
|
||||
|
||||
)
|
||||
|
|
|
@ -254,7 +254,8 @@ fn (p mut Parser) fn_decl() {
|
|||
}
|
||||
// full mod function name
|
||||
// os.exit ==> os__exit()
|
||||
if !is_c && !p.builtin_mod && receiver_typ.len == 0 {
|
||||
// if !is_c && !p.builtin_mod && receiver_typ.len == 0 {
|
||||
if !is_c && receiver_typ.len == 0 && (!p.builtin_mod || (p.builtin_mod && f.name == 'init')) {
|
||||
f.name = p.prepend_mod(f.name)
|
||||
}
|
||||
if p.first_pass() && receiver_typ.len == 0 {
|
||||
|
@ -363,6 +364,7 @@ fn (p mut Parser) fn_decl() {
|
|||
p.gen_fn_decl(f, typ, str_args)
|
||||
}
|
||||
}
|
||||
|
||||
if is_fn_header {
|
||||
p.genln('$typ $fn_name_cgen($str_args);')
|
||||
p.fgenln('')
|
||||
|
|
|
@ -227,6 +227,7 @@ fn (table mut Table) fn_gen_name(f &Fn) string {
|
|||
f.mod != 'darwin' &&
|
||||
f.mod != 'os' &&
|
||||
f.mod != 'json' &&
|
||||
!f.name.ends_with('_init') &&
|
||||
!f.name.contains('window_proc') &&
|
||||
!name.ends_with('_str') &&
|
||||
!name.contains('contains') {
|
||||
|
|
128
compiler/main.v
128
compiler/main.v
|
@ -71,6 +71,7 @@ mut:
|
|||
mod string // module being built with -lib
|
||||
parsers []Parser
|
||||
vgen_buf strings.Builder // temporary buffer for generated V code (.str() etc)
|
||||
cached_mods []string
|
||||
}
|
||||
|
||||
struct Preferences {
|
||||
|
@ -269,6 +270,15 @@ fn (v mut V) compile() {
|
|||
for file in v.files {
|
||||
v.parse(file, .decl)
|
||||
}
|
||||
|
||||
// generate missing module init's
|
||||
init_parsers := v.module_gen_init_parsers()
|
||||
// run decl pass
|
||||
for i in 0..init_parsers.len {
|
||||
mut ip := init_parsers[i]
|
||||
ip.parse(.decl)
|
||||
}
|
||||
|
||||
// Main pass
|
||||
cgen.pass = Pass.main
|
||||
if v.pref.is_debug {
|
||||
|
@ -334,6 +344,11 @@ fn (v mut V) compile() {
|
|||
// new vfmt is not ready yet
|
||||
}
|
||||
}
|
||||
// run main parser on the init parsers
|
||||
for i in 0..init_parsers.len {
|
||||
mut ip := init_parsers[i]
|
||||
ip.parse(.main)
|
||||
}
|
||||
// Generate .vh if we are building a module
|
||||
if v.pref.build_mode == .build_module {
|
||||
v.generate_vh()
|
||||
|
@ -345,9 +360,13 @@ fn (v mut V) compile() {
|
|||
v.vgen_buf.free()
|
||||
vgen_parser.parse(.main)
|
||||
// v.parsers.add(vgen_parser)
|
||||
v.log('Done parsing.')
|
||||
|
||||
// All definitions
|
||||
mut def := strings.new_builder(10000)// Avoid unnecessary allocations
|
||||
if v.pref.build_mode == .build_module {
|
||||
init_fn_name := v.mod.replace('.', '__') + '__init_consts'
|
||||
def.writeln('void $init_fn_name();')
|
||||
}
|
||||
$if !js {
|
||||
def.writeln(cgen.includes.join_lines())
|
||||
def.writeln(cgen.typedefs.join_lines())
|
||||
|
@ -365,6 +384,7 @@ fn (v mut V) compile() {
|
|||
def.writeln(v.prof_counters())
|
||||
}
|
||||
cgen.lines[defs_pos] = def.str()
|
||||
v.generate_init()
|
||||
v.generate_main()
|
||||
v.generate_hot_reload_code()
|
||||
if v.pref.is_verbose {
|
||||
|
@ -380,28 +400,68 @@ fn (v mut V) compile() {
|
|||
v.cc()
|
||||
}
|
||||
|
||||
fn (v mut V) generate_main() {
|
||||
mut cgen := v.cgen
|
||||
fn (v mut V) module_gen_init_parsers() []Parser {
|
||||
mut parsers := []Parser
|
||||
if v.pref.build_mode == .build_module {
|
||||
init_fn_name := mod_gen_name(v.mod) + '__init'
|
||||
if !v.table.known_fn(init_fn_name) {
|
||||
mod_def := if v.mod.contains('.') { v.mod.all_after('.') } else { v.mod }
|
||||
mut fn_v := 'module $mod_def\n\n'
|
||||
fn_v += 'fn init() { /*println(\'$v.mod module init\')*/ }'
|
||||
mut p := v.new_parser_from_string(fn_v, 'init_gen_$v.mod')
|
||||
p.mod = v.mod
|
||||
parsers << p
|
||||
}
|
||||
}
|
||||
else if v.pref.build_mode == .default_mode {
|
||||
for mod in v.table.imports {
|
||||
if mod in v.cached_mods { continue }
|
||||
init_fn_name := mod_gen_name(mod) + '__init'
|
||||
if !v.table.known_fn(init_fn_name) {
|
||||
mod_def := if mod.contains('.') { mod.all_after('.') } else { mod }
|
||||
mut fn_v := 'module $mod_def\n\n'
|
||||
fn_v += 'fn init() { /*println(\'$v.mod module init\')*/ }'
|
||||
mut p := v.new_parser_from_string(fn_v, 'init_gen_$mod')
|
||||
p.mod = mod
|
||||
parsers << p
|
||||
}
|
||||
}
|
||||
}
|
||||
return parsers
|
||||
}
|
||||
|
||||
fn (v mut V) generate_init() {
|
||||
$if js { return }
|
||||
|
||||
///// After this point, the v files are compiled.
|
||||
///// The rest is auto generated code, which will not have
|
||||
///// different .v source file/line numbers.
|
||||
lines_so_far := cgen.lines.join('\n').count('\n') + 5
|
||||
cgen.genln('')
|
||||
cgen.genln('////////////////// Reset the file/line numbers //////////')
|
||||
cgen.lines << '#line $lines_so_far "${cescaped_path(os.realpath(cgen.out_path))}"'
|
||||
cgen.genln('')
|
||||
|
||||
if v.pref.build_mode == .build_module {
|
||||
nogen := v.cgen.nogen
|
||||
v.cgen.nogen = false
|
||||
consts_init_body := v.cgen.consts_init.join_lines()
|
||||
init_fn_name := mod_gen_name(v.mod) + '__init_consts'
|
||||
println('generating init for $v.mod: $init_fn_name')
|
||||
v.cgen.genln('void ${init_fn_name}() {\n$consts_init_body\n}')
|
||||
v.cgen.nogen = nogen
|
||||
}
|
||||
if v.pref.build_mode == .default_mode {
|
||||
mut consts_init_body := cgen.consts_init.join_lines()
|
||||
mut call_mod_init := ''
|
||||
mut call_mod_init_consts := ''
|
||||
for mod in v.table.imports {
|
||||
init_fn_name := mod_gen_name(mod) + '__init'
|
||||
call_mod_init += '${init_fn_name}();\n'
|
||||
if mod in v.cached_mods {
|
||||
call_mod_init_consts += '${init_fn_name}_consts();\n'
|
||||
}
|
||||
}
|
||||
consts_init_body := v.cgen.consts_init.join_lines()
|
||||
// vlib can't have `init_consts()`
|
||||
cgen.genln('void init_consts() {
|
||||
v.cgen.genln('void init() {
|
||||
g_str_buf=malloc(1000);
|
||||
$call_mod_init_consts
|
||||
$consts_init_body
|
||||
builtin__init();
|
||||
$call_mod_init
|
||||
}')
|
||||
// _STR function can't be defined in vlib
|
||||
cgen.genln('
|
||||
v.cgen.genln('
|
||||
string _STR(const char *fmt, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
|
@ -435,6 +495,20 @@ string _STR_TMP(const char *fmt, ...) {
|
|||
|
||||
')
|
||||
}
|
||||
}
|
||||
|
||||
fn (v mut V) generate_main() {
|
||||
mut cgen := v.cgen
|
||||
$if js { return }
|
||||
|
||||
///// After this point, the v files are compiled.
|
||||
///// The rest is auto generated code, which will not have
|
||||
///// different .v source file/line numbers.
|
||||
lines_so_far := cgen.lines.join('\n').count('\n') + 5
|
||||
cgen.genln('')
|
||||
cgen.genln('////////////////// Reset the file/line numbers //////////')
|
||||
cgen.lines << '#line $lines_so_far "${cescaped_path(os.realpath(cgen.out_path))}"'
|
||||
cgen.genln('')
|
||||
|
||||
// Make sure the main function exists
|
||||
// Obviously we don't need it in libraries
|
||||
|
@ -483,7 +557,7 @@ string _STR_TMP(const char *fmt, ...) {
|
|||
|
||||
fn (v mut V) gen_main_start(add_os_args bool){
|
||||
v.cgen.genln('int main(int argc, char** argv) { ')
|
||||
v.cgen.genln(' init_consts();')
|
||||
v.cgen.genln(' init();')
|
||||
if add_os_args && 'os' in v.table.imports {
|
||||
v.cgen.genln(' os__args = os__init_os_args(argc, (byteptr*)argv);')
|
||||
}
|
||||
|
@ -597,6 +671,10 @@ fn (v mut V) add_v_files_to_compile() {
|
|||
// Parse user imports
|
||||
for file in v.get_user_files() {
|
||||
mut p := v.new_parser_from_file(file)
|
||||
// set mod so we dont have to resolve submodule
|
||||
if v.pref.build_mode == .build_module && file.contains(v.mod.replace('.', os.PathSeparator)) {
|
||||
p.mod = v.mod
|
||||
}
|
||||
p.parse(.imports)
|
||||
//if p.pref.autofree { p.scanner.text.free() free(p.scanner) }
|
||||
v.add_parser(p)
|
||||
|
@ -617,11 +695,12 @@ fn (v mut V) add_v_files_to_compile() {
|
|||
}
|
||||
|
||||
// use cached built module if exists
|
||||
if v.pref.build_mode != .build_module {
|
||||
vh_path := '$v_modules_path/${mod}.vh'
|
||||
//println(vh_path)
|
||||
if v.pref.build_mode != .build_module && !mod.contains('vweb') {
|
||||
mod_path := mod.replace('.', os.PathSeparator)
|
||||
vh_path := '$v_modules_path/${mod_path}.vh'
|
||||
if v.pref.is_debug && os.file_exists(vh_path) {
|
||||
println('using cached module `$mod`: $vh_path')
|
||||
v.cached_mods << mod
|
||||
v.files << vh_path
|
||||
continue
|
||||
}
|
||||
|
@ -791,15 +870,18 @@ fn new_v(args[]string) &V {
|
|||
if joined_args.contains('build module ') {
|
||||
build_mode = .build_module
|
||||
// v build module ~/v/os => os.o
|
||||
mod = if adir.contains(os.PathSeparator) {
|
||||
mod_path := if adir.contains('vlib') {
|
||||
adir.all_after('vlib'+os.PathSeparator)
|
||||
}
|
||||
else if adir.contains(os.PathSeparator) {
|
||||
adir.all_after(os.PathSeparator)
|
||||
} else {
|
||||
adir
|
||||
}
|
||||
mod = mod_path.replace(os.PathSeparator, '.')
|
||||
println('Building module "${mod}" (dir="$dir")...')
|
||||
//out_name = '$TmpPath/vlib/${base}.o'
|
||||
out_name = mod + '.o'
|
||||
println('$out_name')
|
||||
out_name = mod
|
||||
// Cross compiling? Use separate dirs for each os
|
||||
/*
|
||||
if target_os != os.user_os() {
|
||||
|
|
|
@ -106,17 +106,27 @@ fn v_type_str(typ_ string) string {
|
|||
|
||||
fn (v &V) generate_vh() {
|
||||
println('\n\n\n\nGenerating a V header file for module `$v.mod`')
|
||||
dir := '$v_modules_path${os.PathSeparator}$v.mod'
|
||||
mod_path := v.mod.replace('.', os.PathSeparator)
|
||||
dir := '$v_modules_path${os.PathSeparator}$mod_path'
|
||||
path := dir + '.vh'
|
||||
if !os.dir_exists(dir) {
|
||||
os.mkdir(dir)
|
||||
// create recursive
|
||||
mut mkpath := v_modules_path
|
||||
for subdir in mod_path.split(os.PathSeparator) {
|
||||
mkpath += os.PathSeparator + subdir
|
||||
if !os.dir_exists(mkpath) {
|
||||
os.mkdir(mkpath)
|
||||
}
|
||||
}
|
||||
// os.mkdir(os.realpath(dir))
|
||||
}
|
||||
println(path)
|
||||
|
||||
file := os.create(path) or { panic(err) }
|
||||
// Consts
|
||||
mod_def := if v.mod.contains('.') { v.mod.all_after('.') } else { v.mod }
|
||||
file.writeln('// $v.mod module header \n')
|
||||
file.writeln('module $v.mod')
|
||||
file.writeln('module $mod_def')
|
||||
file.writeln('// Consts')
|
||||
if v.table.consts.len > 0 {
|
||||
file.writeln('const (')
|
||||
|
|
|
@ -60,3 +60,11 @@ fn (v &V) find_module_path(mod string) ?string {
|
|||
}
|
||||
return import_path
|
||||
}
|
||||
|
||||
fn mod_gen_name(mod string) string {
|
||||
return mod.replace('.', '_dot_')
|
||||
}
|
||||
|
||||
fn mod_gen_name_rev(mod string) string {
|
||||
return mod.replace('_dot_', '.')
|
||||
}
|
|
@ -245,18 +245,26 @@ fn (p mut Parser) parse(pass Pass) {
|
|||
//p.log('\nparse() run=$p.pass file=$p.file_name tok=${p.strtok()}')// , "script_file=", script_file)
|
||||
// `module main` is not required if it's a single file program
|
||||
if p.is_script || p.pref.is_test {
|
||||
p.mod = 'main'
|
||||
// User may still specify `module main`
|
||||
if p.tok == .key_module {
|
||||
p.next()
|
||||
p.fgen('module ')
|
||||
p.mod = p.check_name()
|
||||
mod := p.check_name()
|
||||
if p.mod == '' {
|
||||
p.mod = mod
|
||||
}
|
||||
} else {
|
||||
p.mod = 'main'
|
||||
}
|
||||
}
|
||||
else {
|
||||
p.check(.key_module)
|
||||
p.fspace()
|
||||
p.mod = p.check_name()
|
||||
// setting mod manually for mod init parsers
|
||||
mod := p.check_name()
|
||||
if p.mod == '' {
|
||||
p.mod = mod
|
||||
}
|
||||
}
|
||||
//
|
||||
|
||||
|
@ -270,12 +278,13 @@ fn (p mut Parser) parse(pass Pass) {
|
|||
p.builtin_mod = p.mod == 'builtin'
|
||||
p.can_chash = p.mod=='ui' || p.mod == 'darwin'// TODO tmp remove
|
||||
// Import pass - the first and the smallest pass that only analyzes imports
|
||||
// fully qualify the module name, eg base64 to encoding.base64
|
||||
|
||||
fq_mod := p.table.qualify_module(p.mod, p.file_path)
|
||||
p.import_table.module_name = fq_mod
|
||||
p.table.register_module(fq_mod)
|
||||
// replace "." with "_dot_" in module name for C variable names
|
||||
p.mod = fq_mod.replace('.', '_dot_')
|
||||
p.mod = mod_gen_name(fq_mod)
|
||||
|
||||
if p.pass == .imports {
|
||||
for p.tok == .key_import && p.peek() != .key_const {
|
||||
p.imports()
|
||||
|
@ -1063,7 +1072,7 @@ fn (p mut Parser) get_type() string {
|
|||
if !p.builtin_mod && p.import_table.known_alias(typ) {
|
||||
mod := p.import_table.resolve_alias(typ)
|
||||
if mod.contains('.') {
|
||||
typ = mod.replace('.', '_dot_')
|
||||
typ = mod_gen_name(mod)
|
||||
}
|
||||
}
|
||||
p.next()
|
||||
|
@ -1791,7 +1800,7 @@ fn (p mut Parser) name_expr() string {
|
|||
p.import_table.register_used_import(name)
|
||||
// we replaced "." with "_dot_" in p.mod for C variable names,
|
||||
// do same here.
|
||||
mod = p.import_table.resolve_alias(name).replace('.', '_dot_')
|
||||
mod = mod_gen_name(p.import_table.resolve_alias(name))
|
||||
}
|
||||
p.next()
|
||||
p.check(.dot)
|
||||
|
@ -1956,7 +1965,7 @@ fn (p mut Parser) name_expr() string {
|
|||
// If orig_name is a mod, then printing undefined: `mod` tells us nothing
|
||||
// if p.table.known_mod(orig_name) {
|
||||
if p.table.known_mod(orig_name) || p.import_table.known_alias(orig_name) {
|
||||
name = name.replace('__', '.').replace('_dot_', '.')
|
||||
name = mod_gen_name_rev(name.replace('__', '.'))
|
||||
p.error('undefined: `$name`')
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
module builtin
|
||||
|
||||
fn builtin_init() int {
|
||||
fn init() {
|
||||
$if windows {
|
||||
if is_atty(0) {
|
||||
C._setmode(C._fileno(C.stdin), C._O_U16TEXT)
|
||||
|
@ -15,13 +15,8 @@ fn builtin_init() int {
|
|||
C.SetConsoleMode(C.GetStdHandle(C.STD_OUTPUT_HANDLE), C.ENABLE_PROCESSED_OUTPUT | 0x0004) // ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
C.setbuf(C.stdout,0)
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
const (
|
||||
_ = builtin_init()
|
||||
)
|
||||
|
||||
fn C.memcpy(byteptr, byteptr, int)
|
||||
fn C.memmove(byteptr, byteptr, int)
|
||||
//fn C.malloc(int) byteptr
|
||||
|
|
|
@ -9,7 +9,6 @@ import http.chunked
|
|||
|
||||
const (
|
||||
max_redirects = 4
|
||||
_ = http.init()
|
||||
)
|
||||
|
||||
struct Request {
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
module net
|
||||
|
||||
const (
|
||||
_ = net.init()
|
||||
)
|
||||
|
||||
// hostname returns the host name reported by the kernel.
|
||||
pub fn hostname() ?string {
|
||||
mut name := [256]byte
|
||||
|
|
Loading…
Reference in New Issue