cgen: sort globals and consts definitions (#14739)

master
yuyi 2022-06-11 22:17:49 +08:00 committed by GitHub
parent c7a619d16e
commit cdf4ffc513
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 192 additions and 103 deletions

View File

@ -10,6 +10,7 @@ import v.dotgraph
struct DepGraphNode {
pub mut:
name string
value i64
deps []string
}
@ -17,6 +18,7 @@ struct DepGraph {
pub mut:
acyclic bool
nodes []DepGraphNode
values map[string]i64
}
struct OrderedDepMap {
@ -43,7 +45,6 @@ pub fn (mut o OrderedDepMap) add(name string, deps []string) {
for dep in deps {
if dep !in d {
d << dep
} else {
}
}
o.set(name, d)
@ -95,6 +96,17 @@ pub fn (mut graph DepGraph) add(mod string, deps []string) {
deps: deps.clone()
}
graph.nodes << new_node
graph.values[mod] = 0
}
pub fn (mut graph DepGraph) add_with_value(mod string, deps []string, value i64) {
new_node := DepGraphNode{
name: mod
value: value
deps: deps.clone()
}
graph.nodes << new_node
graph.values[mod] = value
}
pub fn (graph &DepGraph) resolve() &DepGraph {
@ -119,14 +131,14 @@ pub fn (graph &DepGraph) resolve() &DepGraph {
mut g := new_dep_graph()
g.acyclic = false
for name in node_deps.keys {
g.add(name, node_names.get(name))
g.add_with_value(name, node_names.get(name), graph.values[name])
}
return g
}
for name in ready_set {
node_deps.delete(name)
resolved_deps := node_names.get(name)
resolved.add(name, resolved_deps)
resolved.add_with_value(name, resolved_deps, graph.values[name])
}
for name in node_deps.keys {
node_deps.apply_diff(name, ready_set)

View File

@ -61,10 +61,6 @@ mut:
hotcode_definitions strings.Builder // -live declarations & functions
channel_definitions strings.Builder // channel related code
comptime_definitions strings.Builder // custom defines, given by -d/-define flags on the CLI
global_inits map[string]strings.Builder // default initializers for globals (goes in _vinit())
global_init strings.Builder // thread local of the above
inits map[string]strings.Builder // contents of `void _vinit/2{}`
init strings.Builder
cleanup strings.Builder
cleanups map[string]strings.Builder // contents of `void _vcleanup(){}`
gowrappers strings.Builder // all go callsite wrappers
@ -79,6 +75,8 @@ mut:
out_results strings.Builder // `result_xxxx` types
json_forward_decls strings.Builder // json type forward decls
sql_buf strings.Builder // for writing exprs to args via `sqlite3_bind_int()` etc
global_const_defs map[string]GlobalConstDef
sorted_global_const_names []string
file &ast.File
unique_file_path_hash u64 // a hash of file.path, used for making auxilary fn generation unique (like `compare_xyz`)
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
@ -215,6 +213,15 @@ mut:
use_segfault_handler bool = true
}
// global or const variable definition string
struct GlobalConstDef {
mod string // module name
def string // definition
init string // init later (in _vinit)
dep_names []string // the names of all the consts, that this const depends on
order int // -1 for simple defines, string literals, anonymous function names, extern declarations etc
}
pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
// println('start cgen2')
mut module_built := ''
@ -245,7 +252,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
comptime_definitions: strings.new_builder(100)
definitions: strings.new_builder(100)
gowrappers: strings.new_builder(100)
stringliterals: strings.new_builder(100)
auto_str_funcs: strings.new_builder(100)
dump_funcs: strings.new_builder(100)
pcs_declarations: strings.new_builder(100)
@ -266,7 +272,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
timers: util.new_timers(should_print: timers_should_print, label: 'global_cgen')
inner_loop: &ast.EmptyStmt{}
field_data_type: ast.Type(table.find_type_idx('FieldData'))
init: strings.new_builder(100)
is_cc_msvc: pref.ccompiler == 'msvc'
use_segfault_handler: !('no_segfault_handler' in pref.compile_defines || pref.os == .wasm32)
}
@ -278,8 +283,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
global_g.timers.start('cgen init')
for mod in global_g.table.modules {
global_g.inits[mod] = strings.new_builder(200)
global_g.global_inits[mod] = strings.new_builder(100)
global_g.cleanups[mod] = strings.new_builder(100)
}
global_g.init()
@ -315,6 +318,9 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
global_g.force_main_console = global_g.force_main_console || g.force_main_console
// merge maps
for k, v in g.global_const_defs {
global_g.global_const_defs[k] = v
}
for k, v in g.shareds {
global_g.shareds[k] = v
}
@ -342,8 +348,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
global_g.sql_buf.write(g.sql_buf) or { panic(err) }
global_g.cleanups[g.file.mod.name].write(g.cleanup) or { panic(err) } // strings.Builder.write never fails; it is like that in the source
global_g.inits[g.file.mod.name].write(g.init) or { panic(err) }
global_g.global_inits[g.file.mod.name].write(g.global_init) or { panic(err) }
for str_type in g.str_types {
global_g.str_types << str_type
@ -374,10 +378,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
for file in files {
global_g.file = file
global_g.gen_file()
global_g.inits[file.mod.name].drain_builder(mut global_g.init, 100)
global_g.cleanups[file.mod.name].drain_builder(mut global_g.cleanup, 100)
global_g.global_inits[file.mod.name].drain_builder(mut global_g.global_init,
100)
}
global_g.timers.start('cgen unification')
}
@ -399,6 +400,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
global_g.gen_array_index_methods()
global_g.gen_equality_fns()
global_g.gen_free_methods()
global_g.sort_globals_consts()
global_g.timers.show('cgen unification')
mut g := global_g
@ -462,6 +464,12 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
b.write_string(g.json_forward_decls.str())
b.writeln('\n// V definitions:')
b.write_string(g.definitions.str())
b.writeln('\n// V global/const definitions:')
for var_name in g.sorted_global_const_names {
if var := g.global_const_defs[var_name] {
b.writeln(var.def)
}
}
interface_table := g.interface_table()
if interface_table.len > 0 {
b.writeln('\n// V interface table:')
@ -545,7 +553,6 @@ fn cgen_process_one_file_cb(p &pool.PoolProcessor, idx int, wid int) &Gen {
alias_definitions: strings.new_builder(100)
definitions: strings.new_builder(100)
gowrappers: strings.new_builder(100)
stringliterals: strings.new_builder(100)
auto_str_funcs: strings.new_builder(100)
comptime_definitions: strings.new_builder(100)
pcs_declarations: strings.new_builder(100)
@ -559,8 +566,6 @@ fn cgen_process_one_file_cb(p &pool.PoolProcessor, idx int, wid int) &Gen {
json_forward_decls: strings.new_builder(100)
enum_typedefs: strings.new_builder(100)
sql_buf: strings.new_builder(100)
init: strings.new_builder(100)
global_init: strings.new_builder(0)
cleanup: strings.new_builder(100)
table: global_g.table
pref: global_g.pref
@ -599,8 +604,6 @@ pub fn (mut g Gen) free_builders() {
g.type_definitions.free()
g.alias_definitions.free()
g.definitions.free()
g.global_init.free()
g.init.free()
g.cleanup.free()
g.gowrappers.free()
g.stringliterals.free()
@ -618,12 +621,6 @@ pub fn (mut g Gen) free_builders() {
g.json_forward_decls.free()
g.enum_typedefs.free()
g.sql_buf.free()
for _, mut v in g.global_inits {
v.free()
}
for _, mut v in g.inits {
v.free()
}
for _, mut v in g.cleanups {
v.free()
}
@ -707,14 +704,6 @@ pub fn (mut g Gen) init() {
g.write_sorted_types()
g.write_multi_return_types()
g.definitions.writeln('// end of definitions #endif')
//
if !g.pref.no_builtin {
g.stringliterals.writeln('')
g.stringliterals.writeln('// >> string literal consts')
if g.pref.build_mode != .build_module {
g.stringliterals.writeln('void vinit_string_literals(void){')
}
}
if g.pref.compile_defines_all.len > 0 {
g.comptime_definitions.writeln('// V compile time defines by -d or -define flags:')
g.comptime_definitions.writeln('// All custom defines : ' +
@ -796,13 +785,6 @@ pub fn (mut g Gen) init() {
}
pub fn (mut g Gen) finish() {
if !g.pref.no_builtin {
if g.pref.build_mode != .build_module {
g.stringliterals.writeln('}')
}
g.stringliterals.writeln('// << string literal consts')
g.stringliterals.writeln('')
}
if g.pref.is_prof && g.pref.build_mode != .build_module {
g.gen_vprint_profile_stats()
}
@ -4383,6 +4365,44 @@ fn (mut g Gen) return_stmt(node ast.Return) {
}
}
fn (mut g Gen) dependent_var_names(expr ast.Expr) []string {
mut vars := []string{}
match expr {
ast.Ident {
if expr.kind in [.global, .constant] {
vars << util.no_dots(expr.name)
}
}
ast.ArrayInit {
for elem_expr in expr.exprs {
vars << g.dependent_var_names(elem_expr)
}
}
ast.StructInit {
for field in expr.fields {
vars << g.dependent_var_names(field.expr)
}
}
ast.InfixExpr {
vars << g.dependent_var_names(expr.left)
vars << g.dependent_var_names(expr.right)
}
ast.PostfixExpr {
vars << g.dependent_var_names(expr.expr)
}
ast.PrefixExpr {
vars << g.dependent_var_names(expr.right)
}
ast.CallExpr {
for arg in expr.args {
vars << g.dependent_var_names(arg.expr)
}
}
else {}
}
return vars
}
fn (mut g Gen) const_decl(node ast.ConstDecl) {
g.inside_const = true
defer {
@ -4409,21 +4429,23 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
ast.ArrayInit {
if field.expr.is_fixed {
styp := g.typ(field.expr.typ)
if g.pref.build_mode != .build_module {
val := g.expr_string(field.expr)
g.definitions.writeln('$styp $const_name = $val; // fixed array const')
} else {
g.definitions.writeln('$styp $const_name; // fixed array const')
g.global_const_defs[util.no_dots(field.name)] = GlobalConstDef{
mod: field.mod
def: '$styp $const_name = $val; // fixed array const'
dep_names: g.dependent_var_names(field_expr)
}
} else {
g.const_decl_init_later(field.mod, name, field.expr, field.typ, false)
}
}
ast.StringLiteral {
g.definitions.writeln('string $const_name; // a string literal, inited later')
if g.pref.build_mode != .build_module {
val := g.expr_string(field.expr)
g.stringliterals.writeln('\t$const_name = $val;')
g.global_const_defs[util.no_dots(field.name)] = GlobalConstDef{
mod: field.mod
def: 'string $const_name; // a string literal, inited later'
init: '\t$const_name = $val;'
order: -1
}
}
ast.CallExpr {
@ -4450,7 +4472,9 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
use_cache_mode := g.pref.build_mode == .build_module || g.pref.use_cache
if !use_cache_mode {
if ct_value := field.comptime_expr_value() {
if g.const_decl_precomputed(field.mod, name, ct_value, field.typ) {
if g.const_decl_precomputed(field.mod, name, field.name, ct_value,
field.typ)
{
continue
}
}
@ -4458,7 +4482,7 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
if field.is_simple_define_const() {
// "Simple" expressions are not going to need multiple statements,
// only the ones which are inited later, so it's safe to use expr_string
g.const_decl_simple_define(field.name, g.expr_string(field_expr))
g.const_decl_simple_define(field.mod, field.name, g.expr_string(field_expr))
} else {
g.const_decl_init_later(field.mod, name, field.expr, field.typ, false)
}
@ -4467,7 +4491,7 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
}
}
fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.ComptTimeConstValue, typ ast.Type) bool {
fn (mut g Gen) const_decl_precomputed(mod string, name string, field_name string, ct_value ast.ComptTimeConstValue, typ ast.Type) bool {
mut styp := g.typ(typ)
cname := if g.pref.translated && !g.is_builtin_mod { name } else { '_const_$name' }
$if trace_const_precomputed ? {
@ -4475,13 +4499,13 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.Comp
}
match ct_value {
i8 {
g.const_decl_write_precomputed(styp, cname, ct_value.str())
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
}
i16 {
g.const_decl_write_precomputed(styp, cname, ct_value.str())
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
}
int {
g.const_decl_write_precomputed(styp, cname, ct_value.str())
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
}
i64 {
if typ == ast.i64_type {
@ -4493,32 +4517,32 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.Comp
// with -cstrict. Add checker errors for overflows instead,
// so V can catch them earlier, instead of relying on the
// C compiler for that.
g.const_decl_simple_define(name, ct_value.str())
g.const_decl_simple_define(mod, name, ct_value.str())
return true
}
if typ == ast.u64_type {
g.const_decl_write_precomputed(styp, cname, ct_value.str() + 'U')
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str() + 'U')
} else {
g.const_decl_write_precomputed(styp, cname, ct_value.str())
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
}
}
u8 {
g.const_decl_write_precomputed(styp, cname, ct_value.str())
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
}
u16 {
g.const_decl_write_precomputed(styp, cname, ct_value.str())
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
}
u32 {
g.const_decl_write_precomputed(styp, cname, ct_value.str())
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
}
u64 {
g.const_decl_write_precomputed(styp, cname, ct_value.str() + 'U')
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str() + 'U')
}
f32 {
g.const_decl_write_precomputed(styp, cname, ct_value.str())
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
}
f64 {
g.const_decl_write_precomputed(styp, cname, ct_value.str())
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
}
rune {
rune_code := u32(ct_value)
@ -4527,9 +4551,9 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.Comp
return false
}
escval := util.smart_quote(u8(rune_code).ascii_str(), false)
g.const_decl_write_precomputed(styp, cname, "'$escval'")
g.const_decl_write_precomputed(mod, styp, cname, field_name, "'$escval'")
} else {
g.const_decl_write_precomputed(styp, cname, u32(ct_value).str())
g.const_decl_write_precomputed(mod, styp, cname, field_name, u32(ct_value).str())
}
}
string {
@ -4538,8 +4562,12 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.Comp
// TODO: ^ the above for strings, cause:
// `error C2099: initializer is not a constant` errors in MSVC,
// so fall back to the delayed initialisation scheme:
g.definitions.writeln('$styp $cname; // str inited later')
g.init.writeln('\t$cname = _SLIT("$escaped_val");')
g.global_const_defs[util.no_dots(field_name)] = GlobalConstDef{
mod: mod
def: '$styp $cname; // str inited later'
init: '\t$cname = _SLIT("$escaped_val");'
order: -1
}
if g.is_autofree {
g.cleanups[mod].writeln('\tstring_free(&$cname);')
}
@ -4551,11 +4579,14 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.Comp
return true
}
fn (mut g Gen) const_decl_write_precomputed(styp string, cname string, ct_value string) {
g.definitions.writeln('$styp $cname = $ct_value; // precomputed')
fn (mut g Gen) const_decl_write_precomputed(mod string, styp string, cname string, field_name string, ct_value string) {
g.global_const_defs[util.no_dots(field_name)] = GlobalConstDef{
mod: mod
def: '$styp $cname = $ct_value; // precomputed'
}
}
fn (mut g Gen) const_decl_simple_define(name string, val string) {
fn (mut g Gen) const_decl_simple_define(mod string, name string, val string) {
// Simple expressions should use a #define
// so that we don't pollute the binary with unnecessary global vars
// Do not do this when building a module, otherwise the consts
@ -4571,13 +4602,17 @@ fn (mut g Gen) const_decl_simple_define(name string, val string) {
x = '_const_$x'
}
if g.pref.translated {
g.definitions.write_string('const int $x = ')
} else {
g.definitions.write_string('#define $x ')
g.global_const_defs[util.no_dots(name)] = GlobalConstDef{
mod: mod
def: 'const int $x = $val;'
order: -1
}
} else {
g.global_const_defs[util.no_dots(name)] = GlobalConstDef{
mod: mod
def: '#define $x $val'
order: -1
}
g.definitions.writeln(val)
if g.pref.translated {
g.definitions.write_string(';')
}
}
@ -4586,22 +4621,27 @@ fn (mut g Gen) const_decl_init_later(mod string, name string, expr ast.Expr, typ
// (C doesn't allow init expressions that can't be resolved at compile time).
mut styp := g.typ(typ)
cname := if g.pref.translated && !g.is_builtin_mod { name } else { '_const_$name' }
g.definitions.writeln('$styp $cname; // inited later')
mut init := strings.new_builder(100)
if cname == '_const_os__args' {
if g.pref.os == .windows {
g.init.writeln('\t_const_os__args = os__init_os_args_wide(___argc, (byteptr*)___argv);')
init.writeln('\t_const_os__args = os__init_os_args_wide(___argc, (byteptr*)___argv);')
} else {
g.init.writeln('\t_const_os__args = os__init_os_args(___argc, (byte**)___argv);')
init.writeln('\t_const_os__args = os__init_os_args(___argc, (byte**)___argv);')
}
} else {
if unwrap_option {
g.init.writeln('{')
g.init.writeln(g.expr_string_surround('\t$cname = *($styp*)', expr, '.data;'))
g.init.writeln('}')
init.writeln('{')
init.writeln(g.expr_string_surround('\t$cname = *($styp*)', expr, '.data;'))
init.writeln('}')
} else {
g.init.writeln(g.expr_string_surround('\t$cname = ', expr, ';'))
init.writeln(g.expr_string_surround('\t$cname = ', expr, ';'))
}
}
g.global_const_defs[util.no_dots(name)] = GlobalConstDef{
mod: mod
def: '$styp $cname; // inited later'
init: init.str()
}
if g.is_autofree {
sym := g.table.sym(typ)
if styp.starts_with('Array_') {
@ -4654,40 +4694,57 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) {
if field.has_expr && mut anon_fn_expr is ast.AnonFn {
g.gen_anon_fn_decl(mut anon_fn_expr)
fn_type_name := g.get_anon_fn_type_name(mut anon_fn_expr, field.name)
g.definitions.writeln('$fn_type_name = ${g.table.sym(field.typ).name}; // global2')
g.global_const_defs[util.no_dots(fn_type_name)] = GlobalConstDef{
mod: node.mod
def: '$fn_type_name = ${g.table.sym(field.typ).name}; // global2'
order: -1
}
continue
}
mut def_builder := strings.new_builder(100)
mut init := ''
extern := if cextern { 'extern ' } else { '' }
modifier := if field.is_volatile { ' volatile ' } else { '' }
g.definitions.write_string('$extern$visibility_kw$modifier$styp $attributes $field.name')
def_builder.write_string('$extern$visibility_kw$modifier$styp $attributes $field.name')
if cextern {
g.definitions.writeln('; // global5')
def_builder.writeln('; // global5')
g.global_const_defs[util.no_dots(field.name)] = GlobalConstDef{
mod: node.mod
def: def_builder.str()
order: -1
}
continue
}
if field.has_expr || cinit {
if g.pref.translated {
g.definitions.write_string(' = ${g.expr_string(field.expr)}')
def_builder.write_string(' = ${g.expr_string(field.expr)}')
} else if (field.expr.is_literal() && should_init) || cinit
|| (field.expr is ast.ArrayInit && (field.expr as ast.ArrayInit).is_fixed) {
// Simple literals can be initialized right away in global scope in C.
// e.g. `int myglobal = 10;`
g.definitions.write_string(' = ${g.expr_string(field.expr)}')
def_builder.write_string(' = ${g.expr_string(field.expr)}')
} else {
// More complex expressions need to be moved to `_vinit()`
// e.g. `__global ( mygblobal = 'hello ' + world' )`
g.global_init.writeln('\t$field.name = ${g.expr_string(field.expr)}; // 3global')
init = '\t$field.name = ${g.expr_string(field.expr)}; // 3global'
}
} else if !g.pref.translated { // don't zero globals from C code
default_initializer := g.type_default(field.typ)
if default_initializer == '{0}' && should_init {
g.definitions.write_string(' = {0}')
def_builder.write_string(' = {0}')
} else {
if field.name !in ['as_cast_type_indexes', 'g_memory_block', 'global_allocator'] {
g.global_init.writeln('\t$field.name = *($styp*)&(($styp[]){${g.type_default(field.typ)}}[0]); // global')
init = '\t$field.name = *($styp*)&(($styp[]){${g.type_default(field.typ)}}[0]); // global'
}
}
}
g.definitions.writeln('; // global4')
def_builder.writeln('; // global4')
g.global_const_defs[util.no_dots(field.name)] = GlobalConstDef{
mod: node.mod
def: def_builder.str()
init: init
dep_names: g.dependent_var_names(field.expr)
}
}
}
@ -4769,17 +4826,21 @@ fn (mut g Gen) write_init_function() {
// calling module init functions too, just in case they do fail...
g.write('\tas_cast_type_indexes = ')
g.writeln(g.as_cast_name_table())
//
g.writeln('\tbuiltin_init();')
g.writeln('\tvinit_string_literals();')
//
if g.nr_closures > 0 {
g.writeln('\t_closure_mtx_init();')
}
for mod_name in g.table.modules {
g.writeln('\t{ // Initializations for module $mod_name :')
g.write(g.inits[mod_name].str())
g.write(g.global_inits[mod_name].str())
// write globals and consts init later
for var_name in g.sorted_global_const_names {
if var := g.global_const_defs[var_name] {
if var.mod == mod_name && var.init.len > 0 {
g.writeln(var.init)
}
}
}
init_fn_name := '${mod_name}.init'
if initfn := g.table.find_fn(init_fn_name) {
if initfn.return_type == ast.void_type && initfn.params.len == 0 {
@ -5059,6 +5120,22 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
}
}
fn (mut g Gen) sort_globals_consts() {
g.sorted_global_const_names.clear()
mut dep_graph := depgraph.new_dep_graph()
for var_name, var_info in g.global_const_defs {
dep_graph.add_with_value(var_name, var_info.dep_names, var_info.order)
}
dep_graph_sorted := dep_graph.resolve()
for order in [-1, 0] {
for node in dep_graph_sorted.nodes {
if node.value == order {
g.sorted_global_const_names << node.name
}
}
}
}
// sort structs by dependant fields
fn (mut g Gen) sort_structs(typesa []&ast.TypeSymbol) []&ast.TypeSymbol {
util.timing_start(@METHOD)

View File

@ -152,7 +152,7 @@ $enc_fn_dec {
dec.writeln('\topt_ok2(&res, ($option_name*)&ret, sizeof(res));')
dec.writeln('\treturn ret;\n}')
enc.writeln('\treturn o;\n}')
g.definitions.writeln(dec.str())
g.gowrappers.writeln(dec.str())
g.gowrappers.writeln(enc.str())
}
}