From 8d52d877fb213a83e8e68272ca792dbc8e51dbfa Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Mon, 23 Sep 2019 20:34:08 +0300 Subject: [PATCH] compiler: free local_vars --- compiler/fn.v | 102 ++++++++++++++--------------- compiler/main.v | 2 +- compiler/parser.v | 47 +++++++------ compiler/query.v | 4 +- compiler/table.v | 8 +-- vlib/builtin/array.v | 3 + vlib/ui/examples/users_gui/users.v | 37 +++++++++-- 7 files changed, 118 insertions(+), 85 deletions(-) diff --git a/compiler/fn.v b/compiler/fn.v index 22f7b79dfb..1d7f5da466 100644 --- a/compiler/fn.v +++ b/compiler/fn.v @@ -18,8 +18,8 @@ struct Fn { mut: name string mod string - local_vars []Var - var_idx int + //local_vars []Var + //var_idx int args []Var is_interface bool // called_fns []string @@ -36,19 +36,19 @@ mut: //gen_types []string } -fn (f &Fn) find_var(name string) ?Var { - for i in 0 .. f.var_idx { - if f.local_vars[i].name == name { - return f.local_vars[i] +fn (p &Parser) find_var(name string) ?Var { + for i in 0 .. p.var_idx { + if p.local_vars[i].name == name { + return p.local_vars[i] } } return none } fn (p &Parser) find_var_check_new_var(name string) ?Var { - for i in 0 .. p.cur_fn.var_idx { - if p.cur_fn.local_vars[i].name == name { - return p.cur_fn.local_vars[i] + for i in 0 .. p.var_idx { + if p.local_vars[i].name == name { + return p.local_vars[i] } } // A hack to allow `newvar := Foo{ field: newvar }` @@ -69,51 +69,58 @@ fn (p mut Parser) open_scope() { } fn (p mut Parser) mark_var_used(v Var) { - for i, vv in p.cur_fn.local_vars { + for i, vv in p.local_vars { if vv.name == v.name { - p.cur_fn.local_vars[i].is_used = true + p.local_vars[i].is_used = true } } } fn (p mut Parser) mark_var_returned(v Var) { - for i, vv in p.cur_fn.local_vars { + for i, vv in p.local_vars { if vv.name == v.name { - p.cur_fn.local_vars[i].is_returned = true + p.local_vars[i].is_returned = true } } } fn (p mut Parser) mark_var_changed(v Var) { - for i, vv in p.cur_fn.local_vars { + for i, vv in p.local_vars { if vv.name == v.name { - p.cur_fn.local_vars[i].is_changed = true + p.local_vars[i].is_changed = true } } } -fn (f mut Fn) known_var(name string) bool { - _ := f.find_var(name) or { +fn (p mut Parser) known_var(name string) bool { + _ := p.find_var(name) or { return false } return true } -fn (f mut Fn) register_var(v Var) { - new_var := {v | scope_level: f.scope_level} +fn (p mut Parser) register_var(v Var) { + mut new_var := {v | scope_level: p.cur_fn.scope_level} + if v.line_nr == 0 { + spos := p.scanner.get_scanner_pos() + new_var.scanner_pos = spos + new_var.line_nr = spos.line_nr + } // Expand the array - if f.var_idx >= f.local_vars.len { - f.local_vars << new_var + if p.var_idx >= p.local_vars.len { + p.local_vars << new_var } else { - f.local_vars[f.var_idx] = new_var + p.local_vars[p.var_idx] = new_var } - f.var_idx++ + p.var_idx++ } -fn (f mut Fn) clear_vars() { - f.var_idx = 0 - f.local_vars = []Var +fn (p mut Parser) clear_vars() { + // shared a := [1, 2, 3] + p.var_idx = 0 + p.local_vars.free() + p.local_vars = []Var } // vlib header file? @@ -122,30 +129,25 @@ fn (p mut Parser) is_sig() bool { (p.file_path.contains(ModPath)) } -fn new_fn(mod string, is_public bool) Fn { - return Fn { - mod: mod - local_vars: [Var{}].repeat(MaxLocalVars) - is_public: is_public - } -} - // Function signatures are added to the top of the .c file in the first run. fn (p mut Parser) fn_decl() { + p.clear_vars() // clear local vars every time a new fn is started p.fgen('fn ') //defer { p.fgenln('\n') } - is_pub := p.tok == .key_pub + mut f := Fn { + mod: p.mod + is_public: p.tok == .key_pub + } is_live := p.attr == 'live' && !p.pref.is_so && p.pref.is_live if p.attr == 'live' && p.first_pass() && !p.pref.is_live && !p.pref.is_so { println('INFO: run `v -live program.v` if you want to use [live] functions') } - if is_pub { + if f.is_public { p.next() } p.returns = false //p.gen('/* returns $p.returns */') p.next() - mut f := new_fn(p.mod, is_pub) // Method receiver mut receiver_typ := '' if p.tok == .lpar { @@ -191,7 +193,7 @@ fn (p mut Parser) fn_decl() { scanner_pos: p.scanner.get_scanner_pos() } f.args << receiver - f.register_var(receiver) + p.register_var(receiver) } if p.tok == .plus || p.tok == .minus || p.tok == .mul { f.name = p.tok.str() @@ -279,7 +281,7 @@ fn (p mut Parser) fn_decl() { if typ.starts_with('MultiReturn_') { if !p.first_pass() && !p.table.known_type(typ) { p.table.register_type2(Type{ - cat: TypeCategory.struct_, + cat: TypeCategory.struct_, name: typ, mod: p.mod }) @@ -542,7 +544,7 @@ _thread_so = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&reload_so, 0, 0, 0); } fn (p mut Parser) check_unused_variables() { - for var in p.cur_fn.local_vars { + for var in p.local_vars { if var.name == '' { break } @@ -737,9 +739,7 @@ fn (p mut Parser) fn_args(f mut Fn) { } // `(a int, b, c string)` syntax for p.tok != .rpar { - mut names := [ - p.check_name() - ] + mut names := [ p.check_name() ] // `a,b,c int` syntax for p.tok == .comma { p.check(.comma) @@ -773,7 +773,7 @@ fn (p mut Parser) fn_args(f mut Fn) { line_nr: p.scanner.line_nr scanner_pos: p.scanner.get_scanner_pos() } - f.register_var(v) + p.register_var(v) f.args << v } if p.tok == .comma { @@ -861,7 +861,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) &Fn { } p.check(.key_mut) var_name := p.lit - v := p.cur_fn.find_var(var_name) or { + v := p.find_var(var_name) or { p.error('`$arg.name` is a mutable argument, you need to provide a variable to modify: `$f.name(... mut a...)`') exit(1) } @@ -1065,18 +1065,18 @@ fn (f &Fn) str_args(table &Table) string { } // find local function variable with closest name to `name` -fn (f &Fn) find_misspelled_local_var(name string, min_match f32) string { +fn (p &Parser) find_misspelled_local_var(name string, min_match f32) string { mut closest := f32(0) mut closest_var := '' - for var in f.local_vars { - if var.scope_level > f.scope_level { + for var in p.local_vars { + if var.scope_level > p.cur_fn.scope_level { continue } n := name.all_after('.') if var.name == '' || (n.len - var.name.len > 2 || var.name.len - n.len > 2) { continue } - p := strings.dice_coefficient(var.name, n) - if p > closest { - closest = p + coeff := strings.dice_coefficient(var.name, n) + if coeff > closest { + closest = coeff closest_var = var.name } } diff --git a/compiler/main.v b/compiler/main.v index f1bf471c1d..aa4a8549ec 100644 --- a/compiler/main.v +++ b/compiler/main.v @@ -193,7 +193,7 @@ fn main() { v.cgen.lines.free() free(v.cgen) for _, f in v.table.fns { - f.local_vars.free() + //f.local_vars.free() f.args.free() //f.defer_text.free() } diff --git a/compiler/parser.v b/compiler/parser.v index c702e8a6ff..6a5f80241e 100644 --- a/compiler/parser.v +++ b/compiler/parser.v @@ -51,6 +51,8 @@ mut: ptr_cast bool calling_c bool cur_fn Fn + local_vars []Var // local function variables + var_idx int returns bool vroot string is_c_struct_init bool @@ -107,6 +109,7 @@ fn (v mut V) new_parser(path string) Parser { pref: v.pref os: v.os vroot: v.vroot + local_vars: [Var{}].repeat(MaxLocalVars) } $if js { @@ -303,7 +306,7 @@ fn (p mut Parser) parse(pass Pass) { if p.cur_fn.name == '' { p.set_current_fn( MainFn ) if p.pref.is_repl { - p.cur_fn.clear_vars() + p.clear_vars() } } mut start := p.cgen.lines.len @@ -848,18 +851,18 @@ fn (p mut Parser) get_type() string { // multiple returns if p.tok == .lpar { // if p.inside_tuple {p.error('unexpected (')} - // p.inside_tuple = true - p.check(.lpar) - mut types := []string + // p.inside_tuple = true + p.check(.lpar) + mut types := []string for { types << p.get_type() if p.tok != .comma { - break - } - p.check(.comma) + break + } + p.check(.comma) } - p.check(.rpar) - // p.inside_tuple = false + p.check(.rpar) + // p.inside_tuple = false return 'MultiReturn_' + types.join('_Z_').replace('*', '_ZptrZ_') } // fn type @@ -1110,9 +1113,9 @@ fn (p mut Parser) close_scope() { // 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 + mut i := p.var_idx - 1 for ; i >= 0; i-- { - v := p.cur_fn.local_vars[i] + v := p.local_vars[i] //if p.cur_fn.name == 'main' { //println('var in main $v.name $v.typ $v.is_alloc ptr=$v.ptr') //} @@ -1152,7 +1155,7 @@ fn (p mut Parser) close_scope() { } p.cur_fn.scope_level-- 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.var_idx = i + 1 // println('close_scope new var_idx=$f.var_idx\n') } @@ -1191,7 +1194,7 @@ fn (p mut Parser) statement(add_semi bool) string { p.check(.colon) return '' } - // `a := 777` + // `a := 777` else if p.peek() == .decl_assign || p.peek() == .comma { p.log('var decl') p.var_decl() @@ -1385,7 +1388,7 @@ fn (p mut Parser) var_decl() { // p.var_decl_name = name // Don't allow declaring a variable with the same name. Even in a child scope // (shadowing is not allowed) - if !p.builtin_mod && p.cur_fn.known_var(name) { + if !p.builtin_mod && p.known_var(name) { // v := p.cur_fn.find_var(name) p.error('redefinition of `$name`') } @@ -1563,7 +1566,7 @@ fn (p mut Parser) name_expr() string { // module ? // (Allow shadowing `gg = gg.newcontext(); gg.draw_triangle();` ) if p.peek() == .dot && ((name == p.mod && p.table.known_mod(name)) || p.import_table.known_alias(name)) - && !p.cur_fn.known_var(name) && !is_c { + && !p.known_var(name) && !is_c { mut mod := name // must be aliased module if name != p.mod && p.import_table.known_alias(name) { @@ -1577,7 +1580,7 @@ fn (p mut Parser) name_expr() string { p.fgen(name) name = prepend_mod(mod, name) } - else if !p.table.known_type(name) && !p.cur_fn.known_var(name) && + else if !p.table.known_type(name) && !p.known_var(name) && !p.table.known_fn(name) && !p.table.known_const(name) && !is_c { name = p.prepend_mod(name) } @@ -1713,7 +1716,7 @@ fn (p mut Parser) name_expr() string { //f = p.table.find_fn(name) } // check for misspelled function / variable / module - suggested := p.table.identify_typo(name, p.cur_fn, p.import_table) + suggested := p.identify_typo(name, p.import_table) if suggested != '' { p.error('undefined: `$name`. did you mean:$suggested') } @@ -2478,7 +2481,7 @@ fn (p mut Parser) assoc() string { // println('assoc()') p.next() name := p.check_name() - var := p.cur_fn.find_var(name) or { + var := p.find_var(name) or { p.error('unknown variable `$name`') exit(1) } @@ -3649,7 +3652,7 @@ fn (p mut Parser) go_statement() { // Method if p.peek() == .dot { var_name := p.lit - v := p.cur_fn.find_var(var_name) or { return } + v := p.find_var(var_name) or { return } p.mark_var_used(v) p.next() p.check(.dot) @@ -3667,14 +3670,16 @@ fn (p mut Parser) go_statement() { } } +/* fn (p mut Parser) register_var(v Var) { if v.line_nr == 0 { spos := p.scanner.get_scanner_pos() - p.cur_fn.register_var({ v | scanner_pos: spos, line_nr: spos.line_nr }) + p.register_var({ v | scanner_pos: spos, line_nr: spos.line_nr }) } else { - p.cur_fn.register_var(v) + p.register_var(v) } } +*/ // user:=jsdecode(User, user_json_string) fn (p mut Parser) js_decode() string { diff --git a/compiler/query.v b/compiler/query.v index 4ab00bdc4a..c57853701e 100644 --- a/compiler/query.v +++ b/compiler/query.v @@ -84,7 +84,7 @@ fn (p mut Parser) select_query(fn_ph int) string { if field.typ != 'string' && field.typ != 'int' { continue } - p.cur_fn.register_var({ field | is_used:true }) + p.register_var({ field | is_used:true }) } q += table_name // `where` statement @@ -194,7 +194,7 @@ fn (p mut Parser) insert_query(fn_ph int) { p.check(.lpar) var_name := p.check_name() p.check(.rpar) - var := p.cur_fn.find_var(var_name) or { return } + var := p.find_var(var_name) or { return } typ := p.table.find_type(var.typ) mut fields := []Var for i, field in typ.fields { diff --git a/compiler/table.v b/compiler/table.v index 6c755bc685..9c422bafc5 100644 --- a/compiler/table.v +++ b/compiler/table.v @@ -924,24 +924,24 @@ fn (t &Type) contains_field_type(typ string) bool { } // check for a function / variable / module typo in `name` -fn (table &Table) identify_typo(name string, current_fn &Fn, fit &FileImportTable) string { +fn (p &Parser) identify_typo(name string, fit &FileImportTable) string { // dont check if so short if name.len < 2 { return '' } min_match := 0.50 // for dice coefficient between 0.0 - 1.0 name_orig := name.replace('__', '.').replace('_dot_', '.') mut output := '' // check functions - mut n := table.find_misspelled_fn(name, fit, min_match) + mut n := p.table.find_misspelled_fn(name, fit, min_match) if n != '' { output += '\n * function: `$n`' } // check function local variables - n = current_fn.find_misspelled_local_var(name_orig, min_match) + n = p.find_misspelled_local_var(name_orig, min_match) if n != '' { output += '\n * variable: `$n`' } // check imported modules - n = table.find_misspelled_imported_mod(name_orig, fit, min_match) + n = p.table.find_misspelled_imported_mod(name_orig, fit, min_match) if n != '' { output += '\n * module: `$n`' } diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index 9b3be586b7..5a02df49d3 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -18,6 +18,9 @@ pub: // Private function, used by V (`nums := []int`) fn new_array(mylen, cap, elm_size int) array { + a := 3 + _ := a + //println(a) arr := array { len: mylen cap: cap diff --git a/vlib/ui/examples/users_gui/users.v b/vlib/ui/examples/users_gui/users.v index ef428fc6c1..eb26a3aa86 100644 --- a/vlib/ui/examples/users_gui/users.v +++ b/vlib/ui/examples/users_gui/users.v @@ -1,5 +1,7 @@ -import ui -import gx +import ( + ui + gx +) const ( NR_COLS = 3 @@ -25,12 +27,13 @@ struct Context { } /* +// Current V struct Window { width: 500 height: 300 title: 'Users' - content: Layout { - [ + body: Layout { + body: [ TextBox { placeholder: 'First name' }, @@ -46,9 +49,30 @@ struct Window { }, ] } +} + +// Improved V +struct Window { + width: 500 + height: 300 + title: 'Users' - draw: { - + Layout { + [ + TextBox { + placeholder: 'First name' + } + TextBox { + placeholder: 'Last name' + } + TextBox { + placeholder: 'Age' + } + Button { + title: 'Add user' + onclick: btn_click + } + ] } } @@ -102,6 +126,7 @@ fn main() { // TODO replace with `fn (ctx mut Context) btn_click() {` fn btn_click(_ctx &Context) { + println('users.v: button click') mut ctx := _ctx// TODO hack ctx.users << User { first_name: ctx.first_name.text()