1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

free arrays when they are out of scope

main.v: update help
This commit is contained in:
Alexander Medvednikov 2019-07-21 12:43:47 +02:00
parent 385f1c856e
commit 40c31f701f
5 changed files with 53 additions and 35 deletions

View File

@ -46,23 +46,6 @@ fn (f mut Fn) open_scope() {
f.scope_level++ 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) { fn (f &Fn) mark_var_used(v Var) {
for i, vv in f.local_vars { for i, vv in f.local_vars {
if vv.name == v.name { 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.scanner.line_nr = var.line_nr - 1
p.error('`$var.name` declared and not used') 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.register() => "User_register(user)"
// user.say_hi() => "User_say_hi(user)" // method_ph - where to insert "user_register("
// method_ph - where to insert "user_say_hi("
// receiver_var - "user" (needed for pthreads) // receiver_var - "user" (needed for pthreads)
// receiver_type - "User" // receiver_type - "User"
fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type string) { fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type string) {

View File

@ -977,7 +977,7 @@ fn new_v(args[]string) *V {
if os.dir_exists(vroot) && os.dir_exists(vroot + '/vlib/builtin') { if os.dir_exists(vroot) && os.dir_exists(vroot + '/vlib/builtin') {
} else { } 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.') println('Go to https://vlang.io to install V.')
exit(1) exit(1)
} }

View File

@ -27,6 +27,7 @@ mut:
is_global bool // __global (translated from C only) is_global bool // __global (translated from C only)
is_used bool is_used bool
scope_level int scope_level int
is_alloc bool
} }
struct Parser { struct Parser {
@ -69,6 +70,7 @@ mut:
attr string attr string
v_script bool // "V bash", import all os functions into global space 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 var_decl_name string // To allow declaring the variable so that it can be used in the struct initialization
building_v bool
} }
const ( const (
@ -96,6 +98,9 @@ fn (c mut V) new_parser(path string, run Pass) Parser {
os: c.os os: c.os
run: run run: run
vroot: c.vroot vroot: c.vroot
building_v: !c.pref.is_repl && (path.contains('compiler/') ||
path.contains('v/vlib'))
} }
p.next() p.next()
// p.scanner.debug_tokens() // p.scanner.debug_tokens()
@ -214,8 +219,9 @@ fn (p mut Parser) parse() {
// $if, $else // $if, $else
p.comp_time() p.comp_time()
case Token.key_global: case Token.key_global:
if !p.pref.translated && !p.pref.is_live && !p.builtin_pkg && !p.building_v() { if !p.pref.translated && !p.pref.is_live &&
//p.error('__global is only allowed in translated code') !p.builtin_pkg && !p.building_v {
p.error('__global is only allowed in translated code')
} }
p.next() p.next()
name := p.check_name() name := p.check_name()
@ -988,10 +994,35 @@ fn (p mut Parser) statements_no_curly_end() string {
} }
//p.fmt_dec() //p.fmt_dec()
// println('close scope line=$p.scanner.line_nr') // println('close scope line=$p.scanner.line_nr')
p.cur_fn.close_scope() p.close_scope()
return last_st_typ 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) { fn (p mut Parser) genln(s string) {
p.cgen.genln(s) p.cgen.genln(s)
} }
@ -1221,6 +1252,7 @@ fn (p mut Parser) var_decl() {
name: name name: name
typ: typ typ: typ
is_mut: is_mut is_mut: is_mut
is_alloc: typ.starts_with('array_')
}) })
mut cgen_typ := typ mut cgen_typ := typ
if !or_else { if !or_else {
@ -3115,7 +3147,7 @@ fn (p mut Parser) for_st() {
p.check(.lcbr) p.check(.lcbr)
p.genln('') p.genln('')
p.statements() p.statements()
p.cur_fn.close_scope() p.close_scope()
p.for_expr_cnt-- p.for_expr_cnt--
} }
@ -3228,7 +3260,7 @@ fn (p mut Parser) return_st() {
else { else {
ret := p.cgen.cur_line.right(ph) ret := p.cgen.cur_line.right(ph)
p.cgen(p.cur_fn.defer_text) 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') p.cgen.resetln('return $ret')
} else { } else {
tmp := p.get_tmp() tmp := p.get_tmp()
@ -3369,10 +3401,12 @@ fn is_compile_time_const(s string) bool {
return true return true
} }
/*
fn (p &Parser) building_v() bool { fn (p &Parser) building_v() bool {
cur_dir := os.getwd() cur_dir := os.getwd()
return p.file_path.contains('v/compiler') || cur_dir.contains('v/compiler') return p.file_path.contains('v/compiler') || cur_dir.contains('v/compiler')
} }
*/
fn (p mut Parser) attribute() { fn (p mut Parser) attribute() {
p.check(.lsbr) p.check(.lsbr)

View File

@ -5,13 +5,15 @@
module builtin module builtin
struct array { struct array {
is_slice bool
pub:
// Using a void pointer allows to implement arrays without generics and without generating // Using a void pointer allows to implement arrays without generics and without generating
// extra code for every type. // extra code for every type.
pub:
data voidptr data voidptr
len int len int
cap int cap int
element_size int element_size int
} }
// Private function, used by V (`nums := []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 data: s.data + start * s.element_size
len: l len: l
cap: l cap: l
is_slice: true
} }
return res return res
} }
@ -215,7 +218,11 @@ pub fn (a []int) str() string {
return res 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) C.free(a.data)
} }

View File

@ -716,12 +716,14 @@ pub fn (s string) free() {
C.free(s.str) C.free(s.str)
} }
/*
fn (arr []string) free() { fn (arr []string) free() {
for s in arr { for s in arr {
s.free() s.free()
} }
C.free(arr.data) C.free(arr.data)
} }
*/
// all_before('23:34:45.234', '.') == '23:34:45' // all_before('23:34:45.234', '.') == '23:34:45'
pub fn (s string) all_before(dot string) string { pub fn (s string) all_before(dot string) string {