From 40c31f701facefe92a69865fa9d4db948c7aacde Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Sun, 21 Jul 2019 12:43:47 +0200 Subject: [PATCH] free arrays when they are out of scope main.v: update help --- compiler/fn.v | 29 ++-------------------------- compiler/main.v | 2 +- compiler/parser.v | 44 ++++++++++++++++++++++++++++++++++++++----- vlib/builtin/array.v | 11 +++++++++-- vlib/builtin/string.v | 2 ++ 5 files changed, 53 insertions(+), 35 deletions(-) diff --git a/compiler/fn.v b/compiler/fn.v index 84fab3610d..8f5dde0e18 100644 --- a/compiler/fn.v +++ b/compiler/fn.v @@ -46,23 +46,6 @@ fn (f mut Fn) open_scope() { f.scope_level++ } -fn (f mut Fn) close_scope() { - // println('close_scope level=$f.scope_level var_idx=$f.var_idx') - // Move back `var_idx` (pointer to the end of the array) till we reach the previous scope level. - // This effectivly deletes (closes) current scope. - mut i := f.var_idx - 1 - for; i >= 0; i-- { - v := f.local_vars[i] - if v.scope_level != f.scope_level { - // println('breaking. "$v.name" v.scope_level=$v.scope_level') - break - } - } - f.var_idx = i + 1 - // println('close_scope new var_idx=$f.var_idx\n') - f.scope_level-- -} - fn (f &Fn) mark_var_used(v Var) { for i, vv in f.local_vars { if vv.name == v.name { @@ -432,19 +415,11 @@ fn (p mut Parser) check_unused_variables() { p.scanner.line_nr = var.line_nr - 1 p.error('`$var.name` declared and not used') } - // Very basic automatic memory management at the end of the function. - // This is inserted right before the final `}`, so if the object is being returned, - // the free method will not be called. - if p.pref.is_test && var.typ.contains('array_') { - // p.genln('v_${var.typ}_free($var.name); // !!!! XAXA') - // p.genln('free(${var.name}.data); // !!!! XAXA') - } } } -// Important function with 5 args. -// user.say_hi() => "User_say_hi(user)" -// method_ph - where to insert "user_say_hi(" +// user.register() => "User_register(user)" +// method_ph - where to insert "user_register(" // receiver_var - "user" (needed for pthreads) // receiver_type - "User" fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type string) { diff --git a/compiler/main.v b/compiler/main.v index e3a7fb5176..34b8084a2f 100644 --- a/compiler/main.v +++ b/compiler/main.v @@ -977,7 +977,7 @@ fn new_v(args[]string) *V { if os.dir_exists(vroot) && os.dir_exists(vroot + '/vlib/builtin') { } else { - println('vlib not found. It should be next to V executable. ') + println('vlib not found. It should be next to the V executable. ') println('Go to https://vlang.io to install V.') exit(1) } diff --git a/compiler/parser.v b/compiler/parser.v index ccc99c28b1..51d076ee00 100644 --- a/compiler/parser.v +++ b/compiler/parser.v @@ -27,6 +27,7 @@ mut: is_global bool // __global (translated from C only) is_used bool scope_level int + is_alloc bool } struct Parser { @@ -69,6 +70,7 @@ mut: attr string v_script bool // "V bash", import all os functions into global space var_decl_name string // To allow declaring the variable so that it can be used in the struct initialization + building_v bool } const ( @@ -96,6 +98,9 @@ fn (c mut V) new_parser(path string, run Pass) Parser { os: c.os run: run vroot: c.vroot + building_v: !c.pref.is_repl && (path.contains('compiler/') || + path.contains('v/vlib')) + } p.next() // p.scanner.debug_tokens() @@ -214,8 +219,9 @@ fn (p mut Parser) parse() { // $if, $else p.comp_time() case Token.key_global: - if !p.pref.translated && !p.pref.is_live && !p.builtin_pkg && !p.building_v() { - //p.error('__global is only allowed in translated code') + if !p.pref.translated && !p.pref.is_live && + !p.builtin_pkg && !p.building_v { + p.error('__global is only allowed in translated code') } p.next() name := p.check_name() @@ -988,10 +994,35 @@ fn (p mut Parser) statements_no_curly_end() string { } //p.fmt_dec() // println('close scope line=$p.scanner.line_nr') - p.cur_fn.close_scope() + p.close_scope() return last_st_typ } +fn (p mut Parser) close_scope() { + // println('close_scope level=$f.scope_level var_idx=$f.var_idx') + // Move back `var_idx` (pointer to the end of the array) till we reach the previous scope level. + // This effectivly deletes (closes) current scope. + mut i := p.cur_fn.var_idx - 1 + for; i >= 0; i-- { + v := p.cur_fn.local_vars[i] + if v.scope_level != p.cur_fn.scope_level { + // println('breaking. "$v.name" v.scope_level=$v.scope_level') + break + } + if !p.building_v && !v.is_mut && v.is_alloc { + if v.typ.starts_with('array_') { + p.genln('v_array_free($v.name); // close_scope free') + } + else { + p.genln('free($v.name); // close_scope free') + } + } + } + p.cur_fn.var_idx = i + 1 + // println('close_scope new var_idx=$f.var_idx\n') + p.cur_fn.scope_level-- +} + fn (p mut Parser) genln(s string) { p.cgen.genln(s) } @@ -1221,6 +1252,7 @@ fn (p mut Parser) var_decl() { name: name typ: typ is_mut: is_mut + is_alloc: typ.starts_with('array_') }) mut cgen_typ := typ if !or_else { @@ -3115,7 +3147,7 @@ fn (p mut Parser) for_st() { p.check(.lcbr) p.genln('') p.statements() - p.cur_fn.close_scope() + p.close_scope() p.for_expr_cnt-- } @@ -3228,7 +3260,7 @@ fn (p mut Parser) return_st() { else { ret := p.cgen.cur_line.right(ph) p.cgen(p.cur_fn.defer_text) - if expr_type == 'void*' { + if p.cur_fn.defer_text == '' || expr_type == 'void*' { p.cgen.resetln('return $ret') } else { tmp := p.get_tmp() @@ -3369,10 +3401,12 @@ fn is_compile_time_const(s string) bool { return true } +/* fn (p &Parser) building_v() bool { cur_dir := os.getwd() return p.file_path.contains('v/compiler') || cur_dir.contains('v/compiler') } +*/ fn (p mut Parser) attribute() { p.check(.lsbr) diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index 3edb566f28..5de3a0d2c3 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -5,13 +5,15 @@ module builtin struct array { + is_slice bool +pub: // Using a void pointer allows to implement arrays without generics and without generating // extra code for every type. -pub: data voidptr len int cap int element_size int + } // Private function, used by V (`nums := []int`) @@ -144,6 +146,7 @@ pub fn (s array) slice(start, _end int) array { data: s.data + start * s.element_size len: l cap: l + is_slice: true } return res } @@ -215,7 +218,11 @@ pub fn (a []int) str() string { return res } -pub fn (a []int) free() { +//pub fn (a []int) free() { +pub fn (a array) free() { + if a.is_slice { + return + } C.free(a.data) } diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 9b2b682766..64c84804b3 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -716,12 +716,14 @@ pub fn (s string) free() { C.free(s.str) } +/* fn (arr []string) free() { for s in arr { s.free() } C.free(arr.data) } +*/ // all_before('23:34:45.234', '.') == '23:34:45' pub fn (s string) all_before(dot string) string {