fix maps; use maps for storing functions; verify struct initialization
							parent
							
								
									8e6cb1e1c2
								
							
						
					
					
						commit
						5936ab16c8
					
				|  | @ -151,10 +151,9 @@ fn (g mut CGen) register_thread_fn(wrapper_name, wrapper_text, struct_text strin | |||
| fn (c mut V) prof_counters() string { | ||||
| 	mut res := []string | ||||
| 	// Global fns
 | ||||
| 	for f in c.table.fns { | ||||
| 		res << 'double ${c.table.cgen_name(f)}_time;' | ||||
| 		// println(f.name)
 | ||||
| 	} | ||||
| 	//for f in c.table.fns {
 | ||||
| 		//res << 'double ${c.table.cgen_name(f)}_time;'
 | ||||
| 	//}
 | ||||
| 	// Methods
 | ||||
| 	for typ in c.table.types { | ||||
| 		// println('')
 | ||||
|  | @ -170,11 +169,10 @@ fn (c mut V) prof_counters() string { | |||
| fn (p mut Parser) print_prof_counters() string { | ||||
| 	mut res := []string | ||||
| 	// Global fns
 | ||||
| 	for f in p.table.fns { | ||||
| 		counter := '${p.table.cgen_name(f)}_time' | ||||
| 		res << 'if ($counter) printf("%%f : $f.name \\n", $counter);' | ||||
| 		// println(f.name)
 | ||||
| 	} | ||||
| 	//for f in p.table.fns {
 | ||||
| 		//counter := '${p.table.cgen_name(f)}_time'
 | ||||
| 		//res << 'if ($counter) printf("%%f : $f.name \\n", $counter);'
 | ||||
| 	//}
 | ||||
| 	// Methods
 | ||||
| 	for typ in p.table.types { | ||||
| 		// println('')
 | ||||
|  |  | |||
							
								
								
									
										300
									
								
								compiler/main.v
								
								
								
								
							
							
						
						
									
										300
									
								
								compiler/main.v
								
								
								
								
							|  | @ -59,26 +59,6 @@ enum Pass { | |||
| } | ||||
| */ | ||||
| 
 | ||||
| struct Preferences { | ||||
| 	mut: | ||||
| 		build_mode     BuildMode | ||||
| 		nofmt          bool // disable vfmt
 | ||||
| 		is_test        bool // `v test string_test.v`
 | ||||
| 		is_script      bool // single file mode (`v program.v`), `fn main(){}` can be skipped
 | ||||
| 		is_live        bool // for hot code reloading
 | ||||
| 		is_so          bool | ||||
| 		is_prof        bool // benchmark every function
 | ||||
| 		translated     bool // `v translate doom.v` are we running V code translated from C? allow globals, ++ expressions, etc
 | ||||
| 		is_prod        bool // use "-O2"
 | ||||
| 		is_verbose     bool // print extra information with `v.log()`
 | ||||
| 		obfuscate      bool // `v -obf program.v`, renames functions to "f_XXX"
 | ||||
| 		is_play        bool // playground mode
 | ||||
| 		is_repl        bool | ||||
| 		is_run         bool | ||||
| 		show_c_cmd     bool // `v -show_c_cmd` prints the C command to build program.v.c
 | ||||
| 		sanitize       bool // use Clang's new "-fsanitize" option
 | ||||
| } | ||||
| 
 | ||||
| struct V { | ||||
| mut: | ||||
| 	os         Os // the OS to build for
 | ||||
|  | @ -93,8 +73,27 @@ mut: | |||
| 	vroot      string | ||||
| } | ||||
| 
 | ||||
| struct Preferences { | ||||
| mut: | ||||
| 	build_mode     BuildMode | ||||
| 	nofmt          bool // disable vfmt
 | ||||
| 	is_test        bool // `v test string_test.v`
 | ||||
| 	is_script      bool // single file mode (`v program.v`), `fn main(){}` can be skipped
 | ||||
| 	is_live        bool // for hot code reloading
 | ||||
| 	is_so          bool | ||||
| 	is_prof        bool // benchmark every function
 | ||||
| 	translated     bool // `v translate doom.v` are we running V code translated from C? allow globals, ++ expressions, etc
 | ||||
| 	is_prod        bool // use "-O2"
 | ||||
| 	is_verbose     bool // print extra information with `v.log()`
 | ||||
| 	obfuscate      bool // `v -obf program.v`, renames functions to "f_XXX"
 | ||||
| 	is_play        bool // playground mode
 | ||||
| 	is_repl        bool | ||||
| 	is_run         bool | ||||
| 	show_c_cmd     bool // `v -show_c_cmd` prints the C command to build program.v.c
 | ||||
| 	sanitize       bool // use Clang's new "-fsanitize" option
 | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
| 	// There's no `flags` module yet, so args have to be parsed manually
 | ||||
| 	args := os.args | ||||
| 	// Print the version and exit.
 | ||||
| 	if '-v' in args || 'version' in args { | ||||
|  | @ -142,35 +141,35 @@ fn main() { | |||
| 		return | ||||
| 	} | ||||
| 	// Construct the V object from command line arguments
 | ||||
| 	mut c := new_v(args) | ||||
| 	if c.pref.is_verbose { | ||||
| 	mut v := new_v(args) | ||||
| 	if v.pref.is_verbose { | ||||
| 		println(args) | ||||
| 	} | ||||
| 	// Generate the docs and exit
 | ||||
| 	if args.contains('doc') { | ||||
| 		// c.gen_doc_html_for_module(args.last())
 | ||||
| 		// v.gen_doc_html_for_module(args.last())
 | ||||
| 		exit(0) | ||||
| 	} | ||||
| 	c.compile() | ||||
| 	v.compile() | ||||
| } | ||||
| 
 | ||||
| fn (c mut V) compile() { | ||||
| 	mut cgen := c.cgen | ||||
| fn (v mut V) compile() { | ||||
| 	mut cgen := v.cgen | ||||
| 	cgen.genln('// Generated by V')
 | ||||
| 	// Add user files to compile
 | ||||
| 	c.add_user_v_files() | ||||
| 	if c.pref.is_verbose { | ||||
| 	v.add_user_v_files() | ||||
| 	if v.pref.is_verbose { | ||||
| 		println('all .v files:') | ||||
| 		println(c.files) | ||||
| 		println(v.files) | ||||
| 	} | ||||
| 	// First pass (declarations)
 | ||||
| 	for file in c.files { | ||||
| 		mut p := c.new_parser(file, RUN_DECLS) | ||||
| 	for file in v.files { | ||||
| 		mut p := v.new_parser(file, RUN_DECLS) | ||||
| 		p.parse() | ||||
| 	} | ||||
| 	// Main pass
 | ||||
| 	cgen.run = RUN_MAIN | ||||
| 	if c.pref.is_play { | ||||
| 	if v.pref.is_play { | ||||
| 		cgen.genln('#define VPLAY (1) ') | ||||
| 	} | ||||
| 	cgen.genln('    | ||||
|  | @ -242,31 +241,31 @@ byteptr g_str_buf; | |||
| int load_so(byteptr); | ||||
| void reload_so(); | ||||
| void init_consts();') | ||||
| 	imports_json := c.table.imports.contains('json') | ||||
| 	imports_json := v.table.imports.contains('json') | ||||
| 	// TODO remove global UI hack
 | ||||
| 	if c.os == MAC && ((c.pref.build_mode == EMBED_VLIB && c.table.imports.contains('ui')) || | ||||
| 	(c.pref.build_mode == BUILD && c.dir.contains('/ui'))) { | ||||
| 	if v.os == MAC && ((v.pref.build_mode == EMBED_VLIB && v.table.imports.contains('ui')) || | ||||
| 	(v.pref.build_mode == BUILD && v.dir.contains('/ui'))) { | ||||
| 		cgen.genln('id defaultFont = 0; // main.v')
 | ||||
| 	} | ||||
| 	// TODO remove ugly .c include once V has its own json parser
 | ||||
| 	// Embed cjson either in embedvlib or in json.o
 | ||||
| 	if imports_json && c.pref.build_mode == EMBED_VLIB || | ||||
| 	(c.pref.build_mode == BUILD && c.out_name.contains('json.o')) { | ||||
| 	if imports_json && v.pref.build_mode == EMBED_VLIB || | ||||
| 	(v.pref.build_mode == BUILD && v.out_name.contains('json.o')) { | ||||
| 		cgen.genln('#include "cJSON.c" ') | ||||
| 	} | ||||
| 	// We need the cjson header for all the json decoding user will do in default mode
 | ||||
| 	if c.pref.build_mode == DEFAULT_MODE { | ||||
| 	if v.pref.build_mode == DEFAULT_MODE { | ||||
| 		if imports_json { | ||||
| 			cgen.genln('#include "cJSON.h"') | ||||
| 		} | ||||
| 	} | ||||
| 	if c.pref.build_mode == EMBED_VLIB || c.pref.build_mode == DEFAULT_MODE { | ||||
| 	if v.pref.build_mode == EMBED_VLIB || 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')
 | ||||
| 		cgen.genln('int g_test_ok = 1; ') | ||||
| 		if c.table.imports.contains('json') { | ||||
| 		if v.table.imports.contains('json') { | ||||
| 			cgen.genln('  | ||||
| #define js_get(object, key) cJSON_GetObjectItemCaseSensitive((object), (key)) | ||||
| ') | ||||
|  | @ -278,16 +277,16 @@ void init_consts();') | |||
| 	cgen.genln('/*================================== FNS =================================*/') | ||||
| 	cgen.genln('this line will be replaced with definitions') | ||||
| 	defs_pos := cgen.lines.len - 1 | ||||
| 	for file in c.files { | ||||
| 		mut p := c.new_parser(file, RUN_MAIN) | ||||
| 	for file in v.files { | ||||
| 		mut p := v.new_parser(file, RUN_MAIN) | ||||
| 		p.parse() | ||||
| 		// p.g.gen_x64()
 | ||||
| 		// Format all files (don't format automatically generated vlib headers)
 | ||||
| 		if !c.pref.nofmt && !file.contains('/vlib/') { | ||||
| 		if !v.pref.nofmt && !file.contains('/vlib/') { | ||||
| 			// new vfmt is not ready yet
 | ||||
| 		} | ||||
| 	} | ||||
| 	c.log('Done parsing.') | ||||
| 	v.log('Done parsing.') | ||||
| 	// Write everything
 | ||||
| 	mut d := new_string_builder(10000)// Just to avoid some unnecessary allocations
 | ||||
| 	d.writeln(cgen.includes.join_lines()) | ||||
|  | @ -298,14 +297,14 @@ void init_consts();') | |||
| 	d.writeln(cgen.fns.join_lines()) | ||||
| 	d.writeln(cgen.consts.join_lines()) | ||||
| 	d.writeln(cgen.thread_args.join_lines()) | ||||
| 	if c.pref.is_prof { | ||||
| 	if v.pref.is_prof { | ||||
| 		d.writeln('; // Prof counters:')
 | ||||
| 		d.writeln(c.prof_counters()) | ||||
| 		d.writeln(v.prof_counters()) | ||||
| 	} | ||||
| 	dd := d.str() | ||||
| 	cgen.lines.set(defs_pos, dd)// TODO `def.str()` doesn't compile
 | ||||
| 	// if c.build_mode in [.default, .embed_vlib] {
 | ||||
| 	if c.pref.build_mode == DEFAULT_MODE || c.pref.build_mode == EMBED_VLIB { | ||||
| 	// if v.build_mode in [.default, .embed_vlib] {
 | ||||
| 	if v.pref.build_mode == DEFAULT_MODE || v.pref.build_mode == EMBED_VLIB { | ||||
| 		// vlib can't have `init_consts()`
 | ||||
| 		cgen.genln('void init_consts() { g_str_buf=malloc(1000); ${cgen.consts_init.join_lines()} }') | ||||
| 		// _STR function can't be defined in vlib
 | ||||
|  | @ -345,29 +344,31 @@ string _STR_TMP(const char *fmt, ...) { | |||
| 	} | ||||
| 	// Make sure the main function exists
 | ||||
| 	// Obviously we don't need it in libraries
 | ||||
| 	if c.pref.build_mode != BUILD { | ||||
| 		if !c.table.main_exists() && !c.pref.is_test { | ||||
| 	if v.pref.build_mode != BUILD { | ||||
| 		if !v.table.main_exists() && !v.pref.is_test { | ||||
| 			// It can be skipped in single file programs
 | ||||
| 			if c.pref.is_script { | ||||
| 			if v.pref.is_script { | ||||
| 				//println('Generating main()...')
 | ||||
| 				cgen.genln('int main() { $cgen.fn_main; return 0; }') | ||||
| 			} | ||||
| 			else { | ||||
| 				println('panic: function `main` is undeclared in the main module') | ||||
| 				exit(1)  | ||||
| 			} | ||||
| 		} | ||||
| 		// Generate `main` which calls every single test function
 | ||||
| 		else if c.pref.is_test { | ||||
| 		else if v.pref.is_test { | ||||
| 			cgen.genln('int main() { init_consts();') | ||||
| 			for v in c.table.fns { | ||||
| 				if v.name.starts_with('test_') { | ||||
| 					cgen.genln('$v.name();') | ||||
| 			for entry in v.table.fns.entries {  | ||||
| 				f := v.table.fns[entry.key]  | ||||
| 				if f.name.starts_with('test_') { | ||||
| 					cgen.genln('$f.name();') | ||||
| 				} | ||||
| 			} | ||||
| 			cgen.genln('return g_test_ok == 0; }') | ||||
| 		} | ||||
| 	} | ||||
| 	if c.pref.is_live { | ||||
| 	if v.pref.is_live { | ||||
| 		cgen.genln(' int load_so(byteptr path) { | ||||
| 	 printf("load_so %s\\n", path); dlclose(live_lib); live_lib = dlopen(path, RTLD_LAZY); | ||||
| 	 if (!live_lib) {puts("open failed"); exit(1); return 0;} | ||||
|  | @ -378,70 +379,71 @@ string _STR_TMP(const char *fmt, ...) { | |||
| 		cgen.genln('return 1; }') | ||||
| 	} | ||||
| 	cgen.save() | ||||
| 	if c.pref.is_verbose { | ||||
| 		c.log('flags=') | ||||
| 		println(c.table.flags) | ||||
| 	if v.pref.is_verbose { | ||||
| 		v.log('flags=') | ||||
| 		println(v.table.flags) | ||||
| 	} | ||||
| 	c.cc() | ||||
| 	if c.pref.is_test || c.pref.is_run { | ||||
| 		if true || c.pref.is_verbose { | ||||
| 			println('============ running $c.out_name ============')  | ||||
| 	v.cc() | ||||
| 	if v.pref.is_test || v.pref.is_run { | ||||
| 		if true || v.pref.is_verbose { | ||||
| 			println('============ running $v.out_name ============')  | ||||
| 		} | ||||
| 		mut cmd := if c.out_name.starts_with('/') { | ||||
| 			c.out_name | ||||
| 		mut cmd := if v.out_name.starts_with('/') { | ||||
| 			v.out_name | ||||
| 		} | ||||
| 		else { | ||||
| 			'./' + c.out_name | ||||
| 			'./' + v.out_name | ||||
| 		} | ||||
| 		$if windows { | ||||
| 			cmd = c.out_name  | ||||
| 			cmd = v.out_name  | ||||
| 		}  | ||||
| 		if os.args.len > 3 { | ||||
| 			cmd += ' ' + os.args.right(3).join(' ') | ||||
| 		} | ||||
| 		ret := os.system(cmd) | ||||
| 		if ret != 0 { | ||||
| 			s := os.exec(cmd) | ||||
| 			println(s) | ||||
| 			println('failed to run the compiled program, this should never happen') | ||||
| 			println('please submit a GitHub issue')  | ||||
| 			if !v.pref.is_test {  | ||||
| 				s := os.exec(cmd) | ||||
| 				println(s) | ||||
| 				println('failed to run the compiled program') | ||||
| 			}  | ||||
| 			exit(1) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn (c mut V) cc() { | ||||
| fn (v mut V) cc() { | ||||
| 	linux_host := os.user_os() == 'linux' | ||||
| 	c.log('cc() isprod=$c.pref.is_prod outname=$c.out_name') | ||||
| 	v.log('cc() isprod=$v.pref.is_prod outname=$v.out_name') | ||||
| 	mut a := ['-w']// arguments for the C compiler
 | ||||
| 	flags := c.table.flags.join(' ') | ||||
| 	flags := v.table.flags.join(' ') | ||||
| 	/*  | ||||
| 	mut shared := '' | ||||
| 	if c.pref.is_so { | ||||
| 	if v.pref.is_so { | ||||
| 		a << '-shared'// -Wl,-z,defs'
 | ||||
| 		c.out_name = c.out_name + '.so' | ||||
| 		v.out_name = v.out_name + '.so' | ||||
| 	} | ||||
| */ | ||||
| 	if c.pref.is_prod { | ||||
| 	if v.pref.is_prod { | ||||
| 		a << '-O2' | ||||
| 	} | ||||
| 	else { | ||||
| 		a << '-g' | ||||
| 	} | ||||
| 	mut libs := ''// builtin.o os.o http.o etc
 | ||||
| 	if c.pref.build_mode == BUILD { | ||||
| 	if v.pref.build_mode == BUILD { | ||||
| 		a << '-c' | ||||
| 	} | ||||
| 	else if c.pref.build_mode == EMBED_VLIB { | ||||
| 	else if v.pref.build_mode == EMBED_VLIB { | ||||
| 		// 
 | ||||
| 	} | ||||
| 	else if c.pref.build_mode == DEFAULT_MODE { | ||||
| 	else if v.pref.build_mode == DEFAULT_MODE { | ||||
| 		libs = '$TmpPath/vlib/builtin.o' | ||||
| 		if !os.file_exists(libs) { | ||||
| 			println('`builtin.o` not found') | ||||
| 			exit(1) | ||||
| 		} | ||||
| 		for imp in c.table.imports { | ||||
| 		for imp in v.table.imports { | ||||
| 			if imp == 'webview' { | ||||
| 				continue | ||||
| 			} | ||||
|  | @ -451,62 +453,62 @@ fn (c mut V) cc() { | |||
| 	// -I flags
 | ||||
| 	/*  | ||||
| mut args := ''  | ||||
| 	for flag in c.table.flags { | ||||
| 	for flag in v.table.flags { | ||||
| 		if !flag.starts_with('-l') { | ||||
| 			args += flag | ||||
| 			args += ' ' | ||||
| 		} | ||||
| 	} | ||||
| */ | ||||
| 	if c.pref.sanitize { | ||||
| 	if v.pref.sanitize { | ||||
| 		a << '-fsanitize=leak' | ||||
| 	} | ||||
| 	// Cross compiling linux
 | ||||
| 	sysroot := '/Users/alex/tmp/lld/linuxroot/' | ||||
| 	if c.os == LINUX && !linux_host { | ||||
| 	if v.os == LINUX && !linux_host { | ||||
| 		// Build file.o
 | ||||
| 		a << '-c --sysroot=$sysroot -target x86_64-linux-gnu' | ||||
| 		// Right now `out_name` can be `file`, not `file.o`
 | ||||
| 		if !c.out_name.ends_with('.o') { | ||||
| 			c.out_name = c.out_name + '.o' | ||||
| 		if !v.out_name.ends_with('.o') { | ||||
| 			v.out_name = v.out_name + '.o' | ||||
| 		} | ||||
| 	} | ||||
| 	// Cross compiling windows
 | ||||
| 	// sysroot := '/Users/alex/tmp/lld/linuxroot/'
 | ||||
| 	// Output executable name
 | ||||
| 	// else {
 | ||||
| 	a << '-o $c.out_name' | ||||
| 	a << '-o $v.out_name' | ||||
| 	// The C file we are compiling
 | ||||
| 	a << '$TmpPath/$c.out_name_c' | ||||
| 	a << '$TmpPath/$v.out_name_c' | ||||
| 	// }
 | ||||
| 	// Min macos version is mandatory I think?
 | ||||
| 	if c.os == MAC { | ||||
| 	if v.os == MAC { | ||||
| 		a << '-mmacosx-version-min=10.7' | ||||
| 	} | ||||
| 	a << flags | ||||
| 	a << libs | ||||
| 	// macOS code can include objective C  TODO remove once objective C is replaced with C
 | ||||
| 	if c.os == MAC { | ||||
| 	if v.os == MAC { | ||||
| 		a << '-x objective-c' | ||||
| 	} | ||||
| 	// Without these libs compilation will fail on Linux
 | ||||
| 	if c.os == LINUX && c.pref.build_mode != BUILD { | ||||
| 	if v.os == LINUX && v.pref.build_mode != BUILD { | ||||
| 		a << '-lm -ldl -lpthread' | ||||
| 	} | ||||
| 	// Find clang executable
 | ||||
| 	fast_clang := '/usr/local/Cellar/llvm/8.0.0/bin/clang' | ||||
| 	//fast_clang := '/usr/local/Cellar/llvm/8.0.0/bin/clang'
 | ||||
| 	args := a.join(' ') | ||||
| 	mut cmd := if os.file_exists(fast_clang) { | ||||
| 		'$fast_clang $args' | ||||
| 	} | ||||
| 	else { | ||||
| 		'cc $args' | ||||
| 	} | ||||
| 	//mut cmd := if os.file_exists(fast_clang) {
 | ||||
| 	//'$fast_clang $args'
 | ||||
| 	//}
 | ||||
| 	//else {
 | ||||
| 	mut cmd := 'cc $args' | ||||
| 	//}
 | ||||
| 	$if windows { | ||||
| 		cmd = 'gcc $args'  | ||||
| 	}  | ||||
| 	// Print the C command
 | ||||
| 	if c.pref.show_c_cmd || c.pref.is_verbose { | ||||
| 	if v.pref.show_c_cmd || v.pref.is_verbose { | ||||
| 		println('\n==========\n$cmd\n=========\n') | ||||
| 	} | ||||
| 	// Run
 | ||||
|  | @ -517,29 +519,29 @@ mut args := '' | |||
| 		panic('clang error') | ||||
| 	} | ||||
| 	// Link it if we are cross compiling and need an executable
 | ||||
| 	if c.os == LINUX && !linux_host && c.pref.build_mode != BUILD { | ||||
| 		c.out_name = c.out_name.replace('.o', '') | ||||
| 		obj_file := c.out_name + '.o' | ||||
| 		println('linux obj_file=$obj_file out_name=$c.out_name') | ||||
| 	if v.os == LINUX && !linux_host && v.pref.build_mode != BUILD { | ||||
| 		v.out_name = v.out_name.replace('.o', '') | ||||
| 		obj_file := v.out_name + '.o' | ||||
| 		println('linux obj_file=$obj_file out_name=$v.out_name') | ||||
| 		ress := os.exec('/usr/local/Cellar/llvm/8.0.0/bin/ld.lld --sysroot=$sysroot ' + | ||||
| 		'-v -o $c.out_name ' + | ||||
| 		'-v -o $v.out_name ' + | ||||
| 		'-m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 ' + | ||||
| 		'/usr/lib/x86_64-linux-gnu/crt1.o ' + | ||||
| 		'$sysroot/lib/x86_64-linux-gnu/libm-2.28.a ' + | ||||
| 		'/usr/lib/x86_64-linux-gnu/crti.o ' + | ||||
| 		obj_file + | ||||
| 		' /usr/lib/x86_64-linux-gnu/libc.so ' + | ||||
| 		' /usr/lib/x86_64-linux-gnu/libv.so ' + | ||||
| 		'/usr/lib/x86_64-linux-gnu/crtn.o') | ||||
| 		println(ress) | ||||
| 		if ress.contains('error:') { | ||||
| 			exit(1) | ||||
| 		} | ||||
| 		println('linux cross compilation done. resulting binary: "$c.out_name"') | ||||
| 		println('linux cross compilation done. resulting binary: "$v.out_name"') | ||||
| 	} | ||||
| 	//os.rm('$TmpPath/$c.out_name_c') 
 | ||||
| 	//os.rm('$TmpPath/$v.out_name_c') 
 | ||||
| } | ||||
| 
 | ||||
| fn (c &V) v_files_from_dir(dir string) []string { | ||||
| fn (v &V) v_files_from_dir(dir string) []string { | ||||
| 	mut res := []string | ||||
| 	if !os.file_exists(dir) { | ||||
| 		panic('$dir doesn\'t exist') | ||||
|  | @ -547,38 +549,38 @@ fn (c &V) v_files_from_dir(dir string) []string { | |||
| 		panic('$dir isn\'t a directory') | ||||
| 	} | ||||
| 	mut files := os.ls(dir) | ||||
| 	if c.pref.is_verbose { | ||||
| 	if v.pref.is_verbose { | ||||
| 		println('v_files_from_dir ("$dir")') | ||||
| 	} | ||||
| 	// println(files.len)
 | ||||
| 	// println(files)
 | ||||
| 	files.sort() | ||||
| 	for file in files { | ||||
| 		c.log('F=$file') | ||||
| 		v.log('F=$file') | ||||
| 		if !file.ends_with('.v') && !file.ends_with('.vh') { | ||||
| 			continue | ||||
| 		} | ||||
| 		if file.ends_with('_test.v') { | ||||
| 			continue | ||||
| 		} | ||||
| 		if file.ends_with('_win.v') && c.os != WINDOWS { | ||||
| 		if file.ends_with('_win.v') && v.os != WINDOWS { | ||||
| 			continue | ||||
| 		} | ||||
| 		if file.ends_with('_lin.v') && c.os != LINUX { | ||||
| 		if file.ends_with('_lin.v') && v.os != LINUX { | ||||
| 			continue | ||||
| 		} | ||||
| 		if file.ends_with('_mac.v') && c.os != MAC { | ||||
| 			lin_file := file.replace('_mac.v', '_lin.v') | ||||
| 		if file.ends_with('_mav.v') && v.os != MAC { | ||||
| 			lin_file := file.replace('_mav.v', '_lin.v') | ||||
| 			// println('lin_file="$lin_file"')
 | ||||
| 			// If there are both _mac.v and _lin.v, don't use _mac.v
 | ||||
| 			// If there are both _mav.v and _lin.v, don't use _mav.v
 | ||||
| 			if os.file_exists('$dir/$lin_file') { | ||||
| 				continue | ||||
| 			} | ||||
| 			else if c.os == WINDOWS { | ||||
| 			else if v.os == WINDOWS { | ||||
| 				continue | ||||
| 			} | ||||
| 			else { | ||||
| 				// If there's only _mac.v, then it can be used on Linux too
 | ||||
| 				// If there's only _mav.v, then it can be used on Linux too
 | ||||
| 			} | ||||
| 		} | ||||
| 		res << '$dir/$file' | ||||
|  | @ -587,9 +589,9 @@ fn (c &V) v_files_from_dir(dir string) []string { | |||
| } | ||||
| 
 | ||||
| // Parses imports, adds necessary libs, and then user files
 | ||||
| fn (c mut V) add_user_v_files() { | ||||
| 	mut dir := c.dir | ||||
| 	c.log('add_v_files($dir)') | ||||
| fn (v mut V) add_user_v_files() { | ||||
| 	mut dir := v.dir | ||||
| 	v.log('add_v_files($dir)') | ||||
| 	// Need to store user files separately, because they have to be added after libs, but we dont know
 | ||||
| 	// which libs need to be added yet
 | ||||
| 	mut user_files := []string | ||||
|  | @ -609,7 +611,7 @@ fn (c mut V) add_user_v_files() { | |||
| 	} | ||||
| 	else { | ||||
| 		// Add files from the dir user is compiling (only .v files)
 | ||||
| 		files := c.v_files_from_dir(dir) | ||||
| 		files := v.v_files_from_dir(dir) | ||||
| 		for file in files { | ||||
| 			user_files << file | ||||
| 		} | ||||
|  | @ -618,65 +620,65 @@ fn (c mut V) add_user_v_files() { | |||
| 		println('No input .v files') | ||||
| 		exit(1) | ||||
| 	} | ||||
| 	if c.pref.is_verbose { | ||||
| 		c.log('user_files:') | ||||
| 	if v.pref.is_verbose { | ||||
| 		v.log('user_files:') | ||||
| 		println(user_files) | ||||
| 	} | ||||
| 	// Parse user imports
 | ||||
| 	for file in user_files { | ||||
| 		mut p := c.new_parser(file, RUN_IMPORTS) | ||||
| 		mut p := v.new_parser(file, RUN_IMPORTS) | ||||
| 		p.parse() | ||||
| 	} | ||||
| 	// Parse lib imports
 | ||||
| 	if c.pref.build_mode == DEFAULT_MODE { | ||||
| 		for i := 0; i < c.table.imports.len; i++ { | ||||
| 			pkg := c.table.imports[i] | ||||
| 			vfiles := c.v_files_from_dir('$TmpPath/vlib/$pkg') | ||||
| 	if v.pref.build_mode == DEFAULT_MODE { | ||||
| 		for i := 0; i < v.table.imports.len; i++ { | ||||
| 			pkg := v.table.imports[i] | ||||
| 			vfiles := v.v_files_from_dir('$TmpPath/vlib/$pkg') | ||||
| 			// Add all imports referenced by these libs
 | ||||
| 			for file in vfiles { | ||||
| 				mut p := c.new_parser(file, RUN_IMPORTS) | ||||
| 				mut p := v.new_parser(file, RUN_IMPORTS) | ||||
| 				p.parse() | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	else { | ||||
| 		// TODO this used to crash compiler?
 | ||||
| 		// for pkg in c.table.imports {
 | ||||
| 		for i := 0; i < c.table.imports.len; i++ { | ||||
| 			pkg := c.table.imports[i] | ||||
| 			// mut import_path := '$c.lang_dir/$pkg'
 | ||||
| 			vfiles := c.v_files_from_dir('$c.lang_dir/vlib/$pkg') | ||||
| 		// for pkg in v.table.imports {
 | ||||
| 		for i := 0; i < v.table.imports.len; i++ { | ||||
| 			pkg := v.table.imports[i] | ||||
| 			// mut import_path := '$v.lang_dir/$pkg'
 | ||||
| 			vfiles := v.v_files_from_dir('$v.lang_dir/vlib/$pkg') | ||||
| 			// Add all imports referenced by these libs
 | ||||
| 			for file in vfiles { | ||||
| 				mut p := c.new_parser(file, RUN_IMPORTS) | ||||
| 				mut p := v.new_parser(file, RUN_IMPORTS) | ||||
| 				p.parse() | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if c.pref.is_verbose { | ||||
| 		c.log('imports:') | ||||
| 		println(c.table.imports) | ||||
| 	if v.pref.is_verbose { | ||||
| 		v.log('imports:') | ||||
| 		println(v.table.imports) | ||||
| 	} | ||||
| 	// Only now add all combined lib files
 | ||||
| 	for pkg in c.table.imports { | ||||
| 		mut module_path := '$c.lang_dir/vlib/$pkg' | ||||
| 	for pkg in v.table.imports { | ||||
| 		mut module_path := '$v.lang_dir/vlib/$pkg' | ||||
| 		// If we are in default mode, we don't parse vlib .v files, but header .vh files in
 | ||||
| 		// TmpPath/vlib
 | ||||
| 		// These were generated by vfmt
 | ||||
| 		if c.pref.build_mode == DEFAULT_MODE || c.pref.build_mode == BUILD { | ||||
| 		if v.pref.build_mode == DEFAULT_MODE || v.pref.build_mode == BUILD { | ||||
| 			module_path = '$TmpPath/vlib/$pkg' | ||||
| 		} | ||||
| 		vfiles := c.v_files_from_dir(module_path) | ||||
| 		vfiles := v.v_files_from_dir(module_path) | ||||
| 		for vfile in vfiles { | ||||
| 			c.files << vfile | ||||
| 			v.files << vfile | ||||
| 		} | ||||
| 		// TODO c.files.append_array(vfiles)
 | ||||
| 		// TODO v.files.append_array(vfiles)
 | ||||
| 	} | ||||
| 	// Add user code last
 | ||||
| 	for file in user_files { | ||||
| 		c.files << file | ||||
| 		v.files << file | ||||
| 	} | ||||
| 	// c.files.append_array(user_files)
 | ||||
| 	// v.files.append_array(user_files)
 | ||||
| } | ||||
| 
 | ||||
| fn get_arg(joined_args, arg, def string) string { | ||||
|  | @ -695,8 +697,8 @@ fn get_arg(joined_args, arg, def string) string { | |||
| 	return res | ||||
| } | ||||
| 
 | ||||
| fn (c &V) log(s string) { | ||||
| 	if !c.pref.is_verbose { | ||||
| fn (v &V) log(s string) { | ||||
| 	if !v.pref.is_verbose { | ||||
| 		return | ||||
| 	} | ||||
| 	println(s) | ||||
|  |  | |||
|  | @ -763,6 +763,21 @@ fn (p mut Parser) get_type() string { | |||
| 			p.check(RSBR) | ||||
| 		} | ||||
| 	} | ||||
| 	// map[string]int 
 | ||||
| 	if !p.builtin_pkg && p.tok == NAME && p.lit == 'map' { | ||||
| 		p.next() | ||||
| 		p.check(LSBR)  | ||||
| 		key_type := p.check_name()  | ||||
| 		if key_type != 'string' { | ||||
| 			p.error('maps only support string keys for now')  | ||||
| 		}  | ||||
| 		p.check(RSBR)  | ||||
| 		val_type := p.check_name()  | ||||
| 		typ= 'map_$val_type'  | ||||
| 		p.register_map(typ) | ||||
| 		return typ  | ||||
| 	}  | ||||
| 	//  
 | ||||
| 	for p.tok == MUL { | ||||
| 		mul = true | ||||
| 		nr_muls++ | ||||
|  | @ -2345,6 +2360,18 @@ fn (p mut Parser) register_array(typ string) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| fn (p mut Parser) register_map(typ string) { | ||||
| 	if typ.contains('*') { | ||||
| 		println('bad map $typ') | ||||
| 		return | ||||
| 	} | ||||
| 	if !p.table.known_type(typ) { | ||||
| 		p.register_type_with_parent(typ, 'map') | ||||
| 		p.cgen.typedefs << 'typedef map $typ;' | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn (p mut Parser) struct_init(is_c_struct_init bool) string { | ||||
| 	p.is_struct_init = true | ||||
| 	mut typ := p.get_type() | ||||
|  | @ -2390,11 +2417,12 @@ fn (p mut Parser) struct_init(is_c_struct_init bool) string { | |||
| 			if !t.has_field(field) { | ||||
| 				p.error('`$t.name` has no field `$field`') | ||||
| 			} | ||||
| 			f := t.find_field(field)  | ||||
| 			inited_fields << field | ||||
| 			p.gen('.$field = ') | ||||
| 			p.check(COLON) | ||||
| 			p.fspace() | ||||
| 			p.expression() | ||||
| 			p.check_types(p.bool_expression(),  f.typ)  | ||||
| 			if p.tok == COMMA { | ||||
| 				p.next() | ||||
| 			} | ||||
|  | @ -2419,7 +2447,7 @@ fn (p mut Parser) struct_init(is_c_struct_init bool) string { | |||
| 				p.error('pointer field `${typ}.${field.name}` must be initialized') | ||||
| 			} | ||||
| 			def_val := type_default(field_typ) | ||||
| 			if def_val != '' { | ||||
| 			if def_val != '' && def_val != '{}' { | ||||
| 				p.gen('.$field.name = $def_val') | ||||
| 				if i != t.fields.len - 1 { | ||||
| 					p.gen(',') | ||||
|  | @ -2938,6 +2966,9 @@ fn (p mut Parser) switch_statement() { | |||
| } | ||||
| 
 | ||||
| fn (p mut Parser) assert_statement() { | ||||
| 	if p.first_run() { | ||||
| 		return  | ||||
| 	}  | ||||
| 	p.check(ASSERT) | ||||
| 	p.fspace() | ||||
| 	tmp := p.get_tmp() | ||||
|  |  | |||
|  | @ -8,8 +8,8 @@ struct Table { | |||
| mut: | ||||
| 	types     []Type | ||||
| 	consts    []Var | ||||
| 	fns       []Fn | ||||
| 	obf_ids   map_int // obf_ids 'myfunction'] == 23
 | ||||
| 	fns       map[string]Fn  | ||||
| 	obf_ids   map[string]int // obf_ids 'myfunction'] == 23
 | ||||
| 	packages  []string // List of all modules registered by the application
 | ||||
| 	imports   []string // List of all imports
 | ||||
| 	flags     []string //  ['-framework Cocoa', '-lglfw3']
 | ||||
|  | @ -112,6 +112,7 @@ fn is_float_type(typ string) bool { | |||
| fn new_table(obfuscate bool) *Table { | ||||
| 	mut t := &Table { | ||||
| 		obf_ids: map[string]int{} | ||||
| 		fns: map[string]Fn{} | ||||
| 		obfuscate: obfuscate | ||||
| 	} | ||||
| 	t.register_type('int') | ||||
|  | @ -186,15 +187,8 @@ fn (p mut Parser) register_global(name, typ string) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // TODO PERF O(N) this slows down the comiler a lot!
 | ||||
| fn (t mut Table) register_fn(f Fn) { | ||||
| 	// Avoid duplicate fn names TODO why? the name should already be unique?
 | ||||
| 	for ff in t.fns { | ||||
| 		if ff.name == f.name { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	t.fns << f | ||||
| fn (t mut Table) register_fn(new_fn Fn) { | ||||
| 	t.fns[new_fn.name] = new_fn  | ||||
| } | ||||
| 
 | ||||
| fn (table &Table) known_type(typ string) bool { | ||||
|  | @ -210,24 +204,17 @@ fn (table &Table) known_type(typ string) bool { | |||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // TODO PERF O(N) this slows down the compiler a lot!
 | ||||
| fn (t &Table) find_fn(name string) Fn { | ||||
| 	for f in t.fns { | ||||
| 		if f.name == name { | ||||
| 			return f | ||||
| 		} | ||||
| 	} | ||||
| 	f := t.fns[name]  | ||||
| 	if !isnil(f.name.str) {  | ||||
| 		return f  | ||||
| 	}  | ||||
| 	return Fn{} | ||||
| } | ||||
| 
 | ||||
| // TODO PERF O(N) this slows down the compiler a lot! 
 | ||||
| fn (t &Table) known_fn(name string) bool { | ||||
| 	for f in t.fns { | ||||
| 		if f.name == name { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| 	f := t.find_fn(name)  | ||||
| 	return f.name != ''  | ||||
| } | ||||
| 
 | ||||
| fn (t &Table) known_const(name string) bool { | ||||
|  | @ -240,7 +227,6 @@ fn (t mut Table) register_type(typ string) { | |||
| 	if typ.len == 0 { | ||||
| 		return | ||||
| 	} | ||||
| 	// println('REGISTER TYPE $typ')
 | ||||
| 	for typ2 in t.types { | ||||
| 		if typ2.name == typ { | ||||
| 			return | ||||
|  | @ -553,6 +539,7 @@ fn type_default(typ string) string { | |||
| 	case 'byte*': return '0' | ||||
| 	case 'bool': return '0' | ||||
| 	} | ||||
| 	return '{}'  | ||||
| 	return '' | ||||
| } | ||||
| 
 | ||||
|  | @ -568,7 +555,8 @@ fn (t &Table) is_interface(name string) bool { | |||
| 
 | ||||
| // Do we have fn main()?
 | ||||
| fn (t &Table) main_exists() bool { | ||||
| 	for f in t.fns { | ||||
| 	for entry in t.fns.entries {  | ||||
| 		f := t.fns[entry.key]  | ||||
| 		if f.name == 'main' { | ||||
| 			return true | ||||
| 		} | ||||
|  |  | |||
|  | @ -25,7 +25,7 @@ pub: | |||
| 	// next *Entry
 | ||||
| } | ||||
| 
 | ||||
| pub fn new_map(cap, elm_size int) map { | ||||
| fn new_map(cap, elm_size int) map { | ||||
| 	res := map { | ||||
| 		// len: len,
 | ||||
| 		element_size: elm_size | ||||
|  | @ -59,15 +59,6 @@ fn (m mut map) _set(key string, val voidptr) { | |||
| 	m.is_sorted = false | ||||
| } | ||||
| 
 | ||||
| fn volt_abs(n int) int { | ||||
| 	// println('volt_abs($n)')
 | ||||
| 	if n < 0 { | ||||
| 		// println('< 0: -($n)')
 | ||||
| 		return -n | ||||
| 	} | ||||
| 	return n | ||||
| } | ||||
| 
 | ||||
| fn (m map) bs(query string, start, end int, out voidptr) { | ||||
| 	// println('bs "$query" $start -> $end')
 | ||||
| 	mid := start + ((end - start) / 2) | ||||
|  |  | |||
|  | @ -1,5 +1,10 @@ | |||
| struct User { | ||||
| 	name string  | ||||
| }  | ||||
| 
 | ||||
| struct A { | ||||
| 	m map_int | ||||
| 	m map[string]int  | ||||
| 	users map[string]User  | ||||
| } | ||||
| 
 | ||||
| fn (a mut A) set(key string, val int) { | ||||
|  | @ -10,10 +15,19 @@ fn test_map() { | |||
| 	mut m := map[string]int{} | ||||
| 	m['hi'] = 80 | ||||
| 	assert m['hi'] == 80 | ||||
| 	//// 
 | ||||
| 	mut users := map[string]User{}  | ||||
| 	users['1'] = User{'Peter'}  | ||||
| 	peter := users['1'] | ||||
| 	assert  peter.name == 'Peter'  | ||||
| 
 | ||||
| 	mut a := A{ | ||||
| 		m: new_map(1, sizeof(int)) | ||||
| 		m: map[string]int{}  | ||||
| 		users: map[string]User{}  | ||||
| 	} | ||||
| 	a.users['Bob'] = User{'Bob'}  | ||||
| 	q := a.users['Bob']  | ||||
| 	assert q.name == 'Bob'  | ||||
| 	a.m['one'] = 1 | ||||
| 	a.set('two', 2) | ||||
| 	assert a.m['one'] == 1 | ||||
|  |  | |||
|  | @ -636,7 +636,6 @@ __global g_ustring_runes []int | |||
| pub fn (s string) ustring_tmp() ustring { | ||||
| 	mut res := ustring { | ||||
| 		s: s | ||||
| 		runes: 0 | ||||
| 	} | ||||
| 	res.runes = g_ustring_runes | ||||
| 	res.runes.len = s.len | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue