compiler: fix struct order bug

pull/1787/head
Alexander Medvednikov 2019-08-29 01:52:32 +03:00
parent c6b79dfd24
commit 2fe20cd092
4 changed files with 199 additions and 156 deletions

View File

@ -14,7 +14,6 @@ struct CGen {
typedefs []string typedefs []string
type_aliases []string type_aliases []string
includes []string includes []string
//types []string
thread_args []string thread_args []string
thread_fns []string thread_fns []string
consts []string consts []string
@ -217,15 +216,6 @@ fn (p mut Parser) print_prof_counters() string {
return res.join(';\n') 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) { fn (p mut Parser) gen_typedef(s string) {
if !p.first_pass() { if !p.first_pass() {
return return
@ -297,24 +287,38 @@ fn platform_postfix_to_ifdefguard(name string) string {
} }
// C struct definitions, ordered // C struct definitions, ordered
// Sort the types, make sure types that are referenced by other types
// are added before them.
fn (v mut V) c_type_definitions() string { fn (v mut V) c_type_definitions() string {
mut types := v.table.types mut types := []Type // structs that need to be sorted
// Sort the types, make sure types that are referenced by other types mut top_types := []Type // builtin types and types that only have primitive fields
// 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 { for t in v.table.types {
if !t.name[0].is_capital() {
top_types << t
continue
}
mut only_builtin_fields := true
for field in t.fields {
if field.typ[0].is_capital() {
only_builtin_fields = false
break
}
}
if only_builtin_fields {
top_types << t
continue
}
types << t
}
sort_structs(mut types)
// Generate C code
return types_to_c(top_types, v.table) + '\n/*----*/\n' +
types_to_c(types, v.table)
}
fn types_to_c(types []Type, table &Table) string {
mut sb := strings.new_builder(10)
for t in types {
if t.cat != .union_ && t.cat != .struct_ { if t.cat != .union_ && t.cat != .struct_ {
continue continue
} }
@ -327,14 +331,38 @@ fn (v mut V) c_type_definitions() string {
kind := if t.cat == .union_ {'union'} else {'struct'} kind := if t.cat == .union_ {'union'} else {'struct'}
sb.writeln('$kind $t.name {') sb.writeln('$kind $t.name {')
for field in t.fields { for field in t.fields {
sb.writeln(v.table.cgen_name_type_pair(field.name, sb.writeln(table.cgen_name_type_pair(field.name,
field.typ) + ';') field.typ) + ';')
} }
sb.writeln('};\n') sb.writeln('};\n')
//if is_objc { //if is_objc {
//p.gen_type('@end') //sb.writeln('@end')
//} //}
} }
return sb.str() return sb.str()
} }
// pretty inefficient algo, works fine with N < 1000 (TODO optimize)
fn sort_structs(types mut []Type) {
mut cnt := 0
for i := 0; i < types.len; i++ {
for j in 0 .. i {
t := types[i]
//t2 := types[j]
// check if any of the types before `t` reference `t`
if types[j].contains_field_type(t.name) {
//println('moving up: $t.name len=$types.len')
types.insert(j, t)
types.delete(i+1)
i = 0 // Start from scratch
cnt++
if cnt > 500 {
println('infinite type loop (perhaps you have a recursive struct `$t.name`?)')
exit(1)
}
continue
}
}
}
}

View File

@ -4,9 +4,11 @@
module main module main
import os import (
import time os
import strings time
strings
)
const ( const (
Version = '0.1.18' Version = '0.1.18'
@ -298,7 +300,6 @@ 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(v.c_type_definitions()) 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')

View File

@ -7,29 +7,6 @@ module main
import math import math
import strings import strings
struct Var {
mut:
typ string
name string
is_arg bool
is_const bool
args []Var // function args
attr string // [json] etc
is_mut bool
is_alloc bool
ptr bool
ref bool
parent_fn string // Variables can only be defined in functions
mod string // module where this var is stored
line_nr int
access_mod AccessMod
is_global bool // __global (translated from C only)
is_used bool
is_changed bool
scope_level int
}
struct Table { struct Table {
mut: mut:
types []Type types []Type
@ -45,6 +22,9 @@ mut:
obfuscate bool obfuscate bool
} }
struct GenTable { struct GenTable {
fn_name string fn_name string
types []string types []string
@ -77,6 +57,30 @@ enum TypeCategory {
c_typedef c_typedef
} }
struct Var {
mut:
typ string
name string
is_arg bool
is_const bool
args []Var // function args
attr string // [json] etc
is_mut bool
is_alloc bool
ptr bool
ref bool
parent_fn string // Variables can only be defined in functions
mod string // module where this var is stored
line_nr int
access_mod AccessMod
is_global bool // __global (translated from C only)
is_used bool
is_changed bool
scope_level int
}
struct Type { struct Type {
mut: mut:
mod string mod string
@ -96,6 +100,13 @@ mut:
gen_str bool // needs `.str()` method generation gen_str bool // needs `.str()` method generation
} }
struct TypeNode {
mut:
next &TypeNode
typ Type
}
// For debugging types // For debugging types
fn (t Type) str() string { fn (t Type) str() string {
mut s := 'type "$t.name" {' mut s := 'type "$t.name" {'
@ -928,6 +939,9 @@ fn (fit &FileImportTable) resolve_alias(alias string) string {
} }
fn (t &Type) contains_field_type(typ string) bool { fn (t &Type) contains_field_type(typ string) bool {
if !t.name[0].is_capital() {
return false
}
for field in t.fields { for field in t.fields {
if field.typ == typ { if field.typ == typ {
return true return true

View File

@ -4,19 +4,19 @@
module builtin module builtin
import strings import strings
struct map { struct map {
element_size int element_size int
root *Node root *mapnode
pub: pub:
size int size int
} }
struct Node { struct mapnode {
left *Node left *mapnode
right *Node right *mapnode
is_empty bool is_empty bool
key string key string
val voidptr val voidptr
} }
@ -24,108 +24,108 @@ struct Node {
fn new_map(cap, elm_size int) map { fn new_map(cap, elm_size int) map {
res := map { res := map {
element_size: elm_size element_size: elm_size
root: 0 root: 0
} }
return res return res
} }
// `m := { 'one': 1, 'two': 2 }` // `m := { 'one': 1, 'two': 2 }`
fn new_map_init(cap, elm_size int, keys *string, vals voidptr) map { fn new_map_init(cap, elm_size int, keys *string, vals voidptr) map {
mut res := map { mut res := map {
element_size: elm_size element_size: elm_size
root: 0 root: 0
} }
for i in 0 .. cap { for i in 0 .. cap {
res._set(keys[i], vals + i * elm_size) res._set(keys[i], vals + i * elm_size)
} }
return res return res
} }
fn new_node(key string, val voidptr, element_size int) *Node { fn new_node(key string, val voidptr, element_size int) *mapnode {
new_e := &Node { new_e := &mapnode {
key: key key: key
val: malloc(element_size) val: malloc(element_size)
left: 0 left: 0
right: 0 right: 0
} }
C.memcpy(new_e.val, val, element_size) C.memcpy(new_e.val, val, element_size)
return new_e return new_e
} }
fn (m mut map) insert(n mut Node, key string, val voidptr) { fn (m mut map) insert(n mut mapnode, key string, val voidptr) {
if n.key == key { if n.key == key {
C.memcpy(n.val, val, m.element_size) C.memcpy(n.val, val, m.element_size)
return return
} }
if n.key > key { if n.key > key {
if isnil(n.left) { if isnil(n.left) {
n.left = new_node(key, val, m.element_size) n.left = new_node(key, val, m.element_size)
m.size++ m.size++
} else { } else {
m.insert(mut n.left, key, val) m.insert(mut n.left, key, val)
} }
return return
} }
if isnil(n.right) { if isnil(n.right) {
n.right = new_node(key, val, m.element_size) n.right = new_node(key, val, m.element_size)
m.size++ m.size++
} else { } else {
m.insert(mut n.right, key, val) m.insert(mut n.right, key, val)
} }
} }
fn (n & Node) find(key string, out voidptr, element_size int) bool{ fn (n & mapnode) find(key string, out voidptr, element_size int) bool{
if n.key == key { if n.key == key {
C.memcpy(out, n.val, element_size) C.memcpy(out, n.val, element_size)
return true return true
} }
else if n.key > key { else if n.key > key {
if isnil(n.left) { if isnil(n.left) {
return false return false
} else { } else {
return n.left.find(key, out, element_size) return n.left.find(key, out, element_size)
} }
} }
else { else {
if isnil(n.right) { if isnil(n.right) {
return false return false
} else { } else {
return n.right.find(key, out, element_size) return n.right.find(key, out, element_size)
} }
} }
} }
// same as `find`, but doesn't return a value. Used by `exists` // same as `find`, but doesn't return a value. Used by `exists`
fn (n & Node) find2(key string, element_size int) bool{ fn (n & mapnode) find2(key string, element_size int) bool{
if n.key == key { if n.key == key {
return true return true
} }
else if n.key > key { else if n.key > key {
if isnil(n.left) { if isnil(n.left) {
return false return false
} else { } else {
return n.left.find2(key, element_size) return n.left.find2(key, element_size)
} }
} }
else { else {
if isnil(n.right) { if isnil(n.right) {
return false return false
} else { } else {
return n.right.find2(key, element_size) return n.right.find2(key, element_size)
} }
} }
} }
fn (m mut map) _set(key string, val voidptr) { fn (m mut map) _set(key string, val voidptr) {
if isnil(m.root) { if isnil(m.root) {
m.root = new_node(key, val, m.element_size) m.root = new_node(key, val, m.element_size)
m.size++ m.size++
return return
} }
m.insert(mut m.root, key, val) m.insert(mut m.root, key, val)
} }
/* /*
fn (m map) bs(query string, start, end int, out voidptr) { fn (m map) bs(query string, start, end int, out voidptr) {
// println('bs "$query" $start -> $end') // println('bs "$query" $start -> $end')
mid := start + ((end - start) / 2) mid := start + ((end - start) / 2)
@ -150,23 +150,23 @@ fn (m map) bs(query string, start, end int, out voidptr) {
} }
m.bs(query, mid, end, out) m.bs(query, mid, end, out)
} }
*/ */
fn preorder_keys(node &Node, keys mut []string, key_i int) int { fn preorder_keys(node &mapnode, keys mut []string, key_i int) int {
mut i := key_i mut i := key_i
if !node.is_empty { if !node.is_empty {
mut a := *keys mut a := *keys
a[i] = node.key a[i] = node.key
i++ i++
} }
if !isnil(node.left) { if !isnil(node.left) {
i = preorder_keys(node.left, mut keys, i) i = preorder_keys(node.left, mut keys, i)
} }
if !isnil(node.right) { if !isnil(node.right) {
i = preorder_keys(node.right, mut keys, i) i = preorder_keys(node.right, mut keys, i)
} }
return i return i
} }
pub fn (m mut map) keys() []string { pub fn (m mut map) keys() []string {
mut keys := [''; m.size] mut keys := [''; m.size]
@ -179,44 +179,44 @@ pub fn (m mut map) keys() []string {
fn (m map) get(key string, out voidptr) bool { fn (m map) get(key string, out voidptr) bool {
if isnil(m.root) { if isnil(m.root) {
return false return false
} }
return m.root.find(key, out, m.element_size) return m.root.find(key, out, m.element_size)
} }
pub fn (n mut Node) delete(key string, element_size int) { pub fn (n mut mapnode) delete(key string, element_size int) {
if n.key == key { if n.key == key {
C.memset(n.val, 0, element_size) C.memset(n.val, 0, element_size)
n.is_empty = true n.is_empty = true
return return
} }
else if n.key > key { else if n.key > key {
if isnil(n.left) { if isnil(n.left) {
return return
} else { } else {
n.left.delete(key, element_size) n.left.delete(key, element_size)
} }
} }
else { else {
if isnil(n.right) { if isnil(n.right) {
return return
} else { } else {
n.right.delete(key, element_size) n.right.delete(key, element_size)
} }
} }
} }
pub fn (m mut map) delete(key string) { pub fn (m mut map) delete(key string) {
m.root.delete(key, m.element_size) m.root.delete(key, m.element_size)
m.size-- m.size--
} }
pub fn (m map) exists(key string) bool { pub fn (m map) exists(key string) bool {
panic('map.exists(key) was removed from the language. Use `key in map` instead.') panic('map.exists(key) was removed from the language. Use `key in map` instead.')
} }
fn (m map) _exists(key string) bool { fn (m map) _exists(key string) bool {
return !isnil(m.root) && m.root.find2(key, m.element_size) return !isnil(m.root) && m.root.find2(key, m.element_size)
} }
pub fn (m map) print() { pub fn (m map) print() {
@ -246,10 +246,10 @@ pub fn (m map_string) str() string {
return '{}' return '{}'
} }
mut sb := strings.new_builder(50) mut sb := strings.new_builder(50)
sb.writeln('{') sb.writeln('{')
for key, val in m { for key, val in m {
sb.writeln(' "$key" => "$val"') sb.writeln(' "$key" => "$val"')
} }
sb.writeln('}') sb.writeln('}')
return sb.str() return sb.str()
} }