compiler: fix struct order bug
parent
f29079daac
commit
5b1700e52a
141
compiler/cgen.v
141
compiler/cgen.v
|
@ -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()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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', '')
|
||||||
|
|
|
@ -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, ')
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue