compiler: more memory logic + replace "cur_fn &Fn" with "cur_fn Fn"
parent
f3a74e7d80
commit
9dd86f6fb8
|
@ -43,43 +43,31 @@ fn (f &Fn) find_var(name string) Var {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn (f mut Fn) open_scope() {
|
fn (p mut Parser) open_scope() {
|
||||||
f.defer_text << ''
|
p.cur_fn.defer_text << ''
|
||||||
f.scope_level++
|
p.cur_fn.scope_level++
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (f mut Fn) close_scope() {
|
fn (p mut Parser) mark_var_used(v Var) {
|
||||||
f.scope_level--
|
for i, vv in p.cur_fn.local_vars {
|
||||||
f.defer_text = f.defer_text.left(f.scope_level + 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (f mut Fn) mark_var_used(v Var) {
|
|
||||||
for i, vv in f.local_vars {
|
|
||||||
if vv.name == v.name {
|
if vv.name == v.name {
|
||||||
//mut ptr := &f.local_vars[i]
|
p.cur_fn.local_vars[i].is_used = true
|
||||||
//ptr.is_used = true
|
|
||||||
f.local_vars[i].is_used = true
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (f mut Fn) mark_var_returned(v Var) {
|
fn (p mut Parser) mark_var_returned(v Var) {
|
||||||
for i, vv in f.local_vars {
|
for i, vv in p.cur_fn.local_vars {
|
||||||
if vv.name == v.name {
|
if vv.name == v.name {
|
||||||
f.local_vars[i].is_returned = true
|
p.cur_fn.local_vars[i].is_returned = true
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (f mut Fn) mark_var_changed(v Var) {
|
fn (p mut Parser) mark_var_changed(v Var) {
|
||||||
for i, vv in f.local_vars {
|
for i, vv in p.cur_fn.local_vars {
|
||||||
if vv.name == v.name {
|
if vv.name == v.name {
|
||||||
//mut ptr := &f.local_vars[i]
|
p.cur_fn.local_vars[i].is_changed = true
|
||||||
//ptr.is_used = true
|
|
||||||
f.local_vars[i].is_changed = true
|
|
||||||
// return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,8 +100,8 @@ fn (p mut Parser) is_sig() bool {
|
||||||
(p.file_path.contains(ModPath))
|
(p.file_path.contains(ModPath))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_fn(mod string, is_public bool) &Fn {
|
fn new_fn(mod string, is_public bool) Fn {
|
||||||
return &Fn {
|
return Fn {
|
||||||
mod: mod
|
mod: mod
|
||||||
local_vars: [Var{} ; MaxLocalVars]
|
local_vars: [Var{} ; MaxLocalVars]
|
||||||
is_public: is_public
|
is_public: is_public
|
||||||
|
@ -158,8 +146,9 @@ fn (p mut Parser) fn_decl() {
|
||||||
println('p.mod=$p.mod')
|
println('p.mod=$p.mod')
|
||||||
p.error('cannot define new methods on non-local type `$receiver_typ`')
|
p.error('cannot define new methods on non-local type `$receiver_typ`')
|
||||||
}
|
}
|
||||||
// (a *Foo) instead of (a mut Foo) is a common mistake
|
// `(f *Foo)` instead of `(f mut Foo)` is a common mistake
|
||||||
if !p.builtin_mod && receiver_typ.contains('*') {
|
//if !p.builtin_mod && receiver_typ.contains('*') {
|
||||||
|
if receiver_typ.contains('*') {
|
||||||
t := receiver_typ.replace('*', '')
|
t := receiver_typ.replace('*', '')
|
||||||
p.error('use `($receiver_name mut $t)` instead of `($receiver_name *$t)`')
|
p.error('use `($receiver_name mut $t)` instead of `($receiver_name *$t)`')
|
||||||
}
|
}
|
||||||
|
@ -463,7 +452,9 @@ _thread_so = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&reload_so, 0, 0, 0);
|
||||||
if p.pref.is_prof && f.name != 'main' && f.name != 'time__ticks' {
|
if p.pref.is_prof && f.name != 'main' && f.name != 'time__ticks' {
|
||||||
p.genln('double _PROF_START = time__ticks();//$f.name')
|
p.genln('double _PROF_START = time__ticks();//$f.name')
|
||||||
cgen_name := p.table.cgen_name(f)
|
cgen_name := p.table.cgen_name(f)
|
||||||
|
if f.defer_text.len > f.scope_level {
|
||||||
f.defer_text[f.scope_level] = ' ${cgen_name}_time += time__ticks() - _PROF_START;'
|
f.defer_text[f.scope_level] = ' ${cgen_name}_time += time__ticks() - _PROF_START;'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if is_generic {
|
if is_generic {
|
||||||
// Don't need to generate body for the actual generic definition
|
// Don't need to generate body for the actual generic definition
|
||||||
|
@ -477,7 +468,9 @@ _thread_so = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&reload_so, 0, 0, 0);
|
||||||
}
|
}
|
||||||
// Counting or not, always need to add defer before the end
|
// Counting or not, always need to add defer before the end
|
||||||
if !p.is_vweb {
|
if !p.is_vweb {
|
||||||
|
if f.defer_text.len > f.scope_level {
|
||||||
p.genln(f.defer_text[f.scope_level])
|
p.genln(f.defer_text[f.scope_level])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if typ != 'void' && !p.returns && f.name != 'main' && f.name != 'WinMain' {
|
if typ != 'void' && !p.returns && f.name != 'main' && f.name != 'WinMain' {
|
||||||
p.error('$f.name must return "$typ"')
|
p.error('$f.name must return "$typ"')
|
||||||
|
@ -658,7 +651,7 @@ fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type strin
|
||||||
p.error('`$p.expr_var.name` is immutable, declare it with `mut`')
|
p.error('`$p.expr_var.name` is immutable, declare it with `mut`')
|
||||||
}
|
}
|
||||||
if !p.expr_var.is_changed {
|
if !p.expr_var.is_changed {
|
||||||
p.cur_fn.mark_var_changed(p.expr_var)
|
p.mark_var_changed(p.expr_var)
|
||||||
}
|
}
|
||||||
// if receiver is key_mut or a ref (&), generate & for the first arg
|
// if receiver is key_mut or a ref (&), generate & for the first arg
|
||||||
if receiver.ref || (receiver.is_mut && !receiver_type.contains('*')) {
|
if receiver.ref || (receiver.is_mut && !receiver_type.contains('*')) {
|
||||||
|
@ -837,7 +830,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) &Fn {
|
||||||
p.error('`$arg.name` is a mutable argument, you need to provide a variable to modify: `$f.name(... mut a...)`')
|
p.error('`$arg.name` is a mutable argument, you need to provide a variable to modify: `$f.name(... mut a...)`')
|
||||||
}
|
}
|
||||||
if !v.is_changed {
|
if !v.is_changed {
|
||||||
p.cur_fn.mark_var_changed(v)
|
p.mark_var_changed(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.expected_type = arg.typ
|
p.expected_type = arg.typ
|
||||||
|
|
|
@ -40,7 +40,7 @@ mut:
|
||||||
expected_type string
|
expected_type string
|
||||||
tmp_cnt int
|
tmp_cnt int
|
||||||
is_script bool
|
is_script bool
|
||||||
pref &Preferences // Setting and Preferences shared from V struct
|
pref &Preferences // Preferences shared from V struct
|
||||||
builtin_mod bool
|
builtin_mod bool
|
||||||
vh_lines []string
|
vh_lines []string
|
||||||
inside_if_expr bool
|
inside_if_expr bool
|
||||||
|
@ -51,7 +51,7 @@ mut:
|
||||||
for_expr_cnt int // to detect whether `continue` can be used
|
for_expr_cnt int // to detect whether `continue` can be used
|
||||||
ptr_cast bool
|
ptr_cast bool
|
||||||
calling_c bool
|
calling_c bool
|
||||||
cur_fn &Fn
|
cur_fn Fn
|
||||||
returns bool
|
returns bool
|
||||||
vroot string
|
vroot string
|
||||||
is_c_struct_init bool
|
is_c_struct_init bool
|
||||||
|
@ -71,8 +71,8 @@ mut:
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
EmptyFn = &Fn { }
|
EmptyFn = Fn { }
|
||||||
MainFn= &Fn{name:'main'}
|
MainFn= Fn{name:'main'}
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -121,8 +121,9 @@ fn (v mut V) new_parser(path string) Parser {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) set_current_fn(f &Fn) {
|
fn (p mut Parser) set_current_fn(f Fn) {
|
||||||
p.cur_fn = f
|
p.cur_fn = f
|
||||||
|
//p.cur_fn = p.table.fns[f.name]
|
||||||
p.scanner.fn_name = '${f.mod}.${f.name}'
|
p.scanner.fn_name = '${f.mod}.${f.name}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -882,9 +883,10 @@ fn (p mut Parser) get_type() string {
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
mut warn := false
|
||||||
for p.tok == .mul {
|
for p.tok == .mul {
|
||||||
if p.first_pass() {
|
if p.first_pass() {
|
||||||
p.warn('use `&Foo` instead of `*Foo`')
|
warn = true
|
||||||
}
|
}
|
||||||
mul = true
|
mul = true
|
||||||
nr_muls++
|
nr_muls++
|
||||||
|
@ -908,6 +910,9 @@ fn (p mut Parser) get_type() string {
|
||||||
typ = p.lit
|
typ = p.lit
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if warn {
|
||||||
|
p.warn('use `&Foo` instead of `*Foo`')
|
||||||
|
}
|
||||||
// Module specified? (e.g. gx.Image)
|
// Module specified? (e.g. gx.Image)
|
||||||
if p.peek() == .dot {
|
if p.peek() == .dot {
|
||||||
// try resolve full submodule
|
// try resolve full submodule
|
||||||
|
@ -1010,7 +1015,7 @@ fn (p mut Parser) statements() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) statements_no_rcbr() string {
|
fn (p mut Parser) statements_no_rcbr() string {
|
||||||
p.cur_fn.open_scope()
|
p.open_scope()
|
||||||
|
|
||||||
if !p.inside_if_expr {
|
if !p.inside_if_expr {
|
||||||
p.genln('')
|
p.genln('')
|
||||||
|
@ -1055,39 +1060,45 @@ fn (p mut Parser) close_scope() {
|
||||||
mut i := p.cur_fn.var_idx - 1
|
mut i := p.cur_fn.var_idx - 1
|
||||||
for ; i >= 0; i-- {
|
for ; i >= 0; i-- {
|
||||||
v := p.cur_fn.local_vars[i]
|
v := p.cur_fn.local_vars[i]
|
||||||
|
//if p.cur_fn.name == 'main' {
|
||||||
|
//println('var in main $v.name $v.typ $v.is_alloc ptr=$v.ptr')
|
||||||
|
//}
|
||||||
if v.scope_level ≠ p.cur_fn.scope_level {
|
if v.scope_level ≠ p.cur_fn.scope_level {
|
||||||
// println('breaking. "$v.name" v.scope_level=$v.scope_level')
|
// println('breaking. "$v.name" v.scope_level=$v.scope_level')
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// Clean up memory, only do this for V compiler for now
|
// Clean up memory, only do this for V compiler for now
|
||||||
if p.pref.building_v && v.is_alloc && !p.pref.is_test {
|
if p.pref.building_v && v.is_alloc && !p.pref.is_test {
|
||||||
|
mut free_fn := 'free'
|
||||||
if v.typ.starts_with('array_') {
|
if v.typ.starts_with('array_') {
|
||||||
//if false && p.returns {
|
free_fn = 'v_array_free'
|
||||||
if p.returns {
|
} else if v.typ == 'string' {
|
||||||
if !v.is_returned {
|
free_fn = 'v_string_free'
|
||||||
prev_line := p.cgen.lines[p.cgen.lines.len-2]
|
continue
|
||||||
p.cgen.lines[p.cgen.lines.len-2] =
|
} else if v.ptr || v.typ.ends_with('*') {
|
||||||
'v_array_free($v.name); /* :) close_scope free */' + prev_line
|
free_fn = 'v_ptr_free'
|
||||||
}
|
//continue
|
||||||
} else {
|
} else {
|
||||||
p.genln('v_array_free($v.name); // close_scope free')
|
continue
|
||||||
|
}
|
||||||
|
//if false && p.returns {
|
||||||
|
if p.returns {
|
||||||
|
if !v.is_returned && v.typ != 'FILE*' { //!v.is_c {
|
||||||
|
prev_line := p.cgen.lines[p.cgen.lines.len-2]
|
||||||
|
p.cgen.lines[p.cgen.lines.len-2] =
|
||||||
|
'$free_fn($v.name); /* :) close_scope free $v.typ */' + prev_line
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else if v.typ == 'string' {
|
p.genln('$free_fn($v.name); // close_scope free')
|
||||||
//p.genln('v_string_free($v.name); // close_scope free')
|
|
||||||
}
|
|
||||||
else if v.ptr {
|
|
||||||
//p.genln('free($v.name); // close_scope free')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.cur_fn.defer_text.last() != '' {
|
if p.cur_fn.defer_text.last() != '' {
|
||||||
p.genln(p.cur_fn.defer_text.last())
|
p.genln(p.cur_fn.defer_text.last())
|
||||||
//p.cur_fn.defer_text[f] = ''
|
//p.cur_fn.defer_text[f] = ''
|
||||||
}
|
}
|
||||||
|
p.cur_fn.scope_level--
|
||||||
p.cur_fn.close_scope()
|
p.cur_fn.defer_text = p.cur_fn.defer_text.left(p.cur_fn.scope_level + 1)
|
||||||
p.cur_fn.var_idx = i + 1
|
p.cur_fn.var_idx = i + 1
|
||||||
// println('close_scope new var_idx=$f.var_idx\n')
|
// println('close_scope new var_idx=$f.var_idx\n')
|
||||||
}
|
}
|
||||||
|
@ -1225,7 +1236,7 @@ fn ($v.name mut $v.typ) $p.cur_fn.name (...) {
|
||||||
p.error('`$v.name` is immutable.')
|
p.error('`$v.name` is immutable.')
|
||||||
}
|
}
|
||||||
if !v.is_changed {
|
if !v.is_changed {
|
||||||
p.cur_fn.mark_var_changed(v)
|
p.mark_var_changed(v)
|
||||||
}
|
}
|
||||||
is_str := v.typ == 'string'
|
is_str := v.typ == 'string'
|
||||||
switch tok {
|
switch tok {
|
||||||
|
@ -1270,7 +1281,7 @@ fn ($v.name mut $v.typ) $p.cur_fn.name (...) {
|
||||||
// p.assigned_var = ''
|
// p.assigned_var = ''
|
||||||
p.assigned_type = ''
|
p.assigned_type = ''
|
||||||
if !v.is_used {
|
if !v.is_used {
|
||||||
p.cur_fn.mark_var_used(v)
|
p.mark_var_used(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1337,6 +1348,7 @@ fn (p mut Parser) var_decl() {
|
||||||
is_mut: is_mut
|
is_mut: is_mut
|
||||||
is_alloc: p.is_alloc
|
is_alloc: p.is_alloc
|
||||||
})
|
})
|
||||||
|
//if p.is_alloc { println('REG VAR IS ALLOC $name') }
|
||||||
if !or_else {
|
if !or_else {
|
||||||
gen_name := p.table.var_cgen_name(name)
|
gen_name := p.table.var_cgen_name(name)
|
||||||
mut nt_gen := p.table.cgen_name_type_pair(gen_name, typ)
|
mut nt_gen := p.table.cgen_name_type_pair(gen_name, typ)
|
||||||
|
@ -1544,7 +1556,7 @@ fn (p mut Parser) name_expr() string {
|
||||||
}
|
}
|
||||||
if p.inside_return_expr {
|
if p.inside_return_expr {
|
||||||
//println('marking $v.name returned')
|
//println('marking $v.name returned')
|
||||||
p.cur_fn.mark_var_returned(v)
|
p.mark_var_returned(v)
|
||||||
// v.is_returned = true // TODO modifying a local variable
|
// v.is_returned = true // TODO modifying a local variable
|
||||||
// that's not used afterwards, this should be a compilation
|
// that's not used afterwards, this should be a compilation
|
||||||
// error
|
// error
|
||||||
|
@ -1706,13 +1718,17 @@ fn (p mut Parser) name_expr() string {
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
p.log('end of name_expr')
|
p.log('end of name_expr')
|
||||||
|
|
||||||
|
if f.typ.ends_with('*') {
|
||||||
|
p.is_alloc = true
|
||||||
|
}
|
||||||
return f.typ
|
return f.typ
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) var_expr(v Var) string {
|
fn (p mut Parser) var_expr(v Var) string {
|
||||||
p.log('\nvar_expr() v.name="$v.name" v.typ="$v.typ"')
|
p.log('\nvar_expr() v.name="$v.name" v.typ="$v.typ"')
|
||||||
// println('var expr is_tmp=$p.cgen.is_tmp\n')
|
// println('var expr is_tmp=$p.cgen.is_tmp\n')
|
||||||
p.cur_fn.mark_var_used(v)
|
p.mark_var_used(v)
|
||||||
fn_ph := p.cgen.add_placeholder()
|
fn_ph := p.cgen.add_placeholder()
|
||||||
p.expr_var = v
|
p.expr_var = v
|
||||||
p.gen(p.table.var_cgen_name(v.name))
|
p.gen(p.table.var_cgen_name(v.name))
|
||||||
|
@ -1761,7 +1777,7 @@ fn (p mut Parser) var_expr(v Var) string {
|
||||||
p.error('`$v.name` is immutable')
|
p.error('`$v.name` is immutable')
|
||||||
}
|
}
|
||||||
if !v.is_changed {
|
if !v.is_changed {
|
||||||
p.cur_fn.mark_var_changed(v)
|
p.mark_var_changed(v)
|
||||||
}
|
}
|
||||||
if typ != 'int' {
|
if typ != 'int' {
|
||||||
if !p.pref.translated && !is_number_type(typ) {
|
if !p.pref.translated && !is_number_type(typ) {
|
||||||
|
@ -1895,6 +1911,9 @@ struct $f.parent_fn {
|
||||||
// if is_indexer {
|
// if is_indexer {
|
||||||
//return p.index_expr(method.typ, method_ph)
|
//return p.index_expr(method.typ, method_ph)
|
||||||
//}
|
//}
|
||||||
|
if method.typ.ends_with('*') {
|
||||||
|
p.is_alloc = true
|
||||||
|
}
|
||||||
return method.typ
|
return method.typ
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2148,7 +2167,7 @@ fn (p mut Parser) expression() string {
|
||||||
p.error('`$p.expr_var.name` is immutable (can\'t <<)')
|
p.error('`$p.expr_var.name` is immutable (can\'t <<)')
|
||||||
}
|
}
|
||||||
if !p.expr_var.is_changed {
|
if !p.expr_var.is_changed {
|
||||||
p.cur_fn.mark_var_changed(p.expr_var)
|
p.mark_var_changed(p.expr_var)
|
||||||
}
|
}
|
||||||
expr_type := p.expression()
|
expr_type := p.expression()
|
||||||
// Two arrays of the same type?
|
// Two arrays of the same type?
|
||||||
|
@ -2883,7 +2902,9 @@ fn (p mut Parser) struct_init(typ string, is_c_struct_init bool) string {
|
||||||
p.check(.rcbr)
|
p.check(.rcbr)
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
p.gen('($no_star*)memdup(&($no_star) {') //sizeof(Node));
|
p.gen('($no_star*)memdup(&($no_star) {')
|
||||||
|
p.is_alloc = true
|
||||||
|
//println('setting is_alloc=true (ret $typ)')
|
||||||
}
|
}
|
||||||
mut did_gen_something := false
|
mut did_gen_something := false
|
||||||
// Loop thru all struct init keys and assign values
|
// Loop thru all struct init keys and assign values
|
||||||
|
@ -3150,7 +3171,7 @@ fn (p mut Parser) for_st() {
|
||||||
p.for_expr_cnt++
|
p.for_expr_cnt++
|
||||||
next_tok := p.peek()
|
next_tok := p.peek()
|
||||||
//debug := p.scanner.file_path.contains('r_draw')
|
//debug := p.scanner.file_path.contains('r_draw')
|
||||||
p.cur_fn.open_scope()
|
p.open_scope()
|
||||||
if p.tok == .lcbr {
|
if p.tok == .lcbr {
|
||||||
// Infinite loop
|
// Infinite loop
|
||||||
p.gen('while (1) {')
|
p.gen('while (1) {')
|
||||||
|
@ -3703,7 +3724,7 @@ fn (p mut Parser) go_statement() {
|
||||||
if p.peek() == .dot {
|
if p.peek() == .dot {
|
||||||
var_name := p.lit
|
var_name := p.lit
|
||||||
v := p.cur_fn.find_var(var_name)
|
v := p.cur_fn.find_var(var_name)
|
||||||
p.cur_fn.mark_var_used(v)
|
p.mark_var_used(v)
|
||||||
p.next()
|
p.next()
|
||||||
p.check(.dot)
|
p.check(.dot)
|
||||||
typ := p.table.find_type(v.typ)
|
typ := p.table.find_type(v.typ)
|
||||||
|
|
|
@ -77,6 +77,7 @@ mut:
|
||||||
is_used bool
|
is_used bool
|
||||||
is_changed bool
|
is_changed bool
|
||||||
scope_level int
|
scope_level int
|
||||||
|
is_c bool // todo remove once `typ` is `Type`, not string
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Type {
|
struct Type {
|
||||||
|
@ -442,6 +443,7 @@ fn (table mut Table) add_method(type_name string, f Fn) {
|
||||||
print_backtrace()
|
print_backtrace()
|
||||||
cerror('add_method: empty type')
|
cerror('add_method: empty type')
|
||||||
}
|
}
|
||||||
|
// TODO table.typesmap[type_name].methods << f
|
||||||
mut t := table.typesmap[type_name]
|
mut t := table.typesmap[type_name]
|
||||||
t.methods << f
|
t.methods << f
|
||||||
table.typesmap[type_name] = t
|
table.typesmap[type_name] = t
|
||||||
|
|
|
@ -141,5 +141,9 @@ fn memdup(src voidptr, sz int) voidptr {
|
||||||
return C.memcpy(mem, src, sz)
|
return C.memcpy(mem, src, sz)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn v_ptr_free(ptr voidptr) {
|
||||||
|
C.free(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -236,7 +236,24 @@ pub fn (m map) print() {
|
||||||
println('>>>>>>>>>>')
|
println('>>>>>>>>>>')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (m map) free() {
|
fn (n mut mapnode) free() {
|
||||||
|
if n.val != 0 {
|
||||||
|
free(n.val)
|
||||||
|
}
|
||||||
|
if n.left != 0 {
|
||||||
|
n.left.free()
|
||||||
|
}
|
||||||
|
if n.right != 0 {
|
||||||
|
n.right.free()
|
||||||
|
}
|
||||||
|
free(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (m mut map) free() {
|
||||||
|
if m.root == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.root.free()
|
||||||
// C.free(m.table)
|
// C.free(m.table)
|
||||||
// C.free(m.keys_table)
|
// C.free(m.keys_table)
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,7 +156,7 @@ pub fn (s string) u64() u64 {
|
||||||
|
|
||||||
// ==
|
// ==
|
||||||
fn (s string) eq(a string) bool {
|
fn (s string) eq(a string) bool {
|
||||||
if isnil(s.str) {
|
if isnil(s.str) { // should never happen
|
||||||
panic('string.eq(): nil string')
|
panic('string.eq(): nil string')
|
||||||
}
|
}
|
||||||
if s.len != a.len {
|
if s.len != a.len {
|
||||||
|
|
|
@ -289,8 +289,7 @@ pub fn (f File) close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// system starts the specified command, waits for it to complete, and returns its code.
|
// system starts the specified command, waits for it to complete, and returns its code.
|
||||||
|
fn popen(path string) *C.FILE {
|
||||||
fn popen(path string) &FILE {
|
|
||||||
$if windows {
|
$if windows {
|
||||||
mode := 'rb'
|
mode := 'rb'
|
||||||
wpath := path.to_wide()
|
wpath := path.to_wide()
|
||||||
|
@ -302,7 +301,7 @@ fn popen(path string) &FILE {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pclose(f &FILE) int {
|
fn pclose(f *C.FILE) int {
|
||||||
$if windows {
|
$if windows {
|
||||||
return C._pclose(f)
|
return C._pclose(f)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue