mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
compiler: v -autofree can now compile itself
This commit is contained in:
parent
2b0f2be18b
commit
f638caef39
@ -212,6 +212,12 @@ fn (a array) slice2(start, _end int, end_max bool) array {
|
||||
return a.slice(start, end)
|
||||
}
|
||||
|
||||
// array.clone_static returns an independent copy of a given array
|
||||
// It should be used only in -autofree generated code.
|
||||
fn (a array) clone_static() array {
|
||||
return a.clone()
|
||||
}
|
||||
|
||||
// array.clone returns an independent copy of a given array
|
||||
pub fn (a &array) clone() array {
|
||||
mut size := a.cap * a.element_size
|
||||
@ -304,7 +310,7 @@ pub fn (a array) reverse() array {
|
||||
|
||||
// pub fn (a []int) free() {
|
||||
[unsafe_fn]
|
||||
pub fn (a array) free() {
|
||||
pub fn (a &array) free() {
|
||||
// if a.is_slice {
|
||||
// return
|
||||
// }
|
||||
|
@ -98,11 +98,17 @@ pub fn (a array) reverse() array {
|
||||
return a
|
||||
}
|
||||
|
||||
// array.clone_static returns an independent copy of a given array
|
||||
// It should be used only in -autofree generated code.
|
||||
fn (a array) clone_static() array {
|
||||
return a.clone()
|
||||
}
|
||||
|
||||
pub fn (a array) clone() array {
|
||||
return a
|
||||
}
|
||||
|
||||
pub fn (a array) free() {
|
||||
pub fn (a &array) free() {
|
||||
}
|
||||
|
||||
// "[ 'a', 'b', 'c' ]"
|
||||
|
@ -26,6 +26,11 @@ pub fn tos(s byteptr) string {
|
||||
}
|
||||
}
|
||||
|
||||
// string.clone_static returns an independent copy of a given array
|
||||
// It should be used only in -autofree generated code.
|
||||
fn (a string) clone_static() string {
|
||||
return a.clone()
|
||||
}
|
||||
|
||||
pub fn (a string) clone() string {
|
||||
return a
|
||||
@ -241,18 +246,9 @@ pub fn (c byte) is_letter() bool {
|
||||
return (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`)
|
||||
}
|
||||
|
||||
pub fn (s string) free() {
|
||||
pub fn (s &string) free() {
|
||||
}
|
||||
|
||||
/*
|
||||
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 {
|
||||
pos := s.index(dot)
|
||||
|
@ -413,7 +413,7 @@ pub fn (m &map) keys() []string {
|
||||
}
|
||||
|
||||
[unsafe_fn]
|
||||
pub fn (m map) free() {
|
||||
pub fn (m &map) free() {
|
||||
free(m.metas)
|
||||
for i := u32(0); i < m.key_values.size; i++ {
|
||||
if m.key_values.keys[i].str == 0 {
|
||||
|
@ -104,6 +104,12 @@ pub fn tos3(s charptr) string {
|
||||
}
|
||||
}
|
||||
|
||||
// string.clone_static returns an independent copy of a given array
|
||||
// It should be used only in -autofree generated code.
|
||||
fn (a string) clone_static() string {
|
||||
return a.clone()
|
||||
}
|
||||
|
||||
pub fn (a string) clone() string {
|
||||
mut b := string{
|
||||
len: a.len
|
||||
@ -1141,7 +1147,7 @@ pub fn (u ustring) at(idx int) string {
|
||||
return u.substr(idx, idx + 1)
|
||||
}
|
||||
|
||||
fn (u ustring) free() {
|
||||
fn (u &ustring) free() {
|
||||
u.runes.free()
|
||||
}
|
||||
|
||||
@ -1165,19 +1171,10 @@ pub fn (c byte) is_letter() bool {
|
||||
return (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`)
|
||||
}
|
||||
|
||||
pub fn (s string) free() {
|
||||
pub fn (s &string) free() {
|
||||
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 {
|
||||
pos := s.index(dot) or {
|
||||
|
@ -278,6 +278,7 @@ pub:
|
||||
name string
|
||||
expr Expr
|
||||
is_mut bool
|
||||
is_arg bool // fn args should not be autofreed
|
||||
mut:
|
||||
typ table.Type
|
||||
pos token.Position
|
||||
|
@ -134,12 +134,12 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||
for file in files {
|
||||
g.file = file
|
||||
// println('\ncgen "$g.file.path" nr_stmts=$file.stmts.len')
|
||||
building_v := true && (g.file.path.contains('/vlib/') || g.file.path.contains('cmd/v'))
|
||||
// building_v := true && (g.file.path.contains('/vlib/') || g.file.path.contains('cmd/v'))
|
||||
is_test := g.file.path.ends_with('.vv') || g.file.path.ends_with('_test.v')
|
||||
if g.file.path.ends_with('_test.v') {
|
||||
g.is_test = is_test
|
||||
}
|
||||
if g.file.path == '' || is_test || building_v || !g.pref.autofree {
|
||||
if g.file.path == '' || is_test || !g.pref.autofree {
|
||||
// cgen test or building V
|
||||
// println('autofree=false')
|
||||
g.autofree = false
|
||||
@ -646,6 +646,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
}
|
||||
ast.Return {
|
||||
g.write_defer_stmts_when_needed()
|
||||
g.write_autofree_stmts_when_needed(it)
|
||||
g.return_statement(it)
|
||||
}
|
||||
ast.StructDecl {
|
||||
@ -980,7 +981,7 @@ fn (mut g Gen) gen_clone_assignment(val ast.Expr, right_sym table.TypeSymbol, ad
|
||||
if add_eq {
|
||||
g.write('=')
|
||||
}
|
||||
g.write(' array_clone(&')
|
||||
g.write(' array_clone_static(')
|
||||
g.expr(val)
|
||||
g.write(')')
|
||||
} else if g.autofree && right_sym.kind == .string && is_ident {
|
||||
@ -988,15 +989,16 @@ fn (mut g Gen) gen_clone_assignment(val ast.Expr, right_sym table.TypeSymbol, ad
|
||||
g.write('=')
|
||||
}
|
||||
// `str1 = str2` => `str1 = str2.clone()`
|
||||
g.write(' string_clone(')
|
||||
g.write(' string_clone_static(')
|
||||
g.expr(val)
|
||||
g.write(')')
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fn (mut g Gen) free_scope_vars(pos int) {
|
||||
println('free_scope_vars($pos)')
|
||||
fn (mut g Gen) autofree_scope_vars(pos int) string {
|
||||
// eprintln('> free_scope_vars($pos)')
|
||||
mut freeing_code := ''
|
||||
scope := g.file.scope.innermost(pos)
|
||||
for _, obj in scope.objects {
|
||||
match obj {
|
||||
@ -1006,34 +1008,56 @@ fn (mut g Gen) free_scope_vars(pos int) {
|
||||
// continue
|
||||
// }
|
||||
v := *it
|
||||
println(v.name)
|
||||
// println(v.typ)
|
||||
sym := g.table.get_type_symbol(v.typ)
|
||||
is_optional := v.typ.flag_is(.optional)
|
||||
if sym.kind == .array && !is_optional {
|
||||
g.writeln('\tarray_free($v.name); // autofreed')
|
||||
}
|
||||
if sym.kind == .string && !is_optional {
|
||||
// Don't free simple string literals.
|
||||
t := typeof(v.expr)
|
||||
match v.expr {
|
||||
ast.StringLiteral {
|
||||
g.writeln('// str literal')
|
||||
continue
|
||||
}
|
||||
else {
|
||||
// NOTE/TODO: assign_stmt multi returns variables have no expr
|
||||
// since the type comes from the called fns return type
|
||||
g.writeln('// other ' + t)
|
||||
continue
|
||||
}
|
||||
}
|
||||
g.writeln('string_free($v.name); // autofreed')
|
||||
if is_optional {
|
||||
// TODO: free optionals
|
||||
continue
|
||||
}
|
||||
freeing_code += g.autofree_variable(v)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
return freeing_code
|
||||
}
|
||||
|
||||
fn (g &Gen) autofree_variable(v ast.Var) string {
|
||||
sym := g.table.get_type_symbol(v.typ)
|
||||
// eprintln(' > var name: ${v.name:-20s} | is_arg: ${v.is_arg.str():6} | var type: ${int(v.typ):8} | type_name: ${sym.name:-33s}')
|
||||
if sym.kind == .array {
|
||||
return g.autofree_var_call('array_free', v)
|
||||
}
|
||||
if sym.kind == .string {
|
||||
// Don't free simple string literals.
|
||||
t := typeof(v.expr)
|
||||
match v.expr {
|
||||
ast.StringLiteral {
|
||||
return '// str literal\n'
|
||||
}
|
||||
else {
|
||||
// NOTE/TODO: assign_stmt multi returns variables have no expr
|
||||
// since the type comes from the called fns return type
|
||||
return '// other ' + t + '\n'
|
||||
}
|
||||
}
|
||||
return g.autofree_var_call('string_free', v)
|
||||
}
|
||||
if sym.has_method('free') {
|
||||
return g.autofree_var_call(c_name(sym.name) + '_free', v)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
fn (g &Gen) autofree_var_call(free_fn_name string, v ast.Var) string {
|
||||
if v.is_arg {
|
||||
// fn args should not be autofreed
|
||||
return ''
|
||||
}
|
||||
if v.typ.is_ptr() {
|
||||
return '\t${free_fn_name}($v.name); // autofreed ptr var\n'
|
||||
}else{
|
||||
return '\t${free_fn_name}(&$v.name); // autofreed var\n'
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) expr(node ast.Expr) {
|
||||
@ -2221,10 +2245,10 @@ fn (mut g Gen) write_init_function() {
|
||||
g.writeln('void _vcleanup() {')
|
||||
// g.writeln('puts("cleaning up...");')
|
||||
if g.is_importing_os() {
|
||||
g.writeln('free(_const_os__args.data);')
|
||||
g.writeln('string_free(_const_os__wd_at_startup);')
|
||||
g.writeln('array_free(&_const_os__args);')
|
||||
g.writeln('string_free(&_const_os__wd_at_startup);')
|
||||
}
|
||||
g.writeln('free(_const_strconv__ftoa__powers_of_10.data);')
|
||||
g.writeln('array_free(&_const_strconv__ftoa__powers_of_10);')
|
||||
g.writeln('}')
|
||||
}
|
||||
}
|
||||
@ -3215,7 +3239,7 @@ fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp, str_fn_name string) {
|
||||
g.auto_str_funcs.writeln('\tstring tmp1 = string_add(tos3("${styp}("), tos3(${typename}_str((${convertor})it).str));')
|
||||
}
|
||||
g.auto_str_funcs.writeln('\tstring tmp2 = string_add(tmp1, tos3(")"));')
|
||||
g.auto_str_funcs.writeln('\tstring_free(tmp1);')
|
||||
g.auto_str_funcs.writeln('\tstring_free(&tmp1);')
|
||||
g.auto_str_funcs.writeln('\treturn tmp2;')
|
||||
g.auto_str_funcs.writeln('}')
|
||||
}
|
||||
@ -3324,7 +3348,7 @@ fn (mut g Gen) gen_str_for_array(info table.Array, styp, str_fn_name string) {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, x);')
|
||||
if g.pref.autofree && info.elem_type != table.bool_type {
|
||||
// no need to free "true"/"false" literals
|
||||
g.auto_str_funcs.writeln('\t\tstring_free(x);')
|
||||
g.auto_str_funcs.writeln('\t\tstring_free(&x);')
|
||||
}
|
||||
g.auto_str_funcs.writeln('\t\tif (i < a.len-1) {')
|
||||
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write(&sb, tos3(", "));')
|
||||
|
@ -159,11 +159,6 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
|
||||
}
|
||||
g.stmts(it.stmts)
|
||||
// ////////////
|
||||
if g.autofree {
|
||||
// println('\n\ncalling free for fn $it.name')
|
||||
g.free_scope_vars(it.body_pos.pos)
|
||||
}
|
||||
// /////////
|
||||
if is_main {
|
||||
if g.autofree {
|
||||
g.writeln('\t_vcleanup();')
|
||||
@ -173,6 +168,11 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
|
||||
}
|
||||
}
|
||||
g.write_defer_stmts_when_needed()
|
||||
// /////////
|
||||
if g.autofree {
|
||||
// TODO: remove this, when g.write_autofree_stmts_when_needed works properly
|
||||
g.writeln( g.autofree_scope_vars(it.body_pos.pos) )
|
||||
}
|
||||
if is_main {
|
||||
g.writeln('\treturn 0;')
|
||||
}
|
||||
@ -183,6 +183,17 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) write_autofree_stmts_when_needed(r ast.Return) {
|
||||
// TODO: write_autofree_stmts_when_needed should account for the current local scope vars.
|
||||
// TODO: write_autofree_stmts_when_needed should not free the returned variables.
|
||||
// It may require rewriting g.return_statement to assign the expressions
|
||||
// to temporary variables, then protecting *them* from autofreeing ...
|
||||
g.writeln('/* autofreeings before return: -------')
|
||||
//g.write( g.autofree_scope_vars(r.pos.pos) )
|
||||
g.write( g.autofree_scope_vars(g.fn_decl.body_pos.pos) )
|
||||
g.writeln('--------------------------------------------------- */')
|
||||
}
|
||||
|
||||
fn (mut g Gen) write_defer_stmts_when_needed() {
|
||||
if g.defer_stmts.len > 0 {
|
||||
g.write_defer_stmts()
|
||||
@ -440,7 +451,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||
// tmps << tmp
|
||||
g.write('string $tmp = ${str_fn_name}(')
|
||||
g.expr(node.args[0].expr)
|
||||
g.writeln('); ${print_method}($tmp); string_free($tmp); //MEM2 $styp')
|
||||
g.writeln('); ${print_method}($tmp); string_free(&$tmp); //MEM2 $styp')
|
||||
} else {
|
||||
expr := node.args[0].expr
|
||||
is_var := match expr {
|
||||
|
@ -175,6 +175,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
is_mut: arg.is_mut
|
||||
pos: p.tok.position()
|
||||
is_used: true
|
||||
is_arg: true
|
||||
})
|
||||
// Do not allow `mut` with simple types
|
||||
// TODO move to checker?
|
||||
@ -280,6 +281,7 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
|
||||
typ: arg.typ
|
||||
pos: p.tok.position()
|
||||
is_used: true
|
||||
is_arg: true
|
||||
})
|
||||
}
|
||||
mut return_type := table.void_type
|
||||
|
Loading…
Reference in New Issue
Block a user