mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
compiler: fix struct order bug
This commit is contained in:
parent
c6b79dfd24
commit
2fe20cd092
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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')
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user