compiler: fix struct order bug
							parent
							
								
									f29079daac
								
							
						
					
					
						commit
						5b1700e52a
					
				
							
								
								
									
										141
									
								
								compiler/cgen.v
								
								
								
								
							
							
						
						
									
										141
									
								
								compiler/cgen.v
								
								
								
								
							|  | @ -5,7 +5,8 @@ | |||
| module main | ||||
| 
 | ||||
| import os | ||||
| import strings  | ||||
| import strings | ||||
| import time | ||||
| 
 | ||||
| struct CGen { | ||||
| 	out          os.File | ||||
|  | @ -13,14 +14,14 @@ struct CGen { | |||
| 	typedefs     []string | ||||
| 	type_aliases []string | ||||
| 	includes     []string | ||||
| 	types        []string | ||||
| 	//types        []string
 | ||||
| 	thread_args  []string | ||||
| 	thread_fns   []string | ||||
| 	consts       []string | ||||
| 	fns          []string | ||||
| 	so_fns       []string | ||||
| 	consts_init  []string | ||||
| 	//buf          strings.Builder 
 | ||||
| 	//buf          strings.Builder
 | ||||
| 	is_user      bool | ||||
| mut: | ||||
| 	lines        []string | ||||
|  | @ -35,19 +36,19 @@ mut: | |||
| 	file            string | ||||
| 	line            int | ||||
| 	line_directives bool | ||||
| 	cut_pos int  | ||||
| 	cut_pos int | ||||
| } | ||||
| 
 | ||||
| fn new_cgen(out_name_c string) *CGen { | ||||
| 	path := out_name_c | ||||
| 	out := os.create(path) or { | ||||
| 		println('failed to create $path')  | ||||
| 		return &CGen{}  | ||||
| 	}  | ||||
| 		println('failed to create $path') | ||||
| 		return &CGen{} | ||||
| 	} | ||||
| 	gen := &CGen { | ||||
| 		out_path: path  | ||||
| 		out: out  | ||||
| 		//buf: strings.new_builder(10000) 
 | ||||
| 		out_path: path | ||||
| 		out: out | ||||
| 		//buf: strings.new_builder(10000)
 | ||||
| 		lines: _make(0, 1000, sizeof(string)) | ||||
| 	} | ||||
| 	return gen | ||||
|  | @ -128,21 +129,21 @@ fn (g mut CGen) add_placeholder() int { | |||
| } | ||||
| 
 | ||||
| fn (g mut CGen) start_cut() { | ||||
| 	g.cut_pos = g.add_placeholder()  | ||||
| }  | ||||
| 	g.cut_pos = g.add_placeholder() | ||||
| } | ||||
| 
 | ||||
| fn (g mut CGen) cut() string { | ||||
| 	pos := g.cut_pos  | ||||
| 	g.cut_pos = 0  | ||||
| 	pos := g.cut_pos | ||||
| 	g.cut_pos = 0 | ||||
| 	if g.is_tmp { | ||||
| 		res := g.tmp_line.right(pos)  | ||||
| 		g.tmp_line = g.tmp_line.left(pos)  | ||||
| 		return res  | ||||
| 		res := g.tmp_line.right(pos) | ||||
| 		g.tmp_line = g.tmp_line.left(pos) | ||||
| 		return res | ||||
| 	} | ||||
| 	res := g.cur_line.right(pos)  | ||||
| 	g.cur_line = g.cur_line.left(pos)  | ||||
| 	return res  | ||||
| }  | ||||
| 	res := g.cur_line.right(pos) | ||||
| 	g.cur_line = g.cur_line.left(pos) | ||||
| 	return res | ||||
| } | ||||
| 
 | ||||
