compiler: fix struct order bug

pull/1773/head
Alexander Medvednikov 2019-08-28 17:35:44 +03:00
parent f29079daac
commit 5b1700e52a
4 changed files with 117 additions and 90 deletions

View File

@ -5,7 +5,8 @@
module main module main
import os import os
import strings import strings
import time
struct CGen { struct CGen {
out os.File out os.File
@ -13,14 +14,14 @@ struct CGen {
typedefs []string typedefs []string
type_aliases []string type_aliases []string
includes []string includes []string
types []string //types []string
thread_args []string thread_args []string
thread_fns []string thread_fns []string
consts []string consts []string
fns []string fns []string
so_fns []string so_fns []string
consts_init []string consts_init []string
//buf strings.Builder //buf strings.Builder
is_user bool is_user bool
mut: mut:
lines []string lines []string
@ -35,19 +36,19 @@ mut:
file string file string
line int line int
line_directives bool line_directives bool
cut_pos int cut_pos int
} }
fn new_cgen(out_name_c string) *CGen { fn new_cgen(out_name_c string) *CGen {
path := out_name_c path := out_name_c
out := os.create(path) or { out := os.create(path) or {
println('failed to create $path') println('failed to create $path')
return &CGen{} return &CGen{}
} }
gen := &CGen { gen := &CGen {
out_path: path out_path: path
out: out out: out
//buf: strings.new_builder(10000) //buf: strings.new_builder(10000)
lines: _make(0, 1000, sizeof(string)) lines: _make(0, 1000, sizeof(string))
} }
return gen return gen
@ -128,21 +129,21 @@ fn (g mut CGen) add_placeholder() int {
} }
fn (g mut CGen) start_cut() { fn (g mut CGen) start_cut() {
g.cut_pos = g.add_placeholder() g.cut_pos = g.add_placeholder()
} }
fn (g mut CGen) cut() string { fn (g mut CGen) cut() string {
pos := g.cut_pos pos := g.cut_pos
g.cut_pos = 0 g.cut_pos = 0
if g.is_tmp { if g.is_tmp {
res := g.tmp_line.right(pos) res := g.tmp_line.right(pos)
g.tmp_line = g.tmp_line.left(pos) g.tmp_line = g.tmp_line.left(pos)
return res return res
} }
res := g.cur_line.right(pos) res := g.cur_line.right(pos)
g.cur_line = g.cur_line.left(pos) g.cur_line = g.cur_line.left(pos)
return res return res
} }
fn (g mut CGen) set_placeholder(pos int, val string) { fn (g mut CGen) set_placeholder(pos int, val string) {
if g.nogen || g.pass != .main { 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) { fn (g mut CGen) insert_before(val string) {
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'
} }
fn (g mut CGen) register_thread_fn(wrapper_name, wrapper_text, struct_text string) { 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') return res.join(';\n')
} }
/*
fn (p mut Parser) gen_type(s string) { fn (p mut Parser) gen_type(s string) {
if !p.first_pass() { if !p.first_pass() {
return return
} }
p.cgen.types << s p.cgen.types << s
} }
*/
fn (p mut Parser) gen_typedef(s string) { fn (p mut Parser) gen_typedef(s string) {
if !p.first_pass() { if !p.first_pass() {
@ -242,42 +245,42 @@ fn (g mut CGen) add_to_main(s string) {
} }
fn build_thirdparty_obj_file(flag string) { fn build_thirdparty_obj_file(flag string) {
obj_path := flag.all_after(' ') obj_path := flag.all_after(' ')
if os.file_exists(obj_path) { if os.file_exists(obj_path) {
return return
} }
println('$obj_path not found, building it...') println('$obj_path not found, building it...')
parent := obj_path.all_before_last('/').trim_space() parent := obj_path.all_before_last('/').trim_space()
files := os.ls(parent) files := os.ls(parent)
//files := os.ls(parent).filter(_.ends_with('.c')) TODO //files := os.ls(parent).filter(_.ends_with('.c')) TODO
mut cfiles := '' mut cfiles := ''
for file in files { for file in files {
if file.ends_with('.c') { if file.ends_with('.c') {
cfiles += parent + '/' + file + ' ' cfiles += parent + '/' + file + ' '
} }
} }
cc := find_c_compiler() cc := find_c_compiler()
cc_thirdparty_options := find_c_compiler_thirdparty_options() cc_thirdparty_options := find_c_compiler_thirdparty_options()
res := os.exec('$cc $cc_thirdparty_options -c -o $obj_path $cfiles') or { res := os.exec('$cc $cc_thirdparty_options -c -o $obj_path $cfiles') or {
panic(err) 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 { switch name {
case 'windows': return '_WIN32' case 'windows': return '_WIN32'
case 'mac': return '__APPLE__' case 'mac': return '__APPLE__'
case 'linux': return '__linux__' case 'linux': return '__linux__'
case 'freebsd': return '__FreeBSD__' case 'freebsd': return '__FreeBSD__'
case 'openbsd': return '__OpenBSD__' case 'openbsd': return '__OpenBSD__'
case 'netbsd': return '__NetBSD__' case 'netbsd': return '__NetBSD__'
case 'dragonfly': return '__DragonFly__' case 'dragonfly': return '__DragonFly__'
case 'msvc': return '_MSC_VER' case 'msvc': return '_MSC_VER'
} }
panic('bad os ifdef name "$name"') panic('bad os ifdef name "$name"')
} }
fn platform_postfix_to_ifdefguard(name string) string { fn platform_postfix_to_ifdefguard(name string) string {
switch name { switch name {
@ -290,3 +293,45 @@ fn platform_postfix_to_ifdefguard(name string) string {
panic('bad platform_postfix "$name"') 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()
}

View File

@ -256,12 +256,6 @@ fn (v mut V) compile() {
(v.pref.build_mode == .build && v.dir.contains('/ui'))) { (v.pref.build_mode == .build && v.dir.contains('/ui'))) {
cgen.genln('id defaultFont = 0; // main.v') 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 // We need the cjson header for all the json decoding user will do in default mode
if v.pref.build_mode == .default_mode { if v.pref.build_mode == .default_mode {
if imports_json { if imports_json {
@ -300,7 +294,8 @@ fn (v mut V) compile() {
mut d := strings.new_builder(10000)// Avoid unnecessary allocations mut d := strings.new_builder(10000)// Avoid unnecessary allocations
d.writeln(cgen.includes.join_lines()) d.writeln(cgen.includes.join_lines())
d.writeln(cgen.typedefs.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(const char*, ...);\n')
d.writeln('\nstring _STR_TMP(const char*, ...);\n') d.writeln('\nstring _STR_TMP(const char*, ...);\n')
d.writeln(cgen.fns.join_lines()) d.writeln(cgen.fns.join_lines())
@ -655,7 +650,7 @@ fn new_v(args[]string) *V {
joined_args := args.join(' ') joined_args := args.join(' ')
target_os := get_arg(joined_args, 'os', '') target_os := get_arg(joined_args, 'os', '')
mut out_name := get_arg(joined_args, 'o', 'a.out') mut out_name := get_arg(joined_args, 'o', 'a.out')
mut dir := args.last() mut dir := args.last()
if args.contains('run') { if args.contains('run') {
dir = get_all_after(joined_args, 'run', '') dir = get_all_after(joined_args, 'run', '')

View File

@ -491,8 +491,8 @@ fn key_to_type_cat(tok Token) TypeCategory {
fn (p mut Parser) struct_decl() { fn (p mut Parser) struct_decl() {
// V can generate Objective C for integration with Cocoa // V can generate Objective C for integration with Cocoa
// `[interface:ParentInterface]` // `[interface:ParentInterface]`
is_objc := p.attr.starts_with('interface') //is_objc := p.attr.starts_with('interface')
objc_parent := if is_objc { p.attr.right(10) } else { '' } //objc_parent := if is_objc { p.attr.right(10) } else { '' }
// interface, union, struct // interface, union, struct
is_interface := p.tok == .key_interface is_interface := p.tok == .key_interface
is_union := p.tok == .key_union 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) { if p.pass == .decl && p.table.known_type(name) {
p.error('`$name` redeclared') p.error('`$name` redeclared')
} }
// Generate type definitions if !is_c {
if is_objc { kind := if is_union {'union'} else {'struct'}
p.gen_type('@interface $name : $objc_parent { @public') p.gen_typedef('typedef $kind $name $name;')
}
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 {')
}
} }
// Register the type // Register the type
mut typ := p.table.find_type(name) mut typ := p.table.find_type(name)
@ -634,10 +626,6 @@ fn (p mut Parser) struct_decl() {
is_atomic := p.tok == .key_atomic is_atomic := p.tok == .key_atomic
if is_atomic { if is_atomic {
p.next() p.next()
p.gen_type('_Atomic ')
}
if !is_c {
p.gen_type(p.table.cgen_name_type_pair(field_name, field_type) + ';')
} }
// [ATTR] // [ATTR]
mut attr := '' mut attr := ''
@ -665,17 +653,6 @@ fn (p mut Parser) struct_decl() {
} }
p.check(.rcbr) 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') 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. // Due to a tcc bug, the length needs to be specified.
// GCC crashes if it is. // GCC crashes if it is.
cast := if p.pref.ccompiler == 'tcc' { '($typ[$i])' } else { '($typ[])' } 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 { ') '$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 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 { fn (p mut Parser) match_statement(is_expr bool) string {
p.check(.key_match) p.check(.key_match)
p.cgen.start_tmp() p.cgen.start_tmp()
@ -3367,7 +3344,7 @@ fn (p mut Parser) match_statement(is_expr bool) string {
mut i := 0 mut i := 0
mut all_cases_return := true mut all_cases_return := true
// stores typ of resulting variable // stores typ of resulting variable
mut res_typ := '' mut res_typ := ''
defer { defer {
@ -3375,8 +3352,8 @@ fn (p mut Parser) match_statement(is_expr bool) string {
} }
for p.tok != .rcbr { for p.tok != .rcbr {
if p.tok == .key_else { if p.tok == .key_else {
p.check(.key_else) p.check(.key_else)
p.check(.arrow) p.check(.arrow)
// unwrap match if there is only else // unwrap match if there is only else
@ -3461,7 +3438,7 @@ fn (p mut Parser) match_statement(is_expr bool) string {
p.gen(') || (') p.gen(') || (')
} }
if typ == 'string' { if typ == 'string' {
// TODO: use tmp variable // TODO: use tmp variable
// p.gen('string_eq($tmp_var, ') // p.gen('string_eq($tmp_var, ')
p.gen('string_eq($tmp_var, ') p.gen('string_eq($tmp_var, ')

View File

@ -44,6 +44,7 @@ enum AccessMod {
} }
enum TypeCategory { enum TypeCategory {
builtin
struct_ struct_
func func
interface_ // 2 interface_ // 2
@ -901,3 +902,12 @@ fn (fit &FileImportTable) is_aliased(mod string) bool {
fn (fit &FileImportTable) resolve_alias(alias string) string { fn (fit &FileImportTable) resolve_alias(alias string) string {
return fit.imports[alias] 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
}