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