all: fix a big mutability bug and update all mutable vars

pull/5958/head
Alexander Medvednikov 2020-07-23 23:16:36 +02:00
parent fb41c6659a
commit 632e27a4a9
17 changed files with 78 additions and 69 deletions

View File

@ -14,4 +14,5 @@
- `recover()` from panics
- IO streams
- struct and interface embedding
- vfmt: fix common errors automatically to save time (make vars mutable and vice versa, add missing imports etc)

View File

@ -123,7 +123,7 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool {
fn break_if_debugger_attached() {
unsafe {
ptr := &voidptr(0)
mut ptr := &voidptr(0)
*ptr = 0
}
}

View File

@ -250,7 +250,7 @@ fn (mut n mapnode) remove_from_non_leaf(idx int) {
predecessor := current.keys[current.len - 1]
n.keys[idx] = predecessor
n.values[idx] = current.values[current.len - 1]
node := unsafe {&mapnode(n.children[idx])}
mut node := unsafe {&mapnode(n.children[idx])}
node.remove_key(predecessor)
} else if unsafe {&mapnode(n.children[idx + 1])}.len >= degree {
mut current := unsafe {&mapnode(n.children[idx + 1])}
@ -260,11 +260,11 @@ fn (mut n mapnode) remove_from_non_leaf(idx int) {
successor := current.keys[0]
n.keys[idx] = successor
n.values[idx] = current.values[0]
node := unsafe {&mapnode(n.children[idx + 1])}
mut node := unsafe {&mapnode(n.children[idx + 1])}
node.remove_key(successor)
} else {
n.merge(idx)
node := unsafe {&mapnode(n.children[idx])}
mut node := unsafe {&mapnode(n.children[idx])}
node.remove_key(k)
}
}

View File

@ -281,7 +281,7 @@ pub fn fileno(cfile voidptr) int {
$if windows {
return C._fileno(cfile)
} $else {
cfile_casted := &C.FILE(0) // FILE* cfile_casted = 0;
mut cfile_casted := &C.FILE(0) // FILE* cfile_casted = 0;
cfile_casted = cfile
// Required on FreeBSD/OpenBSD/NetBSD as stdio.h defines fileno(..) with a macro
// that performs a field access on its argument without casting from void*.
@ -922,7 +922,7 @@ pub fn write_file_array(path string, buffer array) ? {
// read_file_array reads an array of `T` values from file `path`
pub fn read_file_array<T>(path string) []T {
a := T{}
tsize := int(sizeof(a))
tsize := int(sizeof(a))
// prepare for reading, get current file size
mut fp := vfopen(path, 'rb')
if isnil(fp) {
@ -935,7 +935,7 @@ pub fn read_file_array<T>(path string) []T {
len := fsize / tsize
buf := malloc(fsize)
C.fread(buf, fsize, 1, fp)
C.fclose(fp)
C.fclose(fp)
return array{element_size: tsize data: buf len: len cap: len }
}

View File

@ -33,10 +33,11 @@ pub fn new_builder(pref &pref.Preferences) Builder {
compiled_dir := if os.is_dir(rdir) { rdir } else { os.dir(rdir) }
table := table.new_table()
if pref.use_color == .always {
util.emanager.set_support_color(true)
// TODO
//util.emanager.set_support_color(true)
}
if pref.use_color == .never {
util.emanager.set_support_color(false)
//util.emanager.set_support_color(false)
}
msvc := find_msvc() or {
if pref.ccompiler == 'msvc' {
@ -210,9 +211,9 @@ fn module_path(mod string) string {
return mod.replace('.', os.path_separator)
}
pub fn (b Builder) find_module_path(mod, fpath string) ?string {
pub fn (b &Builder) find_module_path(mod, fpath string) ?string {
// support @VROOT/v.mod relative paths:
mcache := vmod.get_cache()
mut mcache := vmod.get_cache()
vmod_file_location := mcache.get_by_file(fpath)
mod_path := module_path(mod)
mut module_lookup_paths := []string{}

View File

@ -671,7 +671,7 @@ fn (mut c Builder) cc_windows_cross() {
println(c.pref.out_name + ' has been successfully compiled')
}
fn (c &Builder) build_thirdparty_obj_files() {
fn (mut c Builder) build_thirdparty_obj_files() {
for flag in c.get_os_cflags() {
if flag.value.ends_with('.o') {
rest_of_module_flags := c.get_rest_of_module_cflags(flag)

View File

@ -7,7 +7,7 @@ import v.table
import v.token
import v.ast
pub fn (c &Checker) check_basic(got, expected table.Type) bool {
pub fn (mut c Checker) check_basic(got, expected table.Type) bool {
if got == expected {
return true
}
@ -112,7 +112,7 @@ pub fn (c &Checker) check_basic(got, expected table.Type) bool {
return false
}
pub fn (c &Checker) check_matching_function_symbols(got_type_sym &table.TypeSymbol, exp_type_sym &table.TypeSymbol) bool {
pub fn (mut c Checker) check_matching_function_symbols(got_type_sym &table.TypeSymbol, exp_type_sym &table.TypeSymbol) bool {
got_info := got_type_sym.info as table.FnType
exp_info := exp_type_sym.info as table.FnType
got_fn := got_info.func
@ -143,7 +143,7 @@ pub fn (c &Checker) check_matching_function_symbols(got_type_sym &table.TypeSymb
}
[inline]
fn (c &Checker) check_shift(left_type, right_type table.Type, left_pos, right_pos token.Position) table.Type {
fn (mut c Checker) check_shift(left_type, right_type table.Type, left_pos, right_pos token.Position) table.Type {
if !left_type.is_int() {
c.error('cannot shift type ${c.table.get_type_symbol(right_type).name} into non-integer type ${c.table.get_type_symbol(left_type).name}',
left_pos)
@ -220,7 +220,7 @@ fn (c &Checker) promote_num(left_type, right_type table.Type) table.Type {
}
// TODO: promote(), check_types(), symmetric_check() and check() overlap - should be rearranged
pub fn (c &Checker) check_types(got, expected table.Type) bool {
pub fn (mut c Checker) check_types(got, expected table.Type) bool {
if got == expected {
return true
}
@ -258,7 +258,7 @@ pub fn (c &Checker) check_types(got, expected table.Type) bool {
return true
}
pub fn (c &Checker) symmetric_check(left, right table.Type) bool {
pub fn (mut c Checker) symmetric_check(left, right table.Type) bool {
// allow direct int-literal assignment for pointers for now
// maybe in the future optionals should be used for that
if right.is_ptr() || right.is_pointer() {
@ -303,7 +303,7 @@ pub fn (c &Checker) get_default_fmt(ftyp, typ table.Type) byte {
}
}
pub fn (c &Checker) string_inter_lit(mut node ast.StringInterLiteral) table.Type {
pub fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) table.Type {
for i, expr in node.exprs {
ftyp := c.expr(expr)
node.expr_types << ftyp

View File

@ -125,7 +125,7 @@ pub fn (mut c Checker) check_files(ast_files []ast.File) {
}
if has_main_mod_file && !has_main_fn && files_from_main_module.len > 0 {
if c.pref.is_script && !c.pref.is_test {
first_main_file := files_from_main_module[0]
mut first_main_file := files_from_main_module[0]
first_main_file.stmts << ast.FnDecl{
name: 'main.main'
mod: 'main'
@ -673,14 +673,15 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) (string, token.Position) {
mut to_lock := '' // name of variable that needs lock
mut pos := token.Position{} // and its position
mut explicit_lock_needed := false
match expr {
match mut expr {
ast.CastExpr {
// TODO
return '', pos
}
ast.Ident {
if expr.obj is ast.Var as v {
if !v.is_mut && !v.typ.is_ptr() {
if expr.obj is ast.Var {
mut v := expr.obj as ast.Var
if !v.is_mut {
c.error('`$expr.name` is immutable, declare it with `mut` to make it mutable',
expr.pos)
}
@ -1368,7 +1369,7 @@ pub fn (mut c Checker) check_or_expr(mut or_expr ast.OrExpr, ret_type table.Type
// allow `f() or {}`
return
}
last_stmt := or_expr.stmts[stmts_len - 1]
mut last_stmt := or_expr.stmts[stmts_len - 1]
if ret_type != table.void_type {
if !(last_stmt is ast.Return || last_stmt is ast.BranchStmt || last_stmt is ast.ExprStmt) {
expected_type_name := c.table.get_type_symbol(ret_type).name
@ -1376,7 +1377,7 @@ pub fn (mut c Checker) check_or_expr(mut or_expr ast.OrExpr, ret_type table.Type
or_expr.pos)
return
}
match last_stmt {
match mut last_stmt {
ast.ExprStmt {
last_stmt.typ = c.expr(last_stmt.expr)
type_fits := c.check_types(last_stmt.typ, ret_type)
@ -1618,7 +1619,7 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
// left_type = c.expr(left)
}
assign_stmt.left_types << left_type
match left {
match mut left {
ast.Ident {
if left.kind == .blank_ident {
left_type = right_type
@ -1641,11 +1642,23 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
ident_var_info.typ = left_type
left.info = ident_var_info
if left_type != 0 {
match mut left.obj as v {
ast.Var {
v.typ = left_type
}
ast.GlobalDecl {
v.typ = left_type
}
else {}
}
/*
if left.obj is ast.Var as v {
v.typ = left_type
} else if left.obj is ast.GlobalDecl as v {
v.typ = left_type
}
*/
}
}
}
@ -2425,7 +2438,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
// first use
start_scope := c.file.scope.innermost(ident.pos.pos)
if obj1 := start_scope.find(ident.name) {
match obj1 as obj {
match mut obj1 as obj {
ast.GlobalDecl {
ident.kind = .global
ident.info = ast.IdentVar{
@ -2482,7 +2495,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
name = '${ident.mod}.$ident.name'
}
if obj1 := c.file.global_scope.find(name) {
match obj1 as obj {
match mut obj1 as obj {
ast.ConstField {
mut typ := obj.typ
if typ == 0 {
@ -2600,7 +2613,7 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) table.Type {
c.stmts(branch.stmts)
// If the last statement is an expression, return its type
if branch.stmts.len > 0 {
match branch.stmts[branch.stmts.len - 1] as stmt {
match mut branch.stmts[branch.stmts.len - 1] as stmt {
ast.ExprStmt {
ret_type = c.expr(stmt.expr)
stmt.typ = ret_type
@ -2874,7 +2887,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
c.stmts(branch.stmts)
if expr_required {
if branch.stmts.len > 0 && branch.stmts[branch.stmts.len - 1] is ast.ExprStmt {
last_expr := branch.stmts[branch.stmts.len - 1] as ast.ExprStmt
mut last_expr := branch.stmts[branch.stmts.len - 1] as ast.ExprStmt
c.expected_type = former_expected_type
last_expr.typ = c.expr(last_expr.expr)
if last_expr.typ != node.typ {
@ -3247,7 +3260,7 @@ fn (mut c Checker) sql_stmt(mut node ast.SqlStmt) table.Type {
return table.void_type
}
fn (c &Checker) fetch_and_verify_orm_fields(info table.Struct, pos token.Position, table_name string) []table.Field {
fn (mut c Checker) fetch_and_verify_orm_fields(info table.Struct, pos token.Position, table_name string) []table.Field {
fields := info.fields.filter(it.typ in
[table.string_type, table.int_type, table.bool_type] &&
'skip' !in it.attrs)
@ -3277,7 +3290,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
c.check_valid_snake_case(node.name, 'function name', node.pos)
}
if node.is_method {
sym := c.table.get_type_symbol(node.receiver.typ)
mut sym := c.table.get_type_symbol(node.receiver.typ)
if sym.kind == .interface_ {
c.error('interfaces cannot be used as method receiver', node.receiver_pos)
}

View File

@ -340,7 +340,7 @@ pub fn (mut g Gen) write_typeof_functions() {
}
// V type to C type
fn (g &Gen) typ(t table.Type) string {
fn (mut g Gen) typ(t table.Type) string {
styp := g.base_type(t)
if t.has_flag(.optional) {
// Register an optional if it's not registered yet
@ -354,7 +354,7 @@ fn (g &Gen) typ(t table.Type) string {
return styp
}
fn (g &Gen) base_type(t table.Type) string {
fn (mut g Gen) base_type(t table.Type) string {
share := t.share()
mut styp := if share == .atomic_t { t.atomic_typename() } else { g.cc_type(t) }
if t.has_flag(.shared_f) {
@ -371,7 +371,7 @@ fn (g &Gen) base_type(t table.Type) string {
// but I(emily) would rather have this generation
// all unified in one place so that it doesnt break
// if one location changes
fn (g &Gen) optional_type_name(t table.Type) (string, string) {
fn (mut g Gen) optional_type_name(t table.Type) (string, string) {
base := g.base_type(t)
mut styp := 'Option_$base'
if t.is_ptr() {
@ -760,14 +760,12 @@ fn (mut g Gen) stmt(node ast.Stmt) {
g.has_main = true
}
if node.name == 'backtrace' ||
node.name == 'backtrace_symbols' ||
node.name == 'backtrace_symbols_fd' {
node.name == 'backtrace_symbols' || node.name == 'backtrace_symbols_fd' {
g.write('\n#ifndef __cplusplus\n')
}
g.gen_fn_decl(node, skip)
if node.name == 'backtrace' ||
node.name == 'backtrace_symbols' ||
node.name == 'backtrace_symbols_fd' {
node.name == 'backtrace_symbols' || node.name == 'backtrace_symbols_fd' {
g.write('\n#endif\n')
}
g.fn_decl = keep_fn_decl
@ -918,7 +916,7 @@ fn (mut g Gen) for_in(it ast.ForInStmt) {
// `for num in nums {`
g.writeln('// FOR IN array')
styp := g.typ(it.val_type)
val_sym := g.table.get_type_symbol(it.val_type)
val_sym := g.table.get_type_symbol(it.val_type)
cond_type_is_ptr := it.cond_type.is_ptr()
atmp := g.new_tmp_var()
atmp_type := if cond_type_is_ptr { 'array *' } else { 'array' }
@ -934,7 +932,7 @@ fn (mut g Gen) for_in(it ast.ForInStmt) {
g.write_fn_ptr_decl(val_sym.info as table.FnType, c_name(it.val_var))
g.writeln(' = ((voidptr*)$atmp${op_field}data)[$i];')
} else {
g.writeln('\t$styp ${c_name(it.val_var)} = (($styp*)$atmp${op_field}data)[$i];')
g.writeln('\t$styp ${c_name(it.val_var)} = (($styp*)$atmp${op_field}data)[$i];')
}
}
g.stmts(it.stmts)
@ -944,7 +942,7 @@ fn (mut g Gen) for_in(it ast.ForInStmt) {
g.writeln('// FOR IN map')
key_styp := g.typ(it.key_type)
val_styp := g.typ(it.val_type)
val_sym := g.table.get_type_symbol(it.val_type)
val_sym := g.table.get_type_symbol(it.val_type)
keys_tmp := 'keys_' + g.new_tmp_var()
idx := g.new_tmp_var()
key := if it.key_var in ['', '_'] { g.new_tmp_var() } else { it.key_var }
@ -1043,8 +1041,7 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type, expected_type table.Type)
got_is_ptr := got_type.is_ptr()
expected_is_ptr := expected_type.is_ptr()
neither_void := table.voidptr_type !in [got_type, expected_type]
if got_is_ptr && !expected_is_ptr && neither_void &&
expected_sym.kind !in [.interface_, .placeholder] {
if got_is_ptr && !expected_is_ptr && neither_void && expected_sym.kind !in [.interface_, .placeholder] {
got_deref_type := got_type.deref()
deref_sym := g.table.get_type_symbol(got_deref_type)
deref_will_match := expected_type in [got_type, got_deref_type, deref_sym.parent_idx]
@ -1161,7 +1158,7 @@ fn (mut g Gen) gen_assert_single_expr(e ast.Expr, t table.Type) {
g.write(' /* typeof: ' + typeof(e) + ' type: ' + t.str() + ' */ ')
}
fn (g &Gen) write_fn_ptr_decl(func &table.FnType, ptr_name string) {
fn (mut g Gen) write_fn_ptr_decl(func &table.FnType, ptr_name string) {
ret_styp := g.typ(func.func.return_type)
g.write('$ret_styp (*$ptr_name) (')
arg_len := func.func.args.len
@ -1615,7 +1612,7 @@ fn (mut g Gen) autofree_scope_vars(pos int) {
}
}
fn (g &Gen) autofree_variable(v ast.Var) {
fn (mut g Gen) autofree_variable(v ast.Var) {
sym := g.table.get_type_symbol(v.typ)
// if v.name.contains('output2') {
// eprintln(' > var name: ${v.name:-20s} | is_arg: ${v.is_arg.str():6} | var type: ${int(v.typ):8} | type_name: ${sym.name:-33s}')
@ -1653,7 +1650,7 @@ fn (g &Gen) autofree_variable(v ast.Var) {
}
}
fn (g &Gen) autofree_var_call(free_fn_name string, v ast.Var) {
fn (mut g Gen) autofree_var_call(free_fn_name string, v ast.Var) {
if v.is_arg {
// fn args should not be autofreed
return
@ -2617,8 +2614,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
}
// `x[0] *= y`
if g.assign_op != .assign &&
g.assign_op in token.assign_tokens &&
info.elem_type != table.string_type {
g.assign_op in token.assign_tokens && info.elem_type != table.string_type {
// TODO move this
g.write('*($elem_type_str*)array_get(')
if left_is_ptr && !node.left_type.has_flag(.shared_f) {
@ -2866,8 +2862,7 @@ fn (mut g Gen) return_statement(node ast.Return) {
// normal return
return_sym := g.table.get_type_symbol(node.types[0])
// `return opt_ok(expr)` for functions that expect an optional
if fn_return_is_optional && !node.types[0].has_flag(.optional) &&
return_sym.name != 'Option' {
if fn_return_is_optional && !node.types[0].has_flag(.optional) && return_sym.name != 'Option' {
styp := g.base_type(g.fn_decl.return_type)
opt_type := g.typ(g.fn_decl.return_type)
// Create a tmp for this option
@ -3802,9 +3797,8 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type table.
g.writeln('\tstring err = ${cvar_name}.v_error;')
g.writeln('\tint errcode = ${cvar_name}.ecode;')
stmts := or_block.stmts
if stmts.len > 0 &&
stmts[or_block.stmts.len - 1] is ast.ExprStmt &&
(stmts[stmts.len - 1] as ast.ExprStmt).typ != table.void_type {
if stmts.len > 0 && stmts[or_block.stmts.len - 1] is ast.ExprStmt && (stmts[stmts.len -
1] as ast.ExprStmt).typ != table.void_type {
g.indent++
for i, stmt in stmts {
if i == stmts.len - 1 {
@ -4010,8 +4004,8 @@ fn (mut g Gen) comp_if_to_ifdef(name string, is_comptime_optional bool) string {
return 'TARGET_ORDER_IS_BIG'
}
else {
if is_comptime_optional || (g.pref.compile_defines_all.len > 0 &&
name in g.pref.compile_defines_all) {
if is_comptime_optional ||
(g.pref.compile_defines_all.len > 0 && name in g.pref.compile_defines_all) {
return 'CUSTOM_DEFINE_$name'
}
verror('bad os ifdef name "$name"')
@ -4030,7 +4024,7 @@ fn c_name(name_ string) string {
return name
}
fn (g Gen) type_default(typ table.Type) string {
fn (mut g Gen) type_default(typ table.Type) string {
sym := g.table.get_type_symbol(typ)
if sym.kind == .array {
elem_sym := g.typ(sym.array_info().elem_type)
@ -4706,7 +4700,7 @@ fn (g Gen) type_to_fmt(typ table.Type) string {
}
// Generates interface table and interface indexes
fn (g &Gen) interface_table() string {
fn (mut g Gen) interface_table() string {
mut sb := strings.new_builder(100)
for ityp in g.table.types {
if ityp.kind != .interface_ {

View File

@ -7,7 +7,7 @@ import v.ast
import v.table
import v.util
fn (g &Gen) comptime_call(node ast.ComptimeCall) {
fn (mut g Gen) comptime_call(node ast.ComptimeCall) {
if node.is_vweb {
for stmt in node.vweb_tmpl.stmts {
if stmt is ast.FnDecl {

View File

@ -3,7 +3,7 @@ module gen
import v.pref
import v.util
fn (g &Gen) generate_hotcode_reloading_declarations() {
fn (mut g Gen) generate_hotcode_reloading_declarations() {
if g.pref.os == .windows {
if g.pref.is_livemain {
g.hotcode_definitions.writeln('HANDLE live_fn_mutex = 0;')
@ -29,7 +29,7 @@ void pthread_mutex_unlock(HANDLE *m) {
}
}
fn (g &Gen) generate_hotcode_reloader_code() {
fn (mut g Gen) generate_hotcode_reloader_code() {
if g.pref.is_liveshared {
g.hotcode_definitions.writeln('')
return
@ -66,7 +66,7 @@ void v_bind_live_symbols(void* live_lib){
'
)
fn (g &Gen) generate_hotcode_reloading_main_caller() {
fn (mut g Gen) generate_hotcode_reloading_main_caller() {
if !g.pref.is_livemain {
return
}

View File

@ -106,7 +106,7 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme
}
}
for i, lx in left {
match lx {
match mut lx {
ast.Ident {
if op == .decl_assign {
if p.scope.known_var(lx.name) {

View File

@ -18,7 +18,7 @@ const (
)
fn (mut p Parser) resolve_vroot(flag string) string {
mcache := vmod.get_cache()
mut mcache := vmod.get_cache()
vmod_file_location := mcache.get_by_folder(p.file_name_dir)
if vmod_file_location.vmod_file.len == 0 {
// There was no actual v.mod file found.
@ -133,7 +133,7 @@ fn (mut p Parser) vweb() ast.ComptimeCall {
for stmt in file.stmts {
if stmt is ast.FnDecl {
if stmt.name == 'main.vweb_tmpl_$p.cur_fn_name' {
tmpl_scope := file.scope.innermost(stmt.body_pos.pos)
mut tmpl_scope := file.scope.innermost(stmt.body_pos.pos)
for _, obj in p.scope.objects {
if obj is ast.Var {
mut v := obj

View File

@ -183,7 +183,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
// default_expr = p.tok.lit
// p.expr(0)
default_expr = p.expr(0)
match default_expr {
match mut default_expr {
ast.EnumVal { default_expr.typ = typ }
// TODO: implement all types??
else {}
@ -358,7 +358,7 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
name_pos)
}
typ := table.new_type(reg_idx)
ts := p.table.get_type_symbol(typ)
mut ts := p.table.get_type_symbol(typ)
// if methods were declared before, it's an error, ignore them
ts.methods.clear()
// Parse methods

View File

@ -919,7 +919,7 @@ fn (mut s Scanner) text_scan() token.Token {
}
if name == 'VMOD_FILE' {
if s.vmod_file_content.len == 0 {
mcache := vmod.get_cache()
mut mcache := vmod.get_cache()
vmod_file_location := mcache.get_by_file(s.file_path)
if vmod_file_location.vmod_file.len == 0 {
s.error('@VMOD_FILE can be used only in projects, that have v.mod file')

View File

@ -500,7 +500,7 @@ pub fn (table &Table) qualify_module(mod, file_path string) string {
return mod
}
pub fn (table &Table) register_fn_gen_type(fn_name string, typ Type) {
pub fn (mut table Table) register_fn_gen_type(fn_name string, typ Type) {
mut a := table.fn_gen_types[fn_name]
if typ in a {
return

View File

@ -39,7 +39,7 @@ pub fn new_error_manager() &EManager {
}
}
pub fn (e &EManager) set_support_color(b bool) {
pub fn (mut e EManager) set_support_color(b bool) {
e.support_color = b
}