caching modules: almost there

pull/2267/head
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
}
mut libs := ''// builtin.o os.o http.o etc
libs := ''// builtin.o os.o http.o etc
if v.pref.build_mode == .build_module {
a << '-c'
}
else if v.pref.build_mode == .embed_vlib {
//
}
else if v.pref.build_mode == .default_mode {
/*
// TODO
libs = '$v_modules_path/vlib/builtin.o'
if !os.file_exists(libs) {
println('object file `$libs` not found')
@ -125,6 +124,7 @@ fn (v mut V) cc() {
}
libs += ' "$v_modules_path/vlib/${imp}.o"'
}
*/
}
if v.pref.sanitize {
a << '-fsanitize=leak'
@ -248,8 +248,8 @@ fn (v mut V) cc() {
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' {
os.rm(v.out_name_c)
if !v.pref.is_debug && v.out_name_c != 'v.c' {
//os.rm(v.out_name_c)
}
if v.pref.compress {
$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) {
if g.nogen {
return
}
prev := g.lines[g.lines.len - 1]
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
}
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
}
//////////////////////////////////////////////////

View File

@ -144,9 +144,8 @@ fn (p mut Parser) comp_time() {
// #include, #flag, #v
fn (p mut Parser) chash() {
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()
is_sig := p.is_sig()
if hash.starts_with('flag ') {
mut flag := hash.right(5)
// expand `@VROOT` `@VMOD` to absolute path
@ -157,7 +156,7 @@ fn (p mut Parser) chash() {
return
}
if hash.starts_with('include') {
if p.first_pass() && !is_sig {
if p.first_pass() && !p.is_vh {
if p.file_pcguard.len != 0 {
//println('p: $p.file_platform $p.file_pcguard')
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.
fn (p mut Parser) fn_decl() {
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))
is_c := f.name == 'C' && p.tok == .dot
// Just fn signature? only builtin.v + default build mode
// is_sig := p.builtin_mod && p.pref.build_mode == default_mode
// is_sig := p.pref.build_mode == default_mode && (p.builtin_mod || p.file.contains(LANG_TMP))
is_sig := p.is_sig()
// println('\n\nfn_decl() name=$f.name receiver_typ=$receiver_typ')
if p.pref.build_mode == .build_module {
println('\n\nfn_decl() name=$f.name receiver_typ=$receiver_typ nogen=$p.cgen.nogen')
}
if is_c {
p.check(.dot)
f.name = p.check_name()
@ -312,13 +305,15 @@ fn (p mut Parser) fn_decl() {
}
p.cgen.typedefs << 'typedef struct $typ $typ;'
}
// Translated C code can have empty functions (just definitions)
is_fn_header := !is_c && !is_sig && (p.pref.translated || p.pref.is_test) && p.tok != .lcbr
// Translated C code and .vh can have empty functions (just definitions)
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 {
f.is_decl = true
}
// { 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.check(.lcbr)
}
@ -350,7 +345,7 @@ fn (p mut Parser) fn_decl() {
mut fn_name_cgen := p.table.fn_gen_name(f)
// Start generation of the function body
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 {
p.genln('; // $f.name')
}
@ -403,10 +398,10 @@ fn (p mut Parser) fn_decl() {
// println('register_fn typ=$typ isg=$is_generic')
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
// Look for generic calls.
if !is_sig && !is_fn_header {
if !p.is_vh && !is_fn_header {
p.skip_fn_body()
}
// Live code reloading? Load all fns from .so
@ -422,19 +417,8 @@ fn (p mut Parser) fn_decl() {
}
// Add function definition to the top
if !is_c && p.first_pass() {
// TODO hack to make Volt compile without -embed_vlib
if f.name == 'darwin__nsstring' && p.pref.build_mode == .default_mode {
} else {
p.cgen.fns << fn_decl + ';'
}
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
}
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')
if is_c || is_sig || is_fn_header {
// println('IS SIG .key_returnING tok=${p.strtok()}')
if is_c || p.is_vh || is_fn_header {
return
}
// 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.statements_no_rcbr()
p.cgen.nogen = false
//p.cgen.nogen = false
// Print counting result after all statements in main
if p.pref.is_prof && f.name == 'main' {
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 {
p.gen('$tmp')
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 {
if p.pref.translated && !p.builtin_mod {
@ -214,18 +215,18 @@ fn (table mut Table) fn_gen_name(f &Fn) string {
// Obfuscate but skip certain names
// TODO ugly, fix
// NB: the order here is from faster to potentially slower checks
if table.obfuscate &&
if table.obfuscate &&
!f.is_c &&
f.name != 'main' && f.name != 'WinMain' && f.name != 'main__main' &&
f.name != 'main' && f.name != 'WinMain' && f.name != 'main__main' &&
f.name != 'gg__vec2' &&
f.name != 'build_token_str' &&
f.name != 'build_keys' &&
f.mod != 'builtin' &&
f.mod != 'darwin' &&
f.mod != 'os' &&
f.name != 'build_token_str' &&
f.name != 'build_keys' &&
f.mod != 'builtin' &&
f.mod != 'darwin' &&
f.mod != 'os' &&
f.mod != 'json' &&
!f.name.contains('window_proc') &&
!name.ends_with('_str') &&
!f.name.contains('window_proc') &&
!name.ends_with('_str') &&
!name.contains('contains') {
mut idx := table.obf_ids[name]
// No such function yet, register it

View File

@ -18,9 +18,6 @@ enum BuildMode {
// `v program.v'
// Build user code only, and add pre-compiled vlib (`cc program.o builtin.o os.o...`)
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`
// build any module (generate os.o + os.vh)
build_module
@ -290,36 +287,25 @@ fn (v mut V) compile() {
cgen.genln('#define V_COMMIT_HASH "' + vhash() + '"')
cgen.genln('#endif')
}
q := cgen.nogen // TODO hack
cgen.nogen = false
$if js {
cgen.genln(js_headers)
} $else {
cgen.genln(CommonCHeaders)
}
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
// default mode
imports_json := 'json' in v.table.imports
if v.pref.build_mode == .default_mode {
if imports_json {
cgen.genln('#include "cJSON.h"')
}
}
if v.pref.build_mode == .embed_vlib || v.pref.build_mode == .default_mode {
//if v.pref.build_mode in [.embed_vlib, .default_mode] {
if v.pref.build_mode == .default_mode {
// If we declare these for all modes, then when running `v a.v` we'll get
// `/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 {
cgen.genln('int g_test_oks = 0;')
cgen.genln('int g_test_fails = 0;')
@ -335,11 +321,14 @@ fn (v mut V) compile() {
}
//cgen.genln('/*================================== FNS =================================*/')
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 {
v.parse(file, .main)
//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)
if !v.pref.nofmt && !file.contains('/vlib/') {
// new vfmt is not ready yet
@ -356,25 +345,25 @@ fn (v mut V) compile() {
vgen_parser.parse(.main)
// v.parsers.add(vgen_parser)
v.log('Done parsing.')
// Write everything
mut d := strings.new_builder(10000)// Avoid unnecessary allocations
// All definitions
mut def := strings.new_builder(10000)// Avoid unnecessary allocations
$if !js {
d.writeln(cgen.includes.join_lines())
d.writeln(cgen.typedefs.join_lines())
d.writeln(v.type_definitions())
d.writeln('\nstring _STR(const char*, ...);\n')
d.writeln('\nstring _STR_TMP(const char*, ...);\n')
d.writeln(cgen.fns.join_lines()) // fn definitions
def.writeln(cgen.includes.join_lines())
def.writeln(cgen.typedefs.join_lines())
def.writeln(v.type_definitions())
def.writeln('\nstring _STR(const char*, ...);\n')
def.writeln('\nstring _STR_TMP(const char*, ...);\n')
def.writeln(cgen.fns.join_lines()) // fn definitions
} $else {
d.writeln(v.type_definitions())
def.writeln(v.type_definitions())
}
d.writeln(cgen.consts.join_lines())
d.writeln(cgen.thread_args.join_lines())
def.writeln(cgen.consts.join_lines())
def.writeln(cgen.thread_args.join_lines())
if v.pref.is_prof {
d.writeln('; // Prof counters:')
d.writeln(v.prof_counters())
def.writeln('; // Prof counters:')
def.writeln(v.prof_counters())
}
cgen.lines[defs_pos] = d.str()
cgen.lines[defs_pos] = def.str()
v.generate_main()
v.generate_hot_reload_code()
if v.pref.is_verbose {
@ -394,8 +383,7 @@ fn (v mut V) generate_main() {
mut cgen := v.cgen
$if js { return }
// if v.build_mode in [.default, .embed_vlib] {
if v.pref.build_mode == .default_mode || v.pref.build_mode == .embed_vlib {
if v.pref.build_mode == .default_mode {
mut consts_init_body := cgen.consts_init.join_lines()
// vlib can't have `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
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
for file in v.get_builtin_files() {
for file in builtin_files {
// add builtins first
v.files << 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:')
println(v.table.imports)
}
// resolve deps & add imports in correct order
for mod in v.resolve_deps().imports() {
// if mod == v.mod { continue } // Building this module? Skip. TODO it's a hack.
if mod == 'builtin' { continue } // builtin already added
if mod == 'main' { continue } // main files will get added last
// resolve deps and add imports in correct order
imported_mods := v.resolve_deps().imports()
for mod in imported_mods {
if mod == 'builtin' || mod == 'main' {
// builtin already added
// main files will get added last
continue
}
// use cached built module if exists
// vh_path := '$v_modules_path/${mod}.vh'
// if os.file_exists(vh_path) {
// println('using cached module `$mod`: $vh_path')
// v.files << vh_path
// continue
// }
if v.pref.build_mode != .build_module {
vh_path := '$v_modules_path/${mod}.vh'
//println(vh_path)
if v.pref.is_debug && os.file_exists(vh_path) {
println('using cached module `$mod`: $vh_path')
v.files << vh_path
continue
}
}
// standard module
mod_path := v.find_module_path(mod) or { verror(err) break }
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 {
// .vh cache exists? Use it
$if 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_script := dir.ends_with('.v')
if is_script && !os.file_exists(dir) {

View File

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

View File

@ -29,7 +29,7 @@ const (
KEY_ENUMERATE_SUB_KEYS = (0x0008)
)
// Given a root key look for one of the subkeys in 'versions' and get the path
// Given a root key look for one of the subkeys in 'versions' and get the path
fn find_windows_kit_internal(key RegKey, versions []string) ?string {
$if windows {
for version in versions {
@ -139,7 +139,7 @@ fn find_vs() ?VsInstallation {
}
// Emily:
// VSWhere is guaranteed to be installed at this location now
// If its not there then end user needs to update their visual studio
// If its not there then end user needs to update their visual studio
// installation!
res := os.exec('""%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath"') or {
return error(err)
@ -207,7 +207,7 @@ fn find_msvc() ?MsvcResult {
}
}
pub fn (v mut V) cc_msvc() {
pub fn (v mut V) cc_msvc() {
r := find_msvc() or {
// TODO: code reuse
if !v.pref.is_debug && v.out_name_c != 'v.c' && v.out_name_c != 'v_macos.c' {
@ -253,9 +253,6 @@ pub fn (v mut V) cc_msvc() {
mut alibs := []string // builtin.o os.o http.o etc
if v.pref.build_mode == .build_module {
}
else if v.pref.build_mode == .embed_vlib {
//
}
else if v.pref.build_mode == .default_mode {
b := os.realpath( '$v_modules_path/vlib/builtin.obj' )
alibs << '"$b"'
@ -334,8 +331,8 @@ pub fn (v mut V) cc_msvc() {
args := a.join(' ')
cmd := '""$r.full_cl_exe_path" $args"'
// It is hard to see it at first, but the quotes above ARE balanced :-| ...
cmd := '""$r.full_cl_exe_path" $args"'
// It is hard to see it at first, but the quotes above ARE balanced :-| ...
// Also the double quotes at the start ARE needed.
if v.pref.show_c_cmd || v.pref.is_verbose {
println('\n========== cl cmd line:')
@ -376,16 +373,16 @@ fn build_thirdparty_obj_file_with_msvc(path string, moduleflags []CFlag) {
if os.file_exists(obj_path) {
println('$obj_path already build.')
return
}
return
}
println('$obj_path not found, building it (with msvc)...')
println('$obj_path not found, building it (with msvc)...')
parent := os.dir(obj_path)
files := os.ls(parent)
mut cfiles := ''
mut cfiles := ''
for file in files {
if file.ends_with('.c') {
if file.ends_with('.c') {
cfiles += '"' + os.realpath( parent + os.PathSeparator + file ) + '" '
}
}

View File

@ -51,7 +51,6 @@ mut:
tmp_cnt int
is_script bool
builtin_mod bool
vh_lines []string
inside_if_expr bool
inside_unwrapping_match_statement bool
inside_return_expr bool
@ -73,7 +72,7 @@ mut:
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
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
is_vweb bool
is_sql bool
@ -81,6 +80,7 @@ mut:
sql_i int // $1 $2 $3
sql_params []string // ("select * from users where id = $1", ***"100"***)
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 (
@ -100,7 +100,6 @@ fn (v mut V) new_parser_from_string(text string, id string) Parser {
return p
}
// new parser from file.
fn (v mut V) new_parser_from_file(path string) Parser {
//println('new_parser("$path")')
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_platform: path_platform,
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 {
p.scanner.should_print_relative_paths_on_error = false
@ -249,6 +249,14 @@ fn (p mut Parser) parse(pass Pass) {
p.fspace()
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.builtin_mod = p.mod == 'builtin'
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)
if p.tok == .assign {
p.next()
// p.gen(' = ')
g += ' = '
p.cgen.start_tmp()
p.bool_expression()
// g += '<<< ' + p.cgen.end_tmp() + '>>>'
g += p.cgen.end_tmp()
_, expr := p.tmp_expr()
g += expr
}
// p.genln('; // global')
g += '; // global'
p.cgen.consts << g
if !p.cgen.nogen {
p.cgen.consts << g
}
case TokenKind.eof:
//p.log('end of parse()')
// TODO: check why this was added? everything seems to work
@ -484,27 +491,36 @@ fn (p mut Parser) const_decl() {
p.fgenln('')
p.fmt_inc()
for p.tok == .name {
if p.lit == '_' && p.peek() == .assign {
if p.lit == '_' && p.peek() == .assign && !p.cgen.nogen {
p.gen_blank_identifier_assign()
//if !p.cgen.nogen {
p.cgen.consts_init << p.cgen.cur_line.trim_space()
p.cgen.resetln('')
//}
continue
}
// `Age = 20`
mut name := p.check_name()
mut name := p.check_name() // `Age = 20`
//if ! (name[0] >= `A` && name[0] <= `Z`) {
//p.error('const name must be capitalized')
//}
name = p.prepend_mod(name)
p.check_space(.assign)
typ := p.expression()
mut typ := ''
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) {
p.error('redefinition of `$name`')
}
if p.first_pass() {
p.table.register_const(name, typ, p.mod)
}
if p.pass == .main {
if p.pass == .main && !p.cgen.nogen {
// TODO hack
// 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
@ -1219,11 +1235,6 @@ fn (p mut Parser) gen(s string) {
}
// 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 {
if p.returns && !p.is_vweb {
p.error('unreachable code')
@ -2806,7 +2817,7 @@ fn (p mut Parser) string_expr() {
p.gen('"$f"')
}
else {
p.gen('tos2((byte*)"$f")')
p.gen('tos3("$f")')
}
p.next()
return

View File

@ -70,8 +70,4 @@ Options/commands:
/*
- To disable automatic formatting:
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 100644
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)
}

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
for i := 0; i < a.len-1; i++ {
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
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
}
struct C.time_t {}
struct C.tm {
tm_year int
tm_mon int