compiler: free local_vars

pull/2089/head
Alexander Medvednikov 2019-09-23 20:34:08 +03:00
parent 0e39df24d4
commit 8d52d877fb
7 changed files with 118 additions and 85 deletions

View File

@ -18,8 +18,8 @@ struct Fn {
mut: mut:
name string name string
mod string mod string
local_vars []Var //local_vars []Var
var_idx int //var_idx int
args []Var args []Var
is_interface bool is_interface bool
// called_fns []string // called_fns []string
@ -36,19 +36,19 @@ mut:
//gen_types []string //gen_types []string
} }
fn (f &Fn) find_var(name string) ?Var { fn (p &Parser) find_var(name string) ?Var {
for i in 0 .. f.var_idx { for i in 0 .. p.var_idx {
if f.local_vars[i].name == name { if p.local_vars[i].name == name {
return f.local_vars[i] return p.local_vars[i]
} }
} }
return none return none
} }
fn (p &Parser) find_var_check_new_var(name string) ?Var { fn (p &Parser) find_var_check_new_var(name string) ?Var {
for i in 0 .. p.cur_fn.var_idx { for i in 0 .. p.var_idx {
if p.cur_fn.local_vars[i].name == name { if p.local_vars[i].name == name {
return p.cur_fn.local_vars[i] return p.local_vars[i]
} }
} }
// A hack to allow `newvar := Foo{ field: newvar }` // 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) { 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 { 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) { 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 { 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) { 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 { 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 { fn (p mut Parser) known_var(name string) bool {
_ := f.find_var(name) or { _ := p.find_var(name) or {
return false return false
} }
return true return true
} }
fn (f mut Fn) register_var(v Var) { fn (p mut Parser) register_var(v Var) {
new_var := {v | scope_level: f.scope_level} 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 // Expand the array
if f.var_idx >= f.local_vars.len { if p.var_idx >= p.local_vars.len {
f.local_vars << new_var p.local_vars << new_var
} }
else { 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() { fn (p mut Parser) clear_vars() {
f.var_idx = 0 // shared a := [1, 2, 3]
f.local_vars = []Var p.var_idx = 0
p.local_vars.free()
p.local_vars = []Var
} }
// vlib header file? // vlib header file?
@ -122,30 +129,25 @@ 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 {
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. // Function signatures are added to the top of the .c file in the first run.
fn (p mut Parser) fn_decl() { fn (p mut Parser) fn_decl() {
p.clear_vars() // clear local vars every time a new fn is started
p.fgen('fn ') p.fgen('fn ')
//defer { p.fgenln('\n') } //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 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 { 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') println('INFO: run `v -live program.v` if you want to use [live] functions')
} }
if is_pub { if f.is_public {
p.next() p.next()
} }
p.returns = false p.returns = false
//p.gen('/* returns $p.returns */') //p.gen('/* returns $p.returns */')
p.next() p.next()
mut f := new_fn(p.mod, is_pub)
// Method receiver // Method receiver
mut receiver_typ := '' mut receiver_typ := ''
if p.tok == .lpar { if p.tok == .lpar {
@ -191,7 +193,7 @@ fn (p mut Parser) fn_decl() {
scanner_pos: p.scanner.get_scanner_pos() scanner_pos: p.scanner.get_scanner_pos()
} }
f.args << receiver f.args << receiver
f.register_var(receiver) p.register_var(receiver)
} }
if p.tok == .plus || p.tok == .minus || p.tok == .mul { if p.tok == .plus || p.tok == .minus || p.tok == .mul {
f.name = p.tok.str() f.name = p.tok.str()
@ -279,7 +281,7 @@ fn (p mut Parser) fn_decl() {
if typ.starts_with('MultiReturn_') { if typ.starts_with('MultiReturn_') {
if !p.first_pass() && !p.table.known_type(typ) { if !p.first_pass() && !p.table.known_type(typ) {
p.table.register_type2(Type{ p.table.register_type2(Type{
cat: TypeCategory.struct_, cat: TypeCategory.struct_,
name: typ, name: typ,
mod: p.mod 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() { fn (p mut Parser) check_unused_variables() {
for var in p.cur_fn.local_vars { for var in p.local_vars {
if var.name == '' { if var.name == '' {
break break
} }
@ -737,9 +739,7 @@ fn (p mut Parser) fn_args(f mut Fn) {
} }
// `(a int, b, c string)` syntax // `(a int, b, c string)` syntax
for p.tok != .rpar { for p.tok != .rpar {
mut names := [ mut names := [ p.check_name() ]
p.check_name()
]
// `a,b,c int` syntax // `a,b,c int` syntax
for p.tok == .comma { for p.tok == .comma {
p.check(.comma) p.check(.comma)
@ -773,7 +773,7 @@ fn (p mut Parser) fn_args(f mut Fn) {
line_nr: p.scanner.line_nr line_nr: p.scanner.line_nr
scanner_pos: p.scanner.get_scanner_pos() scanner_pos: p.scanner.get_scanner_pos()
} }
f.register_var(v) p.register_var(v)
f.args << v f.args << v
} }
if p.tok == .comma { if p.tok == .comma {
@ -861,7 +861,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) &Fn {
} }
p.check(.key_mut) p.check(.key_mut)
var_name := p.lit 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...)`') p.error('`$arg.name` is a mutable argument, you need to provide a variable to modify: `$f.name(... mut a...)`')
exit(1) exit(1)
} }
@ -1065,18 +1065,18 @@ fn (f &Fn) str_args(table &Table) string {
} }
// find local function variable with closest name to `name` // 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 := f32(0)
mut closest_var := '' mut closest_var := ''
for var in f.local_vars { for var in p.local_vars {
if var.scope_level > f.scope_level { if var.scope_level > p.cur_fn.scope_level {
continue continue
} }
n := name.all_after('.') n := name.all_after('.')
if var.name == '' || (n.len - var.name.len > 2 || var.name.len - n.len > 2) { continue } if var.name == '' || (n.len - var.name.len > 2 || var.name.len - n.len > 2) { continue }
p := strings.dice_coefficient(var.name, n) coeff := strings.dice_coefficient(var.name, n)
if p > closest { if coeff > closest {
closest = p closest = coeff
closest_var = var.name closest_var = var.name
} }
} }

View File

@ -193,7 +193,7 @@ fn main() {
v.cgen.lines.free() v.cgen.lines.free()
free(v.cgen) free(v.cgen)
for _, f in v.table.fns { for _, f in v.table.fns {
f.local_vars.free() //f.local_vars.free()
f.args.free() f.args.free()
//f.defer_text.free() //f.defer_text.free()
} }

View File

@ -51,6 +51,8 @@ mut:
ptr_cast bool ptr_cast bool
calling_c bool calling_c bool
cur_fn Fn cur_fn Fn
local_vars []Var // local function variables
var_idx int
returns bool returns bool
vroot string vroot string
is_c_struct_init bool is_c_struct_init bool
@ -107,6 +109,7 @@ fn (v mut V) new_parser(path string) Parser {
pref: v.pref pref: v.pref
os: v.os os: v.os
vroot: v.vroot vroot: v.vroot
local_vars: [Var{}].repeat(MaxLocalVars)
} }
$if js { $if js {
@ -303,7 +306,7 @@ fn (p mut Parser) parse(pass Pass) {
if p.cur_fn.name == '' { if p.cur_fn.name == '' {
p.set_current_fn( MainFn ) p.set_current_fn( MainFn )
if p.pref.is_repl { if p.pref.is_repl {
p.cur_fn.clear_vars() p.clear_vars()
} }
} }
mut start := p.cgen.lines.len mut start := p.cgen.lines.len
@ -848,18 +851,18 @@ fn (p mut Parser) get_type() string {
// multiple returns // multiple returns
if p.tok == .lpar { if p.tok == .lpar {
// if p.inside_tuple {p.error('unexpected (')} // if p.inside_tuple {p.error('unexpected (')}
// p.inside_tuple = true // p.inside_tuple = true
p.check(.lpar) p.check(.lpar)
mut types := []string mut types := []string
for { for {
types << p.get_type() types << p.get_type()
if p.tok != .comma { if p.tok != .comma {
break break
} }
p.check(.comma) p.check(.comma)
} }
p.check(.rpar) p.check(.rpar)
// p.inside_tuple = false // p.inside_tuple = false
return 'MultiReturn_' + types.join('_Z_').replace('*', '_ZptrZ_') return 'MultiReturn_' + types.join('_Z_').replace('*', '_ZptrZ_')
} }
// fn type // 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 // Move back `var_idx` (pointer to the end of the array) till we reach
// the previous scope level. This effectivly deletes (closes) current // the previous scope level. This effectivly deletes (closes) current
// scope. // scope.
mut i := p.cur_fn.var_idx - 1 mut i := p.var_idx - 1
for ; i >= 0; i-- { for ; i >= 0; i-- {
v := p.cur_fn.local_vars[i] v := p.local_vars[i]
//if p.cur_fn.name == 'main' { //if p.cur_fn.name == 'main' {
//println('var in main $v.name $v.typ $v.is_alloc ptr=$v.ptr') //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.scope_level--
p.cur_fn.defer_text = p.cur_fn.defer_text.left(p.cur_fn.scope_level + 1) 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') // 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) p.check(.colon)
return '' return ''
} }
// `a := 777` // `a := 777`
else if p.peek() == .decl_assign || p.peek() == .comma { else if p.peek() == .decl_assign || p.peek() == .comma {
p.log('var decl') p.log('var decl')
p.var_decl() p.var_decl()
@ -1385,7 +1388,7 @@ fn (p mut Parser) var_decl() {
// p.var_decl_name = name // p.var_decl_name = name
// Don't allow declaring a variable with the same name. Even in a child scope // Don't allow declaring a variable with the same name. Even in a child scope
// (shadowing is not allowed) // (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) // v := p.cur_fn.find_var(name)
p.error('redefinition of `$name`') p.error('redefinition of `$name`')
} }
@ -1563,7 +1566,7 @@ fn (p mut Parser) name_expr() string {
// module ? // module ?
// (Allow shadowing `gg = gg.newcontext(); gg.draw_triangle();` ) // (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)) 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 mut mod := name
// must be aliased module // must be aliased module
if name != p.mod && p.import_table.known_alias(name) { if name != p.mod && p.import_table.known_alias(name) {
@ -1577,7 +1580,7 @@ fn (p mut Parser) name_expr() string {
p.fgen(name) p.fgen(name)
name = prepend_mod(mod, 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 { !p.table.known_fn(name) && !p.table.known_const(name) && !is_c {
name = p.prepend_mod(name) name = p.prepend_mod(name)
} }
@ -1713,7 +1716,7 @@ fn (p mut Parser) name_expr() string {
//f = p.table.find_fn(name) //f = p.table.find_fn(name)
} }
// check for misspelled function / variable / module // 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 != '' { if suggested != '' {
p.error('undefined: `$name`. did you mean:$suggested') p.error('undefined: `$name`. did you mean:$suggested')
} }
@ -2478,7 +2481,7 @@ fn (p mut Parser) assoc() string {
// println('assoc()') // println('assoc()')
p.next() p.next()
name := p.check_name() name := p.check_name()
var := p.cur_fn.find_var(name) or { var := p.find_var(name) or {
p.error('unknown variable `$name`') p.error('unknown variable `$name`')
exit(1) exit(1)
} }
@ -3649,7 +3652,7 @@ fn (p mut Parser) go_statement() {
// Method // Method
if p.peek() == .dot { if p.peek() == .dot {
var_name := p.lit 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.mark_var_used(v)
p.next() p.next()
p.check(.dot) p.check(.dot)
@ -3667,14 +3670,16 @@ fn (p mut Parser) go_statement() {
} }
} }
/*
fn (p mut Parser) register_var(v Var) { fn (p mut Parser) register_var(v Var) {
if v.line_nr == 0 { if v.line_nr == 0 {
spos := p.scanner.get_scanner_pos() 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 { } else {
p.cur_fn.register_var(v) p.register_var(v)
} }
} }
*/
// user:=jsdecode(User, user_json_string) // user:=jsdecode(User, user_json_string)
fn (p mut Parser) js_decode() string { fn (p mut Parser) js_decode() string {

View File

@ -84,7 +84,7 @@ fn (p mut Parser) select_query(fn_ph int) string {
if field.typ != 'string' && field.typ != 'int' { if field.typ != 'string' && field.typ != 'int' {
continue continue
} }
p.cur_fn.register_var({ field | is_used:true }) p.register_var({ field | is_used:true })
} }
q += table_name q += table_name
// `where` statement // `where` statement
@ -194,7 +194,7 @@ fn (p mut Parser) insert_query(fn_ph int) {
p.check(.lpar) p.check(.lpar)
var_name := p.check_name() var_name := p.check_name()
p.check(.rpar) 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) typ := p.table.find_type(var.typ)
mut fields := []Var mut fields := []Var
for i, field in typ.fields { for i, field in typ.fields {

View File

@ -924,24 +924,24 @@ fn (t &Type) contains_field_type(typ string) bool {
} }
// check for a function / variable / module typo in `name` // 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 // dont check if so short
if name.len < 2 { return '' } if name.len < 2 { return '' }
min_match := 0.50 // for dice coefficient between 0.0 - 1.0 min_match := 0.50 // for dice coefficient between 0.0 - 1.0
name_orig := name.replace('__', '.').replace('_dot_', '.') name_orig := name.replace('__', '.').replace('_dot_', '.')
mut output := '' mut output := ''
// check functions // 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 != '' { if n != '' {
output += '\n * function: `$n`' output += '\n * function: `$n`'
} }
// check function local variables // 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 != '' { if n != '' {
output += '\n * variable: `$n`' output += '\n * variable: `$n`'
} }
// check imported modules // 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 != '' { if n != '' {
output += '\n * module: `$n`' output += '\n * module: `$n`'
} }

View File

@ -18,6 +18,9 @@ pub:
// Private function, used by V (`nums := []int`) // Private function, used by V (`nums := []int`)
fn new_array(mylen, cap, elm_size int) array { fn new_array(mylen, cap, elm_size int) array {
a := 3
_ := a
//println(a)
arr := array { arr := array {
len: mylen len: mylen
cap: cap cap: cap

View File

@ -1,5 +1,7 @@
import ui import (
import gx ui
gx
)
const ( const (
NR_COLS = 3 NR_COLS = 3
@ -25,12 +27,13 @@ struct Context {
} }
/* /*
// Current V
struct Window { struct Window {
width: 500 width: 500
height: 300 height: 300
title: 'Users' title: 'Users'
content: Layout { body: Layout {
[ body: [
TextBox { TextBox {
placeholder: 'First name' 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() {` // TODO replace with `fn (ctx mut Context) btn_click() {`
fn btn_click(_ctx &Context) { fn btn_click(_ctx &Context) {
println('users.v: button click')
mut ctx := _ctx// TODO hack mut ctx := _ctx// TODO hack
ctx.users << User { ctx.users << User {
first_name: ctx.first_name.text() first_name: ctx.first_name.text()