|
|
@ -219,6 +219,7 @@ struct GlobalConstDef {
|
|
|
|
init string // init later (in _vinit)
|
|
|
|
init string // init later (in _vinit)
|
|
|
|
dep_names []string // the names of all the consts, that this const depends on
|
|
|
|
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
|
|
|
|
order int // -1 for simple defines, string literals, anonymous function names, extern declarations etc
|
|
|
|
|
|
|
|
line int // the line number in the source code, where the const was defined; used to resolve order ambiguities
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
|
|
|
pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
|
|
@ -4425,9 +4426,11 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
|
|
|
|
mod: field.mod
|
|
|
|
mod: field.mod
|
|
|
|
def: '$styp $const_name = $val; // fixed array const'
|
|
|
|
def: '$styp $const_name = $val; // fixed array const'
|
|
|
|
dep_names: g.dependent_var_names(field_expr)
|
|
|
|
dep_names: g.dependent_var_names(field_expr)
|
|
|
|
|
|
|
|
// line: field.pos.line_nr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
g.const_decl_init_later(field.mod, name, field.expr, field.typ, false)
|
|
|
|
g.const_decl_init_later(field.pos.line_nr, field.mod, name, field.expr,
|
|
|
|
|
|
|
|
field.typ, false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast.StringLiteral {
|
|
|
|
ast.StringLiteral {
|
|
|
@ -4437,15 +4440,18 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
|
|
|
|
def: 'string $const_name; // a string literal, inited later'
|
|
|
|
def: 'string $const_name; // a string literal, inited later'
|
|
|
|
init: '\t$const_name = $val;'
|
|
|
|
init: '\t$const_name = $val;'
|
|
|
|
order: -1
|
|
|
|
order: -1
|
|
|
|
|
|
|
|
// line: field.pos.line_nr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast.CallExpr {
|
|
|
|
ast.CallExpr {
|
|
|
|
if field.expr.return_type.has_flag(.optional) {
|
|
|
|
if field.expr.return_type.has_flag(.optional) {
|
|
|
|
g.inside_const_optional = true
|
|
|
|
g.inside_const_optional = true
|
|
|
|
unwrap_option := field.expr.or_block.kind != .absent
|
|
|
|
unwrap_option := field.expr.or_block.kind != .absent
|
|
|
|
g.const_decl_init_later(field.mod, name, field.expr, field.typ, unwrap_option)
|
|
|
|
g.const_decl_init_later(field.pos.line_nr, field.mod, name, field.expr,
|
|
|
|
|
|
|
|
field.typ, unwrap_option)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
g.const_decl_init_later(field.mod, name, field.expr, field.typ, false)
|
|
|
|
g.const_decl_init_later(field.pos.line_nr, field.mod, name, field.expr,
|
|
|
|
|
|
|
|
field.typ, false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g.inside_const_optional = false
|
|
|
|
g.inside_const_optional = false
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -4463,8 +4469,8 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
|
|
|
|
use_cache_mode := g.pref.build_mode == .build_module || g.pref.use_cache
|
|
|
|
use_cache_mode := g.pref.build_mode == .build_module || g.pref.use_cache
|
|
|
|
if !use_cache_mode {
|
|
|
|
if !use_cache_mode {
|
|
|
|
if ct_value := field.comptime_expr_value() {
|
|
|
|
if ct_value := field.comptime_expr_value() {
|
|
|
|
if g.const_decl_precomputed(field.mod, name, field.name, ct_value,
|
|
|
|
if g.const_decl_precomputed(field.pos.line_nr, field.mod, name,
|
|
|
|
field.typ)
|
|
|
|
field.name, ct_value, field.typ)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -4473,16 +4479,18 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
|
|
|
|
if field.is_simple_define_const() {
|
|
|
|
if field.is_simple_define_const() {
|
|
|
|
// "Simple" expressions are not going to need multiple statements,
|
|
|
|
// "Simple" expressions are not going to need multiple statements,
|
|
|
|
// only the ones which are inited later, so it's safe to use expr_string
|
|
|
|
// only the ones which are inited later, so it's safe to use expr_string
|
|
|
|
g.const_decl_simple_define(field.mod, field.name, g.expr_string(field_expr))
|
|
|
|
g.const_decl_simple_define(field.pos.line_nr, field.mod, field.name,
|
|
|
|
|
|
|
|
g.expr_string(field_expr))
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
g.const_decl_init_later(field.mod, name, field.expr, field.typ, false)
|
|
|
|
g.const_decl_init_later(field.pos.line_nr, field.mod, name, field.expr,
|
|
|
|
|
|
|
|
field.typ, false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn (mut g Gen) const_decl_precomputed(mod string, name string, field_name string, ct_value ast.ComptTimeConstValue, typ ast.Type) bool {
|
|
|
|
fn (mut g Gen) const_decl_precomputed(line_nr int, mod string, name string, field_name string, ct_value ast.ComptTimeConstValue, typ ast.Type) bool {
|
|
|
|
mut styp := g.typ(typ)
|
|
|
|
mut styp := g.typ(typ)
|
|
|
|
cname := if g.pref.translated && !g.is_builtin_mod { name } else { '_const_$name' }
|
|
|
|
cname := if g.pref.translated && !g.is_builtin_mod { name } else { '_const_$name' }
|
|
|
|
$if trace_const_precomputed ? {
|
|
|
|
$if trace_const_precomputed ? {
|
|
|
@ -4490,13 +4498,13 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, field_name string
|
|
|
|
}
|
|
|
|
}
|
|
|
|
match ct_value {
|
|
|
|
match ct_value {
|
|
|
|
i8 {
|
|
|
|
i8 {
|
|
|
|
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
|
|
|
|
g.const_decl_write_precomputed(line_nr, mod, styp, cname, field_name, ct_value.str())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i16 {
|
|
|
|
i16 {
|
|
|
|
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
|
|
|
|
g.const_decl_write_precomputed(line_nr, mod, styp, cname, field_name, ct_value.str())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int {
|
|
|
|
int {
|
|
|
|
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
|
|
|
|
g.const_decl_write_precomputed(line_nr, mod, styp, cname, field_name, ct_value.str())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i64 {
|
|
|
|
i64 {
|
|
|
|
if typ == ast.i64_type {
|
|
|
|
if typ == ast.i64_type {
|
|
|
@ -4508,32 +4516,35 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, field_name string
|
|
|
|
// with -cstrict. Add checker errors for overflows instead,
|
|
|
|
// with -cstrict. Add checker errors for overflows instead,
|
|
|
|
// so V can catch them earlier, instead of relying on the
|
|
|
|
// so V can catch them earlier, instead of relying on the
|
|
|
|
// C compiler for that.
|
|
|
|
// C compiler for that.
|
|
|
|
g.const_decl_simple_define(mod, name, ct_value.str())
|
|
|
|
g.const_decl_simple_define(line_nr, mod, name, ct_value.str())
|
|
|
|
return true
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if typ == ast.u64_type {
|
|
|
|
if typ == ast.u64_type {
|
|
|
|
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str() + 'U')
|
|
|
|
g.const_decl_write_precomputed(line_nr, mod, styp, cname, field_name,
|
|
|
|
|
|
|
|
ct_value.str() + 'U')
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
|
|
|
|
g.const_decl_write_precomputed(line_nr, mod, styp, cname, field_name,
|
|
|
|
|
|
|
|
ct_value.str())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
u8 {
|
|
|
|
u8 {
|
|
|
|
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
|
|
|
|
g.const_decl_write_precomputed(line_nr, mod, styp, cname, field_name, ct_value.str())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
u16 {
|
|
|
|
u16 {
|
|
|
|
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
|
|
|
|
g.const_decl_write_precomputed(line_nr, mod, styp, cname, field_name, ct_value.str())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
u32 {
|
|
|
|
u32 {
|
|
|
|
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
|
|
|
|
g.const_decl_write_precomputed(line_nr, mod, styp, cname, field_name, ct_value.str())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
u64 {
|
|
|
|
u64 {
|
|
|
|
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str() + 'U')
|
|
|
|
g.const_decl_write_precomputed(line_nr, mod, styp, cname, field_name, ct_value.str() +
|
|
|
|
|
|
|
|
'U')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f32 {
|
|
|
|
f32 {
|
|
|
|
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
|
|
|
|
g.const_decl_write_precomputed(line_nr, mod, styp, cname, field_name, ct_value.str())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f64 {
|
|
|
|
f64 {
|
|
|
|
g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
|
|
|
|
g.const_decl_write_precomputed(line_nr, mod, styp, cname, field_name, ct_value.str())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rune {
|
|
|
|
rune {
|
|
|
|
rune_code := u32(ct_value)
|
|
|
|
rune_code := u32(ct_value)
|
|
|
@ -4542,14 +4553,16 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, field_name string
|
|
|
|
return false
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
escval := util.smart_quote(u8(rune_code).ascii_str(), false)
|
|
|
|
escval := util.smart_quote(u8(rune_code).ascii_str(), false)
|
|
|
|
g.const_decl_write_precomputed(mod, styp, cname, field_name, "'$escval'")
|
|
|
|
g.const_decl_write_precomputed(line_nr, mod, styp, cname, field_name,
|
|
|
|
|
|
|
|
"'$escval'")
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
g.const_decl_write_precomputed(mod, styp, cname, field_name, u32(ct_value).str())
|
|
|
|
g.const_decl_write_precomputed(line_nr, mod, styp, cname, field_name,
|
|
|
|
|
|
|
|
u32(ct_value).str())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
string {
|
|
|
|
string {
|
|
|
|
escaped_val := util.smart_quote(ct_value, false)
|
|
|
|
escaped_val := util.smart_quote(ct_value, false)
|
|
|
|
// g.const_decl_write_precomputed(styp, cname, '_SLIT("$escaped_val")')
|
|
|
|
// g.const_decl_write_precomputed(line_nr, styp, cname, '_SLIT("$escaped_val")')
|
|
|
|
// TODO: ^ the above for strings, cause:
|
|
|
|
// TODO: ^ the above for strings, cause:
|
|
|
|
// `error C2099: initializer is not a constant` errors in MSVC,
|
|
|
|
// `error C2099: initializer is not a constant` errors in MSVC,
|
|
|
|
// so fall back to the delayed initialisation scheme:
|
|
|
|
// so fall back to the delayed initialisation scheme:
|
|
|
@ -4570,14 +4583,14 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, field_name string
|
|
|
|
return true
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn (mut g Gen) const_decl_write_precomputed(mod string, styp string, cname string, field_name string, ct_value string) {
|
|
|
|
fn (mut g Gen) const_decl_write_precomputed(line_nr int, mod string, styp string, cname string, field_name string, ct_value string) {
|
|
|
|
g.global_const_defs[util.no_dots(field_name)] = GlobalConstDef{
|
|
|
|
g.global_const_defs[util.no_dots(field_name)] = GlobalConstDef{
|
|
|
|
mod: mod
|
|
|
|
mod: mod
|
|
|
|
def: '$styp $cname = $ct_value; // precomputed'
|
|
|
|
def: '$styp $cname = $ct_value; // precomputed'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn (mut g Gen) const_decl_simple_define(mod string, name string, val string) {
|
|
|
|
fn (mut g Gen) const_decl_simple_define(line_nr int, mod string, name string, val string) {
|
|
|
|
// Simple expressions should use a #define
|
|
|
|
// Simple expressions should use a #define
|
|
|
|
// so that we don't pollute the binary with unnecessary global vars
|
|
|
|
// so that we don't pollute the binary with unnecessary global vars
|
|
|
|
// Do not do this when building a module, otherwise the consts
|
|
|
|
// Do not do this when building a module, otherwise the consts
|
|
|
@ -4607,7 +4620,7 @@ fn (mut g Gen) const_decl_simple_define(mod string, name string, val string) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn (mut g Gen) const_decl_init_later(mod string, name string, expr ast.Expr, typ ast.Type, unwrap_option bool) {
|
|
|
|
fn (mut g Gen) const_decl_init_later(line_nr int, mod string, name string, expr ast.Expr, typ ast.Type, unwrap_option bool) {
|
|
|
|
// Initialize more complex consts in `void _vinit/2{}`
|
|
|
|
// Initialize more complex consts in `void _vinit/2{}`
|
|
|
|
// (C doesn't allow init expressions that can't be resolved at compile time).
|
|
|
|
// (C doesn't allow init expressions that can't be resolved at compile time).
|
|
|
|
mut styp := g.typ(typ)
|
|
|
|
mut styp := g.typ(typ)
|
|
|
@ -4628,10 +4641,24 @@ fn (mut g Gen) const_decl_init_later(mod string, name string, expr ast.Expr, typ
|
|
|
|
init.writeln(g.expr_string_surround('\t$cname = ', expr, ';'))
|
|
|
|
init.writeln(g.expr_string_surround('\t$cname = ', expr, ';'))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mut order := 0
|
|
|
|
|
|
|
|
mut line := 0
|
|
|
|
|
|
|
|
if expr is ast.CallExpr {
|
|
|
|
|
|
|
|
// TODO: analyse the function *bodies* too, to know if and what consts are used in them,
|
|
|
|
|
|
|
|
// in order to fill in dep_names properly, and to detect initialisation cycles statically
|
|
|
|
|
|
|
|
// in the checker.
|
|
|
|
|
|
|
|
// For now, just keep the source code order for `const c = f()`,
|
|
|
|
|
|
|
|
// so that programs importing `rand` and `cmd/tools/vshader.v` could run properly:
|
|
|
|
|
|
|
|
order = 1
|
|
|
|
|
|
|
|
line = line_nr
|
|
|
|
|
|
|
|
}
|
|
|
|
g.global_const_defs[util.no_dots(name)] = GlobalConstDef{
|
|
|
|
g.global_const_defs[util.no_dots(name)] = GlobalConstDef{
|
|
|
|
mod: mod
|
|
|
|
mod: mod
|
|
|
|
def: '$styp $cname; // inited later'
|
|
|
|
def: '$styp $cname; // inited later'
|
|
|
|
init: init.str()
|
|
|
|
init: init.str()
|
|
|
|
|
|
|
|
dep_names: g.dependent_var_names(expr)
|
|
|
|
|
|
|
|
order: order
|
|
|
|
|
|
|
|
line: line
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if g.is_autofree {
|
|
|
|
if g.is_autofree {
|
|
|
|
sym := g.table.sym(typ)
|
|
|
|
sym := g.table.sym(typ)
|
|
|
@ -4689,6 +4716,7 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) {
|
|
|
|
mod: node.mod
|
|
|
|
mod: node.mod
|
|
|
|
def: '$fn_type_name = ${g.table.sym(field.typ).name}; // global2'
|
|
|
|
def: '$fn_type_name = ${g.table.sym(field.typ).name}; // global2'
|
|
|
|
order: -1
|
|
|
|
order: -1
|
|
|
|
|
|
|
|
// line: node.pos.line_nr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -4703,6 +4731,7 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) {
|
|
|
|
mod: node.mod
|
|
|
|
mod: node.mod
|
|
|
|
def: def_builder.str()
|
|
|
|
def: def_builder.str()
|
|
|
|
order: -1
|
|
|
|
order: -1
|
|
|
|
|
|
|
|
// line: node.pos.line_nr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -4735,6 +4764,7 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) {
|
|
|
|
def: def_builder.str()
|
|
|
|
def: def_builder.str()
|
|
|
|
init: init
|
|
|
|
init: init
|
|
|
|
dep_names: g.dependent_var_names(field.expr)
|
|
|
|
dep_names: g.dependent_var_names(field.expr)
|
|
|
|
|
|
|
|
// line: node.pos.line_nr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -5112,13 +5142,22 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn (mut g Gen) sort_globals_consts() {
|
|
|
|
fn (mut g Gen) sort_globals_consts() {
|
|
|
|
|
|
|
|
util.timing_start(@METHOD)
|
|
|
|
|
|
|
|
defer {
|
|
|
|
|
|
|
|
util.timing_measure(@METHOD)
|
|
|
|
|
|
|
|
}
|
|
|
|
g.sorted_global_const_names.clear()
|
|
|
|
g.sorted_global_const_names.clear()
|
|
|
|
|
|
|
|
mut orders := map[i64]bool{}
|
|
|
|
mut dep_graph := depgraph.new_dep_graph()
|
|
|
|
mut dep_graph := depgraph.new_dep_graph()
|
|
|
|
for var_name, var_info in g.global_const_defs {
|
|
|
|
for var_name, var_info in g.global_const_defs {
|
|
|
|
dep_graph.add_with_value(var_name, var_info.dep_names, var_info.order)
|
|
|
|
final_order := (var_info.order + 2) * 10000 + var_info.line
|
|
|
|
|
|
|
|
dep_graph.add_with_value(var_name, var_info.dep_names, final_order)
|
|
|
|
|
|
|
|
orders[final_order] = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dep_graph_sorted := dep_graph.resolve()
|
|
|
|
dep_graph_sorted := dep_graph.resolve()
|
|
|
|
for order in [-1, 0] {
|
|
|
|
mut all_orders := orders.keys()
|
|
|
|
|
|
|
|
all_orders.sort()
|
|
|
|
|
|
|
|
for order in all_orders {
|
|
|
|
for node in dep_graph_sorted.nodes {
|
|
|
|
for node in dep_graph_sorted.nodes {
|
|
|
|
if node.value == order {
|
|
|
|
if node.value == order {
|
|
|
|
g.sorted_global_const_names << node.name
|
|
|
|
g.sorted_global_const_names << node.name
|
|
|
|