1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

caching modules: almost there

This commit is contained in:
Alexander Medvednikov 2019-10-07 01:31:01 +03:00
parent dbd72ee828
commit a9a73d9315
15 changed files with 209 additions and 161 deletions

View File

@ -106,14 +106,13 @@ fn (v mut V) cc() {
a << f a << f
} }
mut libs := ''// builtin.o os.o http.o etc libs := ''// builtin.o os.o http.o etc
if v.pref.build_mode == .build_module { if v.pref.build_mode == .build_module {
a << '-c' a << '-c'
} }
else if v.pref.build_mode == .embed_vlib {
//
}
else if v.pref.build_mode == .default_mode { else if v.pref.build_mode == .default_mode {
/*
// TODO
libs = '$v_modules_path/vlib/builtin.o' libs = '$v_modules_path/vlib/builtin.o'
if !os.file_exists(libs) { if !os.file_exists(libs) {
println('object file `$libs` not found') println('object file `$libs` not found')
@ -125,6 +124,7 @@ fn (v mut V) cc() {
} }
libs += ' "$v_modules_path/vlib/${imp}.o"' libs += ' "$v_modules_path/vlib/${imp}.o"'
} }
*/
} }
if v.pref.sanitize { if v.pref.sanitize {
a << '-fsanitize=leak' a << '-fsanitize=leak'
@ -248,8 +248,8 @@ fn (v mut V) cc() {
println('linux cross compilation done. resulting binary: "$v.out_name"') println('linux cross compilation done. resulting binary: "$v.out_name"')
} }
*/ */
if !v.pref.is_debug && v.out_name_c != 'v.c' && v.out_name_c != 'v_macos.c' { if !v.pref.is_debug && v.out_name_c != 'v.c' {
os.rm(v.out_name_c) //os.rm(v.out_name_c)
} }
if v.pref.compress { if v.pref.compress {
$if windows { $if windows {

View File

@ -161,6 +161,9 @@ fn (g mut CGen) set_placeholder(pos int, val string) {
} }
fn (g mut CGen) insert_before(val string) { fn (g mut CGen) insert_before(val string) {
if g.nogen {
return
}
prev := g.lines[g.lines.len - 1] prev := g.lines[g.lines.len - 1]
g.lines[g.lines.len - 1] = '$prev \n $val \n' g.lines[g.lines.len - 1] = '$prev \n $val \n'
} }

View File

@ -254,7 +254,7 @@ fn (s mut Scanner) get_scanner_pos_of_token(t &Token) ScannerPos {
sptoken.pos += tcol sptoken.pos += tcol
} }
s.ignore_line() s.eat_single_newline() s.ignore_line() s.eat_single_newline()
sline := s.text.substr( prevlinepos, s.pos ).trim_right('\r\n') sline := s.text.substr( prevlinepos, s.pos )//.trim_right('\r\n')
s.file_lines << sline s.file_lines << sline
} }
////////////////////////////////////////////////// //////////////////////////////////////////////////

View File

@ -144,9 +144,8 @@ fn (p mut Parser) comp_time() {
// #include, #flag, #v // #include, #flag, #v
fn (p mut Parser) chash() { fn (p mut Parser) chash() {
hash := p.lit.trim_space() hash := p.lit.trim_space()
// println('chsh() file=$p.file is_sig=${p.is_sig()} hash="$hash"') // println('chsh() file=$p.file hash="$hash"')
p.next() p.next()
is_sig := p.is_sig()
if hash.starts_with('flag ') { if hash.starts_with('flag ') {
mut flag := hash.right(5) mut flag := hash.right(5)
// expand `@VROOT` `@VMOD` to absolute path // expand `@VROOT` `@VMOD` to absolute path
@ -157,7 +156,7 @@ fn (p mut Parser) chash() {
return return
} }
if hash.starts_with('include') { if hash.starts_with('include') {
if p.first_pass() && !is_sig { if p.first_pass() && !p.is_vh {
if p.file_pcguard.len != 0 { if p.file_pcguard.len != 0 {
//println('p: $p.file_platform $p.file_pcguard') //println('p: $p.file_platform $p.file_pcguard')
p.cgen.includes << '$p.file_pcguard\n#$hash\n#endif' p.cgen.includes << '$p.file_pcguard\n#$hash\n#endif'

View File

@ -134,12 +134,6 @@ fn (p mut Parser) clear_vars() {
} }
} }
// vlib header file?
fn (p mut Parser) is_sig() bool {
return (p.pref.build_mode == .default_mode || p.pref.build_mode == .build_module) &&
(p.file_path.contains(v_modules_path))
}
// Function signatures are added to the top of the .c file in the first run. // Function signatures are added to the top of the .c file in the first run.
fn (p mut Parser) fn_decl() { fn (p mut Parser) fn_decl() {
p.clear_vars() // clear local vars every time a new fn is started p.clear_vars() // clear local vars every time a new fn is started
@ -231,10 +225,9 @@ fn (p mut Parser) fn_decl() {
// C function header def? (fn C.NSMakeRect(int,int,int,int)) // C function header def? (fn C.NSMakeRect(int,int,int,int))
is_c := f.name == 'C' && p.tok == .dot is_c := f.name == 'C' && p.tok == .dot
// Just fn signature? only builtin.v + default build mode // Just fn signature? only builtin.v + default build mode
// is_sig := p.builtin_mod && p.pref.build_mode == default_mode if p.pref.build_mode == .build_module {
// is_sig := p.pref.build_mode == default_mode && (p.builtin_mod || p.file.contains(LANG_TMP)) println('\n\nfn_decl() name=$f.name receiver_typ=$receiver_typ nogen=$p.cgen.nogen')
is_sig := p.is_sig() }
// println('\n\nfn_decl() name=$f.name receiver_typ=$receiver_typ')
if is_c { if is_c {
p.check(.dot) p.check(.dot)
f.name = p.check_name() f.name = p.check_name()
@ -312,13 +305,15 @@ fn (p mut Parser) fn_decl() {
} }
p.cgen.typedefs << 'typedef struct $typ $typ;' p.cgen.typedefs << 'typedef struct $typ $typ;'
} }
// Translated C code can have empty functions (just definitions) // Translated C code and .vh can have empty functions (just definitions)
is_fn_header := !is_c && !is_sig && (p.pref.translated || p.pref.is_test) && p.tok != .lcbr is_fn_header := !is_c && !p.is_vh &&
(p.pref.translated || p.pref.is_test || p.is_vh) &&
p.tok != .lcbr
if is_fn_header { if is_fn_header {
f.is_decl = true f.is_decl = true
} }
// { required only in normal function declarations // { required only in normal function declarations
if !is_c && !is_sig && !is_fn_header { if !is_c && !p.is_vh && !is_fn_header {
p.fgen(' ') p.fgen(' ')
p.check(.lcbr) p.check(.lcbr)
} }
@ -350,7 +345,7 @@ fn (p mut Parser) fn_decl() {
mut fn_name_cgen := p.table.fn_gen_name(f) mut fn_name_cgen := p.table.fn_gen_name(f)
// Start generation of the function body // Start generation of the function body
skip_main_in_test := false skip_main_in_test := false
if !is_c && !is_live && !is_sig && !is_fn_header && !skip_main_in_test { if !is_c && !is_live && !p.is_vh && !is_fn_header && !skip_main_in_test {
if p.pref.obfuscate { if p.pref.obfuscate {
p.genln('; // $f.name') p.genln('; // $f.name')
} }
@ -403,10 +398,10 @@ fn (p mut Parser) fn_decl() {
// println('register_fn typ=$typ isg=$is_generic') // println('register_fn typ=$typ isg=$is_generic')
p.table.register_fn(f) p.table.register_fn(f)
} }
if is_sig || p.first_pass() || is_live || is_fn_header || skip_main_in_test { if p.is_vh || p.first_pass() || is_live || is_fn_header || skip_main_in_test {
// First pass? Skip the body for now // First pass? Skip the body for now
// Look for generic calls. // Look for generic calls.
if !is_sig && !is_fn_header { if !p.is_vh && !is_fn_header {
p.skip_fn_body() p.skip_fn_body()
} }
// Live code reloading? Load all fns from .so // Live code reloading? Load all fns from .so
@ -422,19 +417,8 @@ fn (p mut Parser) fn_decl() {
} }
// Add function definition to the top // Add function definition to the top
if !is_c && p.first_pass() { if !is_c && p.first_pass() {
// TODO hack to make Volt compile without -embed_vlib p.cgen.fns << fn_decl + ';'
if f.name == 'darwin__nsstring' && p.pref.build_mode == .default_mode {
} else {
p.cgen.fns << fn_decl + ';'
}
} }
// Generate .vh header files when building a module
/*
if p.pref.build_mode == .build_module {
p.vh_genln(f.v_definition())
}
*/
return return
} }
if p.attr == 'live' && p.pref.is_so { if p.attr == 'live' && p.pref.is_so {
@ -448,8 +432,7 @@ fn (p mut Parser) fn_decl() {
} }
} }
// println('is_c=$is_c name=$f.name') // println('is_c=$is_c name=$f.name')
if is_c || is_sig || is_fn_header { if is_c || p.is_vh || is_fn_header {
// println('IS SIG .key_returnING tok=${p.strtok()}')
return return
} }
// Profiling mode? Start counting at the beginning of the function (save current time). // Profiling mode? Start counting at the beginning of the function (save current time).
@ -465,7 +448,7 @@ fn (p mut Parser) fn_decl() {
p.cgen.nogen = true p.cgen.nogen = true
} }
p.statements_no_rcbr() p.statements_no_rcbr()
p.cgen.nogen = false //p.cgen.nogen = false
// Print counting result after all statements in main // Print counting result after all statements in main
if p.pref.is_prof && f.name == 'main' { if p.pref.is_prof && f.name == 'main' {
p.genln(p.print_prof_counters()) p.genln(p.print_prof_counters())

View File

@ -169,7 +169,8 @@ fn (p mut Parser) index_get(typ string, fn_ph int, cfg IndexCfg) {
if cfg.is_map { if cfg.is_map {
p.gen('$tmp') p.gen('$tmp')
def := type_default(typ) def := type_default(typ)
p.cgen.insert_before('$typ $tmp = $def; bool $tmp_ok = map_get($index_expr, & $tmp);') p.cgen.insert_before('$typ $tmp = $def; ' +
'bool $tmp_ok = map_get(/*$p.file_name : $p.scanner.line_nr*/$index_expr, & $tmp);')
} }
else if cfg.is_arr { else if cfg.is_arr {
if p.pref.translated && !p.builtin_mod { if p.pref.translated && !p.builtin_mod {

View File

@ -18,9 +18,6 @@ enum BuildMode {
// `v program.v' // `v program.v'
// Build user code only, and add pre-compiled vlib (`cc program.o builtin.o os.o...`) // Build user code only, and add pre-compiled vlib (`cc program.o builtin.o os.o...`)
default_mode default_mode
// `v -embed_vlib program.v`
// vlib + user code in one file (slower compilation, but easier when working on vlib and cross-compiling)
embed_vlib
// `v -lib ~/v/os` // `v -lib ~/v/os`
// build any module (generate os.o + os.vh) // build any module (generate os.o + os.vh)
build_module build_module
@ -290,36 +287,25 @@ fn (v mut V) compile() {
cgen.genln('#define V_COMMIT_HASH "' + vhash() + '"') cgen.genln('#define V_COMMIT_HASH "' + vhash() + '"')
cgen.genln('#endif') cgen.genln('#endif')
} }
q := cgen.nogen // TODO hack
cgen.nogen = false
$if js { $if js {
cgen.genln(js_headers) cgen.genln(js_headers)
} $else { } $else {
cgen.genln(CommonCHeaders) cgen.genln(CommonCHeaders)
} }
v.generate_hotcode_reloading_declarations() v.generate_hotcode_reloading_declarations()
imports_json := 'json' in v.table.imports
// TODO remove global UI hack
if v.os == .mac && ((v.pref.build_mode == .embed_vlib && 'ui' in
v.table.imports) || (v.pref.build_mode == .build_module &&
v.dir.contains('/ui'))) {
cgen.genln('id defaultFont = 0; // main.v')
}
// We need the cjson header for all the json decoding that will be done in // We need the cjson header for all the json decoding that will be done in
// default mode // default mode
imports_json := 'json' in v.table.imports
if v.pref.build_mode == .default_mode { if v.pref.build_mode == .default_mode {
if imports_json { if imports_json {
cgen.genln('#include "cJSON.h"') cgen.genln('#include "cJSON.h"')
} }
} }
if v.pref.build_mode == .embed_vlib || v.pref.build_mode == .default_mode { if v.pref.build_mode == .default_mode {
//if v.pref.build_mode in [.embed_vlib, .default_mode] {
// If we declare these for all modes, then when running `v a.v` we'll get // If we declare these for all modes, then when running `v a.v` we'll get
// `/usr/bin/ld: multiple definition of 'total_m'` // `/usr/bin/ld: multiple definition of 'total_m'`
// TODO
//cgen.genln('i64 total_m = 0; // For counting total RAM allocated')
//if v.pref.is_test {
$if !js { $if !js {
cgen.genln('int g_test_oks = 0;') cgen.genln('int g_test_oks = 0;')
cgen.genln('int g_test_fails = 0;') cgen.genln('int g_test_fails = 0;')
@ -335,11 +321,14 @@ fn (v mut V) compile() {
} }
//cgen.genln('/*================================== FNS =================================*/') //cgen.genln('/*================================== FNS =================================*/')
cgen.genln('this line will be replaced with definitions') cgen.genln('this line will be replaced with definitions')
defs_pos := cgen.lines.len - 1 mut defs_pos := cgen.lines.len - 1
if defs_pos == -1 {
defs_pos = 0
}
cgen.nogen = q
for file in v.files { for file in v.files {
v.parse(file, .main) v.parse(file, .main)
//if p.pref.autofree { p.scanner.text.free() free(p.scanner) } //if p.pref.autofree { p.scanner.text.free() free(p.scanner) }
// p.g.gen_x64()
// Format all files (don't format automatically generated vlib headers) // Format all files (don't format automatically generated vlib headers)
if !v.pref.nofmt && !file.contains('/vlib/') { if !v.pref.nofmt && !file.contains('/vlib/') {
// new vfmt is not ready yet // new vfmt is not ready yet
@ -356,25 +345,25 @@ fn (v mut V) compile() {
vgen_parser.parse(.main) vgen_parser.parse(.main)
// v.parsers.add(vgen_parser) // v.parsers.add(vgen_parser)
v.log('Done parsing.') v.log('Done parsing.')
// Write everything // All definitions
mut d := strings.new_builder(10000)// Avoid unnecessary allocations mut def := strings.new_builder(10000)// Avoid unnecessary allocations
$if !js { $if !js {
d.writeln(cgen.includes.join_lines()) def.writeln(cgen.includes.join_lines())
d.writeln(cgen.typedefs.join_lines()) def.writeln(cgen.typedefs.join_lines())
d.writeln(v.type_definitions()) def.writeln(v.type_definitions())
d.writeln('\nstring _STR(const char*, ...);\n') def.writeln('\nstring _STR(const char*, ...);\n')
d.writeln('\nstring _STR_TMP(const char*, ...);\n') def.writeln('\nstring _STR_TMP(const char*, ...);\n')
d.writeln(cgen.fns.join_lines()) // fn definitions def.writeln(cgen.fns.join_lines()) // fn definitions
} $else { } $else {
d.writeln(v.type_definitions()) def.writeln(v.type_definitions())
} }
d.writeln(cgen.consts.join_lines()) def.writeln(cgen.consts.join_lines())
d.writeln(cgen.thread_args.join_lines()) def.writeln(cgen.thread_args.join_lines())
if v.pref.is_prof { if v.pref.is_prof {
d.writeln('; // Prof counters:') def.writeln('; // Prof counters:')
d.writeln(v.prof_counters()) def.writeln(v.prof_counters())
} }
cgen.lines[defs_pos] = d.str() cgen.lines[defs_pos] = def.str()
v.generate_main() v.generate_main()
v.generate_hot_reload_code() v.generate_hot_reload_code()
if v.pref.is_verbose { if v.pref.is_verbose {
@ -394,8 +383,7 @@ fn (v mut V) generate_main() {
mut cgen := v.cgen mut cgen := v.cgen
$if js { return } $if js { return }
// if v.build_mode in [.default, .embed_vlib] { if v.pref.build_mode == .default_mode {
if v.pref.build_mode == .default_mode || v.pref.build_mode == .embed_vlib {
mut consts_init_body := cgen.consts_init.join_lines() mut consts_init_body := cgen.consts_init.join_lines()
// vlib can't have `init_consts()` // vlib can't have `init_consts()`
cgen.genln('void init_consts() { cgen.genln('void init_consts() {
@ -591,8 +579,14 @@ fn (v &V) v_files_from_dir(dir string) []string {
// Parses imports, adds necessary libs, and then user files // Parses imports, adds necessary libs, and then user files
fn (v mut V) add_v_files_to_compile() { fn (v mut V) add_v_files_to_compile() {
mut builtin_files := v.get_builtin_files()
// Builtin cache exists? Use it.
builtin_vh := '$v_modules_path/builtin.vh'
if v.pref.is_debug && os.file_exists(builtin_vh) {
builtin_files = [builtin_vh]
}
// Parse builtin imports // Parse builtin imports
for file in v.get_builtin_files() { for file in builtin_files {
// add builtins first // add builtins first
v.files << file v.files << file
mut p := v.new_parser_from_file(file) mut p := v.new_parser_from_file(file)
@ -613,19 +607,25 @@ fn (v mut V) add_v_files_to_compile() {
v.log('imports:') v.log('imports:')
println(v.table.imports) println(v.table.imports)
} }
// resolve deps & add imports in correct order // resolve deps and add imports in correct order
for mod in v.resolve_deps().imports() { imported_mods := v.resolve_deps().imports()
// if mod == v.mod { continue } // Building this module? Skip. TODO it's a hack. for mod in imported_mods {
if mod == 'builtin' { continue } // builtin already added if mod == 'builtin' || mod == 'main' {
if mod == 'main' { continue } // main files will get added last // builtin already added
// main files will get added last
continue
}
// use cached built module if exists // use cached built module if exists
// vh_path := '$v_modules_path/${mod}.vh' if v.pref.build_mode != .build_module {
// if os.file_exists(vh_path) { vh_path := '$v_modules_path/${mod}.vh'
// println('using cached module `$mod`: $vh_path') //println(vh_path)
// v.files << vh_path if v.pref.is_debug && os.file_exists(vh_path) {
// continue println('using cached module `$mod`: $vh_path')
// } v.files << vh_path
continue
}
}
// standard module // standard module
mod_path := v.find_module_path(mod) or { verror(err) break } mod_path := v.find_module_path(mod) or { verror(err) break }
vfiles := v.v_files_from_dir(mod_path) vfiles := v.v_files_from_dir(mod_path)
@ -640,8 +640,9 @@ fn (v mut V) add_v_files_to_compile() {
} }
} }
// get builtin files
fn (v &V) get_builtin_files() []string { fn (v &V) get_builtin_files() []string {
// .vh cache exists? Use it
$if js { $if js {
return v.v_files_from_dir('$v.vroot${os.PathSeparator}vlib${os.PathSeparator}builtin${os.PathSeparator}js') return v.v_files_from_dir('$v.vroot${os.PathSeparator}vlib${os.PathSeparator}builtin${os.PathSeparator}js')
} }
@ -812,11 +813,6 @@ fn new_v(args[]string) &V {
} }
*/ */
} }
// TODO embed_vlib is temporarily the default mode. It's much slower.
else if !('-embed_vlib' in args) {
build_mode = .embed_vlib
}
//
is_test := dir.ends_with('_test.v') is_test := dir.ends_with('_test.v')
is_script := dir.ends_with('.v') is_script := dir.ends_with('.v')
if is_script && !os.file_exists(dir) { if is_script && !os.file_exists(dir) {

View File

@ -9,9 +9,10 @@ import (
os os
) )
/* .vh generation logic. /*
.vh files contains only function signatures, consts, and types. .vh generation logic.
They are used together with pre-compiled modules. .vh files contains only function signatures, consts, and types.
They are used together with pre-compiled modules.
*/ */
// "fn foo(a int) string" // "fn foo(a int) string"
@ -27,7 +28,7 @@ fn (f &Fn) v_definition() string {
} }
if f.is_method { if f.is_method {
recv := f.args[0] recv := f.args[0]
typ := v_type_str(recv.typ) typ := v_type_str(recv.typ).replace('*', '')
mut mu := if recv.is_mut { 'mut' } else { '' } mut mu := if recv.is_mut { 'mut' } else { '' }
if recv.ref { if recv.ref {
mu = '&' mu = '&'
@ -40,6 +41,9 @@ fn (f &Fn) v_definition() string {
sb.write('$f.name(') sb.write('$f.name(')
} }
for i, arg in f.args { for i, arg in f.args {
if i == 0 && f.is_method { // skip the receiver
continue
}
typ := v_type_str(arg.typ) typ := v_type_str(arg.typ)
if arg.name == '' { if arg.name == '' {
sb.write(typ) sb.write(typ)
@ -62,11 +66,12 @@ fn (f &Fn) v_definition() string {
} }
fn v_type_str(typ_ string) string { fn v_type_str(typ_ string) string {
typ := if typ_.ends_with('*') { mut typ := if typ_.ends_with('*') {
'*' + typ_.left(typ_.len - 1) '*' + typ_.left(typ_.len - 1)
} else { } else {
typ_ typ_
} }
typ = typ.replace('Option_', '?')
//println('"$typ"') //println('"$typ"')
if typ == '*void' { if typ == '*void' {
return 'voidptr' return 'voidptr'
@ -80,11 +85,11 @@ fn v_type_str(typ_ string) string {
if typ.contains('__') { if typ.contains('__') {
return typ.all_after('__') return typ.all_after('__')
} }
return typ.replace('Option_', '?') return typ
} }
fn (v &V) generate_vh() { fn (v &V) generate_vh() {
println('Generating a V header file for module `$v.mod`') println('\n\n\n\nGenerating a V header file for module `$v.mod`')
dir := '$v_modules_path${os.PathSeparator}$v.mod' dir := '$v_modules_path${os.PathSeparator}$v.mod'
path := dir + '.vh' path := dir + '.vh'
if !os.dir_exists(dir) { if !os.dir_exists(dir) {
@ -95,6 +100,7 @@ fn (v &V) generate_vh() {
file := os.create(path) or { panic(err) } file := os.create(path) or { panic(err) }
// Consts // Consts
file.writeln('// $v.mod module header \n') file.writeln('// $v.mod module header \n')
file.writeln('module $v.mod')
file.writeln('// Consts') file.writeln('// Consts')
if v.table.consts.len > 0 { if v.table.consts.len > 0 {
file.writeln('const (') file.writeln('const (')
@ -126,16 +132,20 @@ fn (v &V) generate_vh() {
file.writeln('\n') file.writeln('\n')
} }
// Types // Types
file.writeln('// Types') file.writeln('// Types2')
for _, typ in v.table.typesmap { for _, typ in v.table.typesmap {
if typ.mod != v.mod { //println(typ.name)
if typ.mod != v.mod && typ.mod != ''{ // int, string etc mod == ''
//println('skipping type "$typ.name"')
continue continue
} }
mut name := typ.name
if typ.name.contains('__') { if typ.name.contains('__') {
continue name = typ.name.all_after('__')
} }
if typ.cat == .struct_ { if typ.cat in [TypeCategory.struct_, .c_struct] {
file.writeln('struct $typ.name {') c := if typ.is_c { 'C.' } else { '' }
file.writeln('struct ${c}$name {')
// Private fields // Private fields
for field in typ.fields { for field in typ.fields {
if field.access_mod == .public { if field.access_mod == .public {
@ -144,13 +154,18 @@ fn (v &V) generate_vh() {
field_type := v_type_str(field.typ) field_type := v_type_str(field.typ)
file.writeln('\t$field.name $field_type') file.writeln('\t$field.name $field_type')
} }
file.writeln('pub:') //file.writeln('pub:')
mut public_str := ''
for field in typ.fields { for field in typ.fields {
if field.access_mod == .private { if field.access_mod == .private {
continue continue
} }
field_type := v_type_str(field.typ) field_type := v_type_str(field.typ)
file.writeln('\t$field.name $field_type') public_str += '\t$field.name $field_type\n'
//file.writeln('\t$field.name $field_type')
}
if public_str != '' {
file.writeln('pub:' + public_str)
} }
file.writeln('}\n') file.writeln('}\n')
} }
@ -161,8 +176,10 @@ fn (v &V) generate_vh() {
mut fns := []Fn mut fns := []Fn
// TODO fns := v.table.fns.filter(.mod == v.mod) // TODO fns := v.table.fns.filter(.mod == v.mod)
for _, f in v.table.fns { for _, f in v.table.fns {
if f.mod == v.mod { if f.mod == v.mod || f.mod == ''{
fns << f fns << f
} else {
println('skipping fn $f.name mod=$f.mod')
} }
} }
for _, f in fns { for _, f in fns {
@ -181,7 +198,8 @@ fn (v &V) generate_vh() {
// Methods // Methods
file.writeln('\n// Methods //////////////////') file.writeln('\n// Methods //////////////////')
for _, typ in v.table.typesmap { for _, typ in v.table.typesmap {
if typ.mod != v.mod { if typ.mod != v.mod { //&& typ.mod != '' {
println('skipping method typ $typ.name mod=$typ.mod')
continue continue
} }
for method in typ.methods { for method in typ.methods {

View File

@ -253,9 +253,6 @@ pub fn (v mut V) cc_msvc() {
mut alibs := []string // builtin.o os.o http.o etc mut alibs := []string // builtin.o os.o http.o etc
if v.pref.build_mode == .build_module { if v.pref.build_mode == .build_module {
} }
else if v.pref.build_mode == .embed_vlib {
//
}
else if v.pref.build_mode == .default_mode { else if v.pref.build_mode == .default_mode {
b := os.realpath( '$v_modules_path/vlib/builtin.obj' ) b := os.realpath( '$v_modules_path/vlib/builtin.obj' )
alibs << '"$b"' alibs << '"$b"'

View File

@ -51,7 +51,6 @@ mut:
tmp_cnt int tmp_cnt int
is_script bool is_script bool
builtin_mod bool builtin_mod bool
vh_lines []string
inside_if_expr bool inside_if_expr bool
inside_unwrapping_match_statement bool inside_unwrapping_match_statement bool
inside_return_expr bool inside_return_expr bool
@ -73,7 +72,7 @@ mut:
v_script bool // "V bash", import all os functions into global space v_script bool // "V bash", import all os functions into global space
var_decl_name string // To allow declaring the variable so that it can be used in the struct initialization var_decl_name string // To allow declaring the variable so that it can be used in the struct initialization
is_alloc bool // Whether current expression resulted in an allocation is_alloc bool // Whether current expression resulted in an allocation
is_const_literal bool // `1`, `2.0` etc, so that `u64 == 0` works is_const_literal bool // `1`, `2.0` etc, so that `u64_var == 0` works
cur_gen_type string // "App" to replace "T" in current generic function cur_gen_type string // "App" to replace "T" in current generic function
is_vweb bool is_vweb bool
is_sql bool is_sql bool
@ -81,6 +80,7 @@ mut:
sql_i int // $1 $2 $3 sql_i int // $1 $2 $3
sql_params []string // ("select * from users where id = $1", ***"100"***) sql_params []string // ("select * from users where id = $1", ***"100"***)
sql_types []string // int, string and so on; see sql_params sql_types []string // int, string and so on; see sql_params
is_vh bool // parsing .vh file (for example `const (a int)` is allowed)
} }
const ( const (
@ -100,7 +100,6 @@ fn (v mut V) new_parser_from_string(text string, id string) Parser {
return p return p
} }
// new parser from file.
fn (v mut V) new_parser_from_file(path string) Parser { fn (v mut V) new_parser_from_file(path string) Parser {
//println('new_parser("$path")') //println('new_parser("$path")')
mut path_pcguard := '' mut path_pcguard := ''
@ -119,7 +118,8 @@ fn (v mut V) new_parser_from_file(path string) Parser {
file_name: path.all_after(os.PathSeparator), file_name: path.all_after(os.PathSeparator),
file_platform: path_platform, file_platform: path_platform,
file_pcguard: path_pcguard, file_pcguard: path_pcguard,
is_script: (v.pref.is_script && os.realpath(path) == os.realpath(path)) is_script: (v.pref.is_script && os.realpath(path) == os.realpath(path)),
is_vh: path.ends_with('.vh')
} }
if p.pref.building_v { if p.pref.building_v {
p.scanner.should_print_relative_paths_on_error = false p.scanner.should_print_relative_paths_on_error = false
@ -249,6 +249,14 @@ fn (p mut Parser) parse(pass Pass) {
p.fspace() p.fspace()
p.mod = p.check_name() p.mod = p.check_name()
} }
//
p.cgen.nogen = false
if p.pref.build_mode == .build_module && p.mod != p.v.mod {
//println('skipping $p.mod (v.mod = $p.v.mod)')
p.cgen.nogen = true
//defer { p.cgen.nogen = false }
}
p.fgenln('\n') p.fgenln('\n')
p.builtin_mod = p.mod == 'builtin' p.builtin_mod = p.mod == 'builtin'
p.can_chash = p.mod=='ui' || p.mod == 'darwin'// TODO tmp remove p.can_chash = p.mod=='ui' || p.mod == 'darwin'// TODO tmp remove
@ -343,16 +351,15 @@ fn (p mut Parser) parse(pass Pass) {
mut g := p.table.cgen_name_type_pair(name, typ) mut g := p.table.cgen_name_type_pair(name, typ)
if p.tok == .assign { if p.tok == .assign {
p.next() p.next()
// p.gen(' = ')
g += ' = ' g += ' = '
p.cgen.start_tmp() _, expr := p.tmp_expr()
p.bool_expression() g += expr
// g += '<<< ' + p.cgen.end_tmp() + '>>>'
g += p.cgen.end_tmp()
} }
// p.genln('; // global') // p.genln('; // global')
g += '; // global' g += '; // global'
p.cgen.consts << g if !p.cgen.nogen {
p.cgen.consts << g
}
case TokenKind.eof: case TokenKind.eof:
//p.log('end of parse()') //p.log('end of parse()')
// TODO: check why this was added? everything seems to work // TODO: check why this was added? everything seems to work
@ -484,27 +491,36 @@ fn (p mut Parser) const_decl() {
p.fgenln('') p.fgenln('')
p.fmt_inc() p.fmt_inc()
for p.tok == .name { for p.tok == .name {
if p.lit == '_' && p.peek() == .assign { if p.lit == '_' && p.peek() == .assign && !p.cgen.nogen {
p.gen_blank_identifier_assign() p.gen_blank_identifier_assign()
//if !p.cgen.nogen {
p.cgen.consts_init << p.cgen.cur_line.trim_space() p.cgen.consts_init << p.cgen.cur_line.trim_space()
p.cgen.resetln('') p.cgen.resetln('')
//}
continue continue
} }
// `Age = 20` mut name := p.check_name() // `Age = 20`
mut name := p.check_name()
//if ! (name[0] >= `A` && name[0] <= `Z`) { //if ! (name[0] >= `A` && name[0] <= `Z`) {
//p.error('const name must be capitalized') //p.error('const name must be capitalized')
//} //}
name = p.prepend_mod(name) name = p.prepend_mod(name)
p.check_space(.assign) mut typ := ''
typ := p.expression() if p.is_vh {
// .vh files don't have const values, just types: `const (a int)`
typ = p.get_type()
p.table.register_const(name, typ, p.mod)
continue // Don't generate C code when building a .vh file
} else {
p.check_space(.assign)
typ = p.expression()
}
if p.first_pass() && p.table.known_const(name) { if p.first_pass() && p.table.known_const(name) {
p.error('redefinition of `$name`') p.error('redefinition of `$name`')
} }
if p.first_pass() { if p.first_pass() {
p.table.register_const(name, typ, p.mod) p.table.register_const(name, typ, p.mod)
} }
if p.pass == .main { if p.pass == .main && !p.cgen.nogen {
// TODO hack // TODO hack
// cur_line has const's value right now. if it's just a number, then optimize generation: // cur_line has const's value right now. if it's just a number, then optimize generation:
// output a #define so that we don't pollute the binary with unnecessary global vars // output a #define so that we don't pollute the binary with unnecessary global vars
@ -1219,11 +1235,6 @@ fn (p mut Parser) gen(s string) {
} }
// Generate V header from V source // Generate V header from V source
fn (p mut Parser) vh_genln(s string) {
//println('vh $s')
p.vh_lines << s
}
fn (p mut Parser) statement(add_semi bool) string { fn (p mut Parser) statement(add_semi bool) string {
if p.returns && !p.is_vweb { if p.returns && !p.is_vweb {
p.error('unreachable code') p.error('unreachable code')
@ -2806,7 +2817,7 @@ fn (p mut Parser) string_expr() {
p.gen('"$f"') p.gen('"$f"')
} }
else { else {
p.gen('tos2((byte*)"$f")') p.gen('tos3("$f")')
} }
p.next() p.next()
return return

View File

@ -70,8 +70,4 @@ Options/commands:
/* /*
- To disable automatic formatting: - To disable automatic formatting:
v -nofmt file.v v -nofmt file.v
- To build a program with an embedded vlib (use this if you do not have prebuilt vlib libraries or if you
are working on vlib)
v -embed_vlib file.v
*/ */

32
vlib/os2/os2_mac.v Normal file
View File

@ -0,0 +1,32 @@
module os2
#include <fcntl.h>
struct File {
fd int
}
fn C.open(byteptr, int, int) int
fn C.write(voidptr, byteptr, int) int
pub fn create(path string) ?File {
fd := C.creat(path.str, 0644)//511)
if fd == -1 {
return error('failed to create "$path":')
//os.print_c_errno()
}
return File{fd}
}
pub fn (f File) writeln(s string) {
ss := s + '\n'
ret := C.write(f.fd, ss.str, s.len + 1)
if ret == -1 {
C.perror('failed to write')
}
}
pub fn (f File) close() {
C.close(f.fd)
}

9
vlib/os2/os2_test.v Normal file
View File

@ -0,0 +1,9 @@
import os2
fn test_open() {
$if mac {
f := os2.create('os2.test')
f.writeln('hello world!')
f.close()
}
}

View File

@ -45,7 +45,8 @@ pub fn dice_coefficient(s1, s2 string) f32 {
mut first_bigrams := map[string]int mut first_bigrams := map[string]int
for i := 0; i < a.len-1; i++ { for i := 0; i < a.len-1; i++ {
bigram := a.substr(i, i+2) bigram := a.substr(i, i+2)
first_bigrams[bigram] = if bigram in first_bigrams { first_bigrams[bigram]+1 } else { 1 } q := if bigram in first_bigrams { first_bigrams[bigram]+1 } else { 1 }
first_bigrams[bigram] = q
} }
mut intersection_size := 0 mut intersection_size := 0
for i := 0; i < b.len-1; i++ { for i := 0; i < b.len-1; i++ {

View File

@ -29,6 +29,8 @@ fn C.localtime(int) &C.tm
fn remove_me_when_c_bug_is_fixed() { // TODO fn remove_me_when_c_bug_is_fixed() { // TODO
} }
struct C.time_t {}
struct C.tm { struct C.tm {
tm_year int tm_year int
tm_mon int tm_mon int