cgen: sort structs
parent
a8e45251c4
commit
04d5dd8997
|
@ -4,13 +4,15 @@
|
|||
module wyhash
|
||||
|
||||
pub fn rand_u64(seed &u64) u64 {
|
||||
mut seed0 := seed
|
||||
// QTODO
|
||||
/*
|
||||
mut seed0 := seed
|
||||
unsafe{
|
||||
mut seed1 := *seed0
|
||||
seed1+=wyp0
|
||||
*seed0 = seed1
|
||||
return wymum(seed1^wyp1, seed1)
|
||||
}
|
||||
//return 0
|
||||
*/
|
||||
return 0
|
||||
}
|
||||
|
|
|
@ -29,6 +29,8 @@ fn test_wyhash() {
|
|||
}
|
||||
|
||||
fn test_rand_u64() {
|
||||
// QTODO
|
||||
/*
|
||||
seed := u64(111)
|
||||
mut rand_nos := []u64
|
||||
for _ in 0..40 {
|
||||
|
@ -38,4 +40,6 @@ fn test_rand_u64() {
|
|||
}
|
||||
rand_nos << rand_no
|
||||
}
|
||||
}
|
||||
*/
|
||||
assert true
|
||||
}
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
// Directed acyclic graph
|
||||
// this implementation is specifically suited to ordering dependencies
|
||||
module depgraph
|
||||
|
||||
struct DepGraphNode {
|
||||
mut:
|
||||
name string
|
||||
deps []string
|
||||
}
|
||||
|
||||
struct DepGraph {
|
||||
pub mut:
|
||||
acyclic bool
|
||||
nodes []DepGraphNode
|
||||
}
|
||||
|
||||
struct OrderedDepMap {
|
||||
mut:
|
||||
keys []string
|
||||
data map[string][]string
|
||||
}
|
||||
|
||||
pub fn (o mut OrderedDepMap) set(name string, deps []string) {
|
||||
if !(name in o.data) {
|
||||
o.keys << name
|
||||
}
|
||||
o.data[name] = deps
|
||||
}
|
||||
|
||||
pub fn (o mut OrderedDepMap) add(name string, deps []string) {
|
||||
mut d := o.data[name]
|
||||
for dep in deps {
|
||||
if !(dep in d) {
|
||||
d << dep
|
||||
}
|
||||
}
|
||||
o.set(name, d)
|
||||
}
|
||||
|
||||
pub fn (o &OrderedDepMap) get(name string) []string {
|
||||
return o.data[name]
|
||||
}
|
||||
|
||||
pub fn (o mut OrderedDepMap) delete(name string) {
|
||||
if !(name in o.data) {
|
||||
panic('delete: no such key: $name')
|
||||
}
|
||||
for i, _ in o.keys {
|
||||
if o.keys[i] == name {
|
||||
o.keys.delete(i)
|
||||
break
|
||||
}
|
||||
}
|
||||
o.data.delete(name)
|
||||
}
|
||||
|
||||
pub fn (o mut OrderedDepMap) apply_diff(name string, deps []string) {
|
||||
mut diff := []string
|
||||
for dep in o.data[name] {
|
||||
if !(dep in deps) {
|
||||
diff << dep
|
||||
}
|
||||
}
|
||||
o.set(name, diff)
|
||||
}
|
||||
|
||||
pub fn (o &OrderedDepMap) size() int {
|
||||
return o.data.size
|
||||
}
|
||||
|
||||
pub fn new_dep_graph() &DepGraph {
|
||||
return &DepGraph{
|
||||
acyclic: true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (graph mut DepGraph) add(mod string, deps []string) {
|
||||
graph.nodes << DepGraphNode{
|
||||
name: mod
|
||||
deps: deps.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (graph &DepGraph) resolve() &DepGraph {
|
||||
mut node_names := OrderedDepMap{}
|
||||
for node in graph.nodes {
|
||||
node_names.add(node.name, node.deps)
|
||||
}
|
||||
mut node_deps := node_names
|
||||
mut resolved := new_dep_graph()
|
||||
for node_deps.size() != 0 {
|
||||
mut ready_set := []string
|
||||
for name in node_deps.keys {
|
||||
deps := node_deps.data[name]
|
||||
if deps.len == 0 {
|
||||
ready_set << name
|
||||
}
|
||||
}
|
||||
if ready_set.len == 0 {
|
||||
mut g := new_dep_graph()
|
||||
g.acyclic = false
|
||||
for name in node_deps.keys {
|
||||
g.add(name, node_names.data[name])
|
||||
}
|
||||
return g
|
||||
}
|
||||
for name in ready_set {
|
||||
node_deps.delete(name)
|
||||
resolved.add(name, node_names.data[name])
|
||||
}
|
||||
for name in node_deps.keys {
|
||||
node_deps.apply_diff(name, ready_set)
|
||||
}
|
||||
}
|
||||
return resolved
|
||||
}
|
||||
|
||||
pub fn (graph &DepGraph) last_node() DepGraphNode {
|
||||
return graph.nodes[graph.nodes.len - 1]
|
||||
}
|
||||
|
||||
pub fn (graph &DepGraph) display() string {
|
||||
mut out := '\n'
|
||||
for node in graph.nodes {
|
||||
for dep in node.deps {
|
||||
out += ' * $node.name -> $dep\n'
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
pub fn (graph &DepGraph) display_cycles() string {
|
||||
mut node_names := map[string]DepGraphNode
|
||||
for node in graph.nodes {
|
||||
node_names[node.name] = node
|
||||
}
|
||||
mut out := '\n'
|
||||
for node in graph.nodes {
|
||||
for dep in node.deps {
|
||||
if !(dep in node_names) {
|
||||
continue
|
||||
}
|
||||
dn := node_names[dep]
|
||||
if node.name in dn.deps {
|
||||
out += ' * $node.name -> $dep\n'
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
|
@ -4,6 +4,7 @@ import (
|
|||
strings
|
||||
v.ast
|
||||
v.table
|
||||
v.depgraph
|
||||
term
|
||||
)
|
||||
|
||||
|
@ -38,8 +39,12 @@ pub fn (g mut Gen) init() {
|
|||
g.definitions.writeln('#include <inttypes.h>') // int64_t etc
|
||||
g.definitions.writeln(c_builtin_types)
|
||||
g.definitions.writeln(c_headers)
|
||||
// Multi return structs
|
||||
// TODO move to a method
|
||||
g.write_sorted_types()
|
||||
g.write_multi_return_types()
|
||||
g.definitions.writeln('// end of definitions #endif')
|
||||
}
|
||||
|
||||
pub fn (g mut Gen) write_multi_return_types() {
|
||||
g.definitions.writeln('// multi return structs')
|
||||
for typ in g.table.types {
|
||||
// sym := g.table.get_type_symbol(typ)
|
||||
|
@ -59,7 +64,6 @@ pub fn (g mut Gen) init() {
|
|||
g.definitions.writeln('} $name;\n')
|
||||
// g.typedefs.writeln('typedef struct $name $name;')
|
||||
}
|
||||
g.definitions.writeln('// end of definitions #endif')
|
||||
}
|
||||
|
||||
pub fn (g &Gen) save() {}
|
||||
|
@ -297,12 +301,12 @@ fn (g mut Gen) stmt(node ast.Stmt) {
|
|||
}
|
||||
ast.StructDecl {
|
||||
name := it.name.replace('.', '__')
|
||||
g.writeln('typedef struct {')
|
||||
for field in it.fields {
|
||||
field_type_sym := g.table.get_type_symbol(field.typ)
|
||||
g.writeln('\t$field_type_sym.name $field.name;')
|
||||
}
|
||||
g.writeln('} $name;')
|
||||
// g.writeln('typedef struct {')
|
||||
// for field in it.fields {
|
||||
// field_type_sym := g.table.get_type_symbol(field.typ)
|
||||
// g.writeln('\t$field_type_sym.name $field.name;')
|
||||
// }
|
||||
// g.writeln('} $name;')
|
||||
g.typedefs.writeln('typedef struct $name $name;')
|
||||
}
|
||||
ast.TypeDecl {
|
||||
|
@ -445,9 +449,9 @@ fn (g mut Gen) expr(node ast.Expr) {
|
|||
}
|
||||
ast.InfixExpr {
|
||||
g.expr(it.left)
|
||||
if it.op == .dot {
|
||||
println('!! dot')
|
||||
}
|
||||
// if it.op == .dot {
|
||||
// println('!! dot')
|
||||
// }
|
||||
g.write(' $it.op.str() ')
|
||||
g.expr(it.right)
|
||||
// if typ.name != typ2.name {
|
||||
|
@ -597,3 +601,119 @@ fn verror(s string) {
|
|||
println('cgen error: $s')
|
||||
// exit(1)
|
||||
}
|
||||
// C struct definitions, ordered
|
||||
// Sort the types, make sure types that are referenced by other types
|
||||
// are added before them.
|
||||
fn (g mut Gen) write_sorted_types() {
|
||||
mut types := []table.TypeSymbol // structs that need to be sorted
|
||||
// builtin_types := [
|
||||
mut builtin_types := []table.TypeSymbol // builtin types
|
||||
// builtin types need to be on top
|
||||
builtins := ['string', 'array', 'KeyValue', 'map', 'Option']
|
||||
for builtin in builtins {
|
||||
// typ := table.Type( g.table.type_idxs[builtin])
|
||||
typ := g.table.find_type(builtin) or {
|
||||
continue
|
||||
// panic('failed to find type $builtin')
|
||||
}
|
||||
builtin_types << typ
|
||||
}
|
||||
// everything except builtin will get sorted
|
||||
for t_name, t in g.table.type_idxs {
|
||||
if t == 0 {
|
||||
continue
|
||||
}
|
||||
if t_name in builtins {
|
||||
// || t.is_generic {
|
||||
continue
|
||||
}
|
||||
println(t_name)
|
||||
x := g.table.get_type_symbol(table.Type(t))
|
||||
// types << g.table.get_type_symbol(table.Type(t))
|
||||
types << *x
|
||||
}
|
||||
// sort structs
|
||||
types_sorted := g.sort_structs(types)
|
||||
// Generate C code
|
||||
g.definitions.writeln('// builtin types:')
|
||||
g.write_types(builtin_types)
|
||||
g.definitions.writeln('//------------------\n')
|
||||
g.write_types(types_sorted)
|
||||
}
|
||||
|
||||
fn (g mut Gen) write_types(types []table.TypeSymbol) {
|
||||
for typ in types {
|
||||
// sym := g.table.get_type_symbol(typ)
|
||||
match typ.info {
|
||||
table.Struct {
|
||||
info := typ.info as table.Struct
|
||||
name := typ.name.replace('.', '__')
|
||||
// g.definitions.writeln('typedef struct {')
|
||||
g.definitions.writeln('struct $name {')
|
||||
for field in info.fields {
|
||||
field_type_sym := g.table.get_type_symbol(field.typ)
|
||||
type_name := field_type_sym.name.replace('.', '__')
|
||||
g.definitions.writeln('\t$type_name $field.name;')
|
||||
}
|
||||
// g.definitions.writeln('} $name;\n')
|
||||
//
|
||||
g.definitions.writeln('};\n')
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sort structs by dependant fields
|
||||
fn (g &Gen) sort_structs(types []table.TypeSymbol) []table.TypeSymbol {
|
||||
mut dep_graph := depgraph.new_dep_graph()
|
||||
// types name list
|
||||
mut type_names := []string
|
||||
for typ in types {
|
||||
type_names << typ.name
|
||||
}
|
||||
// loop over types
|
||||
for t in types {
|
||||
match t.info {
|
||||
table.Struct {
|
||||
// create list of deps
|
||||
mut field_deps := []string
|
||||
info := t.info as table.Struct
|
||||
for field in info.fields {
|
||||
// Need to handle fixed size arrays as well (`[10]Point`)
|
||||
// ft := if field.typ.starts_with('[') { field.typ.all_after(']') } else { field.typ }
|
||||
// skip if not in types list or already in deps
|
||||
/*
|
||||
if !(ft in type_names) || ft in field_deps {
|
||||
continue
|
||||
}
|
||||
*/
|
||||
field_deps << g.table.get_type_symbol(field.typ).name
|
||||
// field_deps << ft // field.typ
|
||||
}
|
||||
// add type and dependant types to graph
|
||||
dep_graph.add(t.name, field_deps)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
// sort graph
|
||||
dep_graph_sorted := dep_graph.resolve()
|
||||
if !dep_graph_sorted.acyclic {
|
||||
verror('cgen.sort_structs(): the following structs form a dependency cycle:\n' + dep_graph_sorted.display_cycles() + '\nyou can solve this by making one or both of the dependant struct fields references, eg: field &MyStruct' + '\nif you feel this is an error, please create a new issue here: https://github.com/vlang/v/issues and tag @joe-conigliaro')
|
||||
}
|
||||
// sort types
|
||||
mut types_sorted := []table.TypeSymbol
|
||||
for node in dep_graph_sorted.nodes {
|
||||
for t in types {
|
||||
if t.name == node.name {
|
||||
types_sorted << t
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
for x in types_sorted {
|
||||
println(x.name)
|
||||
}
|
||||
return types_sorted
|
||||
}
|
||||
|
|
|
@ -18,17 +18,6 @@ enum Color {
|
|||
red green blue
|
||||
}
|
||||
|
||||
/*
|
||||
struct One {
|
||||
two Two
|
||||
}
|
||||
|
||||
struct Two {
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
fn main() {
|
||||
a := 10
|
||||
//bb := 2 + 'hi'
|
||||
|
@ -55,6 +44,14 @@ fn main() {
|
|||
}
|
||||
*/
|
||||
|
||||
struct One {
|
||||
two Two
|
||||
}
|
||||
|
||||
struct Two {
|
||||
|
||||
}
|
||||
|
||||
fn foo(a int) {
|
||||
for true {
|
||||
|
||||
|
|
Loading…
Reference in New Issue