| fn (g mut CGen) set_placeholder(pos int, val string) { | ||||
| 	if g.nogen || g.pass != .main { | ||||
|  | @ -162,8 +163,8 @@ fn (g mut CGen) set_placeholder(pos int, val string) { | |||
| } | ||||
| 
 | ||||
| fn (g mut CGen) insert_before(val string) { | ||||
| 	prev := g.lines[g.lines.len - 1]  | ||||
| 	g.lines[g.lines.len - 1] = '$prev \n $val \n'  | ||||
| 	prev := g.lines[g.lines.len - 1] | ||||
| 	g.lines[g.lines.len - 1] = '$prev \n $val \n' | ||||
| } | ||||
| 
 | ||||
| fn (g mut CGen) register_thread_fn(wrapper_name, wrapper_text, struct_text string) { | ||||
|  | @ -216,12 +217,14 @@ fn (p mut Parser) print_prof_counters() string { | |||
| 	return res.join(';\n') | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| fn (p mut Parser) gen_type(s string) { | ||||
| 	if !p.first_pass() { | ||||
| 		return | ||||
| 	} | ||||
| 	p.cgen.types << s | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| fn (p mut Parser) gen_typedef(s string) { | ||||
| 	if !p.first_pass() { | ||||
|  | @ -242,42 +245,42 @@ fn (g mut CGen) add_to_main(s string) { | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| fn build_thirdparty_obj_file(flag string) {  | ||||
| 	obj_path := flag.all_after(' ')  | ||||
| fn build_thirdparty_obj_file(flag string) { | ||||
| 	obj_path := flag.all_after(' ') | ||||
| 	if os.file_exists(obj_path) { | ||||
| 		return  | ||||
| 	}  | ||||
| 	println('$obj_path not found, building it...')  | ||||
| 	parent := obj_path.all_before_last('/').trim_space()  | ||||
| 	files := os.ls(parent)  | ||||
| 	//files := os.ls(parent).filter(_.ends_with('.c'))  TODO 
 | ||||
| 	mut cfiles := ''  | ||||
| 		return | ||||
| 	} | ||||
| 	println('$obj_path not found, building it...') | ||||
| 	parent := obj_path.all_before_last('/').trim_space() | ||||
| 	files := os.ls(parent) | ||||
| 	//files := os.ls(parent).filter(_.ends_with('.c'))  TODO
 | ||||
| 	mut cfiles := '' | ||||
| 	for file in files { | ||||
| 		if file.ends_with('.c') {  | ||||
| 			cfiles += parent + '/' + file + ' '  | ||||
| 		}  | ||||
| 	}  | ||||
| 		if file.ends_with('.c') { | ||||
| 			cfiles += parent + '/' + file + ' ' | ||||
| 		} | ||||
| 	} | ||||
| 	cc := find_c_compiler() | ||||
| 	cc_thirdparty_options := find_c_compiler_thirdparty_options() | ||||
| 	res := os.exec('$cc $cc_thirdparty_options -c -o $obj_path $cfiles') or { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	println(res.output)  | ||||
| }  | ||||
| 	println(res.output) | ||||
| } | ||||
| 
 | ||||
| fn os_name_to_ifdef(name string) string {  | ||||
| fn os_name_to_ifdef(name string) string { | ||||
| 	switch name { | ||||
| 		case 'windows': return '_WIN32' | ||||
| 		case 'mac': return '__APPLE__' | ||||
| 		case 'linux': return '__linux__'  | ||||
| 		case 'freebsd': return '__FreeBSD__'  | ||||
| 		case 'openbsd': return '__OpenBSD__'  | ||||
| 		case 'netbsd': return '__NetBSD__'  | ||||
| 		case 'dragonfly': return '__DragonFly__'  | ||||
| 		case 'msvc': return '_MSC_VER'  | ||||
| 	}  | ||||
| 	panic('bad os ifdef name "$name"')  | ||||
| }  | ||||
| 		case 'linux': return '__linux__' | ||||
| 		case 'freebsd': return '__FreeBSD__' | ||||
| 		case 'openbsd': return '__OpenBSD__' | ||||
| 		case 'netbsd': return '__NetBSD__' | ||||
| 		case 'dragonfly': return '__DragonFly__' | ||||
| 		case 'msvc': return '_MSC_VER' | ||||
| 	} | ||||
| 	panic('bad os ifdef name "$name"') | ||||
| } | ||||
| 
 | ||||
| fn platform_postfix_to_ifdefguard(name string) string { | ||||
|   switch name { | ||||
|  | @ -290,3 +293,45 @@ fn platform_postfix_to_ifdefguard(name string) string { | |||
|   panic('bad platform_postfix "$name"') | ||||
| } | ||||
| 
 | ||||
| // C struct definitions, ordered
 | ||||
| fn (v mut V) c_type_definitions() string { | ||||
| 	mut types := v.table.types | ||||
| 	// Sort the types, make sure types that are referenced by other types
 | ||||
| 	// are added before them.
 | ||||
| 	for i in 0 .. types.len { | ||||
| 		for j in 0 .. i { | ||||
| 			t := types[i] | ||||
| 			if types[j].contains_field_type(t.name) { | ||||
| 				types[i] = types[j] | ||||
| 				types[j] = t | ||||
| 				continue | ||||
| 			} | ||||
| 			 | ||||
| 		} | ||||
| 	} | ||||
| 	// Generate C code
 | ||||
| 	mut sb := strings.new_builder(10) | ||||
| 	for t in v.table.types { | ||||
| 		if t.cat != .union_ && t.cat != .struct_ { | ||||
| 			continue | ||||
| 		} | ||||
| 		//if is_objc {
 | ||||
| 			//sb.writeln('@interface $name : $objc_parent { @public')
 | ||||
| 		//}
 | ||||
| 		//if is_atomic {
 | ||||
| 			//sb.write('_Atomic ')
 | ||||
| 		//}
 | ||||
| 		kind := if t.cat == .union_ {'union'} else {'struct'} | ||||
| 		sb.writeln('$kind $t.name {') | ||||
| 		for field in t.fields { | ||||
| 			sb.writeln(v.table.cgen_name_type_pair(field.name, | ||||
| 				field.typ) + ';') | ||||
| 		} | ||||
| 		sb.writeln('};\n') | ||||
| 		//if is_objc {
 | ||||
| 			//p.gen_type('@end')
 | ||||
| 		//}
 | ||||
| 	} | ||||
| 	return sb.str() | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -256,12 +256,6 @@ fn (v mut V) compile() { | |||
| 	(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 && 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 v.pref.build_mode == .default_mode { | ||||
| 		if imports_json { | ||||
|  | @ -300,7 +294,8 @@ fn (v mut V) compile() { | |||
| 	mut d := strings.new_builder(10000)// Avoid unnecessary allocations
 | ||||
| 	d.writeln(cgen.includes.join_lines()) | ||||
| 	d.writeln(cgen.typedefs.join_lines()) | ||||
| 	d.writeln(cgen.types.join_lines()) | ||||
| 	//d.writeln(cgen.types.join_lines())
 | ||||
| 	d.writeln(v.c_type_definitions()) | ||||
| 	d.writeln('\nstring _STR(const char*, ...);\n') | ||||
| 	d.writeln('\nstring _STR_TMP(const char*, ...);\n') | ||||
| 	d.writeln(cgen.fns.join_lines()) | ||||
|  | @ -655,7 +650,7 @@ fn new_v(args[]string) *V { | |||
| 	joined_args := args.join(' ') | ||||
| 	target_os := get_arg(joined_args, 'os', '') | ||||
| 	mut out_name := get_arg(joined_args, 'o', 'a.out') | ||||
|    | ||||
| 
 | ||||
| 	mut dir := args.last() | ||||
| 	if args.contains('run') { | ||||
| 		dir = get_all_after(joined_args, 'run', '') | ||||
|  |  | |||
|  | @ -491,8 +491,8 @@ fn key_to_type_cat(tok Token) TypeCategory { | |||
| fn (p mut Parser) struct_decl() { | ||||
| 	// V can generate Objective C for integration with Cocoa
 | ||||
| 	// `[interface:ParentInterface]`
 | ||||
| 	is_objc := p.attr.starts_with('interface') | ||||
| 	objc_parent := if is_objc { p.attr.right(10) } else { '' } | ||||
| 	//is_objc := p.attr.starts_with('interface')
 | ||||
| 	//objc_parent := if is_objc { p.attr.right(10) } else { '' }
 | ||||
| 	// interface, union, struct
 | ||||
| 	is_interface := p.tok == .key_interface | ||||
| 	is_union := p.tok == .key_union | ||||
|  | @ -527,17 +527,9 @@ fn (p mut Parser) struct_decl() { | |||
| 	if p.pass == .decl && p.table.known_type(name) { | ||||
| 		p.error('`$name` redeclared') | ||||
| 	} | ||||
| 	// Generate type definitions
 | ||||
| 	if is_objc { | ||||
| 		p.gen_type('@interface $name : $objc_parent { @public') | ||||
| 	} | ||||
| 	else { | ||||
| 		// type alias is generated later
 | ||||
| 		if !is_c { | ||||
| 			kind := if is_union {'union'} else {'struct'} | ||||
| 			p.gen_typedef('typedef $kind $name $name;') | ||||
| 			p.gen_type('$kind $name {') | ||||
| 		} | ||||
| 	if !is_c { | ||||
| 		kind := if is_union {'union'} else {'struct'} | ||||
| 		p.gen_typedef('typedef $kind $name $name;') | ||||
| 	} | ||||
| 	// Register the type
 | ||||
| 	mut typ := p.table.find_type(name) | ||||
|  | @ -634,10 +626,6 @@ fn (p mut Parser) struct_decl() { | |||
| 		is_atomic := p.tok == .key_atomic | ||||
| 		if is_atomic { | ||||
| 			p.next() | ||||
| 			p.gen_type('_Atomic ') | ||||
| 		} | ||||
| 		if !is_c { | ||||
| 			p.gen_type(p.table.cgen_name_type_pair(field_name, field_type) + ';') | ||||
| 		} | ||||
| 		// [ATTR]
 | ||||
| 		mut attr := '' | ||||
|  | @ -665,17 +653,6 @@ fn (p mut Parser) struct_decl() { | |||
| 	} | ||||
| 
 | ||||
| 	p.check(.rcbr) | ||||
| 	if !is_c { | ||||
| 		if !did_gen_something { | ||||
| 			p.gen_type('EMPTY_STRUCT_DECLARATION };') | ||||
| 			p.fgenln('') | ||||
| 		} else { | ||||
| 			p.gen_type('}; ') | ||||
| 		} | ||||
| 	} | ||||
| 	if is_objc { | ||||
| 		p.gen_type('@end') | ||||
| 	} | ||||
| 	p.fgenln('\n') | ||||
| } | ||||
| 
 | ||||
|  | @ -2790,7 +2767,7 @@ fn (p mut Parser) array_init() string { | |||
| 		// Due to a tcc bug, the length needs to be specified.
 | ||||
| 		// GCC crashes if it is.
 | ||||
| 		cast := if p.pref.ccompiler == 'tcc' { '($typ[$i])' } else { '($typ[])' } | ||||
| 		p.cgen.set_placeholder(new_arr_ph,  | ||||
| 		p.cgen.set_placeholder(new_arr_ph, | ||||
| 			'$new_arr($i, $i, sizeof($typ), $cast { ') | ||||
| 		//}
 | ||||
| 	} | ||||
|  | @ -3352,7 +3329,7 @@ fn (p mut Parser) switch_statement() { | |||
| 	p.returns = false // only get here when no default, so return is not guaranteed
 | ||||
| } | ||||
| 
 | ||||
| // Returns typ if used as expession 
 | ||||
| // Returns typ if used as expession
 | ||||
| fn (p mut Parser) match_statement(is_expr bool) string { | ||||
| 	p.check(.key_match) | ||||
| 	p.cgen.start_tmp() | ||||
|  | @ -3367,7 +3344,7 @@ fn (p mut Parser) match_statement(is_expr bool) string { | |||
| 	mut i := 0 | ||||
| 	mut all_cases_return := true | ||||
| 
 | ||||
| 	// stores typ of resulting variable 
 | ||||
| 	// stores typ of resulting variable
 | ||||
| 	mut res_typ := '' | ||||
| 
 | ||||
| 	defer { | ||||
|  | @ -3375,8 +3352,8 @@ fn (p mut Parser) match_statement(is_expr bool) string { | |||
| 	} | ||||
| 
 | ||||
| 	for p.tok != .rcbr { | ||||
| 		if p.tok == .key_else {  | ||||
| 			p.check(.key_else)  | ||||
| 		if p.tok == .key_else { | ||||
| 			p.check(.key_else) | ||||
| 			p.check(.arrow) | ||||
| 
 | ||||
| 			// unwrap match if there is only else
 | ||||
|  | @ -3461,7 +3438,7 @@ fn (p mut Parser) match_statement(is_expr bool) string { | |||
| 				p.gen(') || (') | ||||
| 			} | ||||
| 
 | ||||
| 			if typ == 'string' {  | ||||
| 			if typ == 'string' { | ||||
| 				// TODO: use tmp variable
 | ||||
| 				// p.gen('string_eq($tmp_var, ')
 | ||||
| 				p.gen('string_eq($tmp_var, ') | ||||
|  |  | |||
|  | @ -44,6 +44,7 @@ enum AccessMod { | |||
| } | ||||
| 
 | ||||
| enum TypeCategory { | ||||
| 	builtin | ||||
| 	struct_ | ||||
| 	func | ||||
| 	interface_ // 2
 | ||||
|  | @ -901,3 +902,12 @@ fn (fit &FileImportTable) is_aliased(mod string) bool { | |||
| fn (fit &FileImportTable) resolve_alias(alias string) string { | ||||
| 	return fit.imports[alias] | ||||
| } | ||||
| 
 | ||||
| fn (t &Type) contains_field_type(typ string) bool { | ||||
| 	for field in t.fields { | ||||
| 		if field.typ == typ { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue