mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: sort globals and consts definitions (#14739)
This commit is contained in:
parent
c7a619d16e
commit
cdf4ffc513
@ -9,14 +9,16 @@ import v.dotgraph
|
||||
|
||||
struct DepGraphNode {
|
||||
pub mut:
|
||||
name string
|
||||
deps []string
|
||||
name string
|
||||
value i64
|
||||
deps []string
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -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')
|
||||
val := g.expr_string(field.expr)
|
||||
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;')
|
||||
val := g.expr_string(field.expr)
|
||||
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 = ')
|
||||
g.global_const_defs[util.no_dots(name)] = GlobalConstDef{
|
||||
mod: mod
|
||||
def: 'const int $x = $val;'
|
||||
order: -1
|
||||
}
|
||||
} else {
|
||||
g.definitions.write_string('#define $x ')
|
||||
}
|
||||
g.definitions.writeln(val)
|
||||
if g.pref.translated {
|
||||
g.definitions.write_string(';')
|
||||
g.global_const_defs[util.no_dots(name)] = GlobalConstDef{
|
||||
mod: mod
|
||||
def: '#define $x $val'
|
||||
order: -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user