cgen: autofree: first step

pull/4097/head
Alexander Medvednikov 2020-03-21 19:52:19 +01:00
parent efbf114a2f
commit e5f6a0949f
7 changed files with 127 additions and 37 deletions

View File

@ -42,6 +42,7 @@ pub fn make(len int, cap int, elm_size int) array {
// Private function, used by V (`nums := [1, 2, 3]`) // Private function, used by V (`nums := [1, 2, 3]`)
fn new_array_from_c_array(len, cap, elm_size int, c_array voidptr) array { fn new_array_from_c_array(len, cap, elm_size int, c_array voidptr) array {
cap_ := if cap == 0 { 1 } else { cap } cap_ := if cap == 0 { 1 } else { cap }
arr := array{ arr := array{
len: len len: len
cap: cap cap: cap
@ -377,7 +378,9 @@ pub fn (a []int) str() string {
mut sb := strings.new_builder(a.len * 13) mut sb := strings.new_builder(a.len * 13)
sb.write('[') sb.write('[')
for i in 0..a.len { for i in 0..a.len {
sb.write(a[i].str()) val := a[i].str()
sb.write(val)
val.free()
if i < a.len - 1 { if i < a.len - 1 {
sb.write(', ') sb.write(', ')
} }

View File

@ -2809,6 +2809,13 @@ fn (p mut Parser) array_init() string {
p.gen_array_init(real, no_alloc, new_arr_ph, i) p.gen_array_init(real, no_alloc, new_arr_ph, i)
typ = 'array_${stringify_pointer(typ)}' typ = 'array_${stringify_pointer(typ)}'
p.register_array(typ) p.register_array(typ)
if p.tok == .lcbr && i == 0 && p.peek() == .name {
// []string{len:10} (V2)
for p.tok != .rcbr {
p.next()
}
p.check(.rcbr)
}
return typ return typ
} }

View File

@ -20,7 +20,11 @@ fn C.symlink(charptr, charptr) int
fn init_os_args(argc int, argv &byteptr) []string { fn init_os_args(argc int, argv &byteptr) []string {
mut args := []string mut args := []string
//mut args := []string(make(0, argc, sizeof(string)))
//mut args := []string{len:argc}
for i in 0 .. argc { for i in 0 .. argc {
//args [i] = string(argv[i])
args << string(argv[i]) args << string(argv[i])
} }
return args return args

View File

@ -153,6 +153,7 @@ pub:
rec_mut bool // is receiver mutable rec_mut bool // is receiver mutable
is_c bool is_c bool
no_body bool // just a definition `fn C.malloc()` no_body bool // just a definition `fn C.malloc()`
pos token.Position
} }
pub struct BranchStmt { pub struct BranchStmt {

View File

@ -15,6 +15,7 @@ struct Gen {
inits strings.Builder // contents of `void _vinit(){}` inits strings.Builder // contents of `void _vinit(){}`
table &table.Table table &table.Table
mut: mut:
file ast.File
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0 fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
tmp_count int tmp_count int
varaidic_args map[string]int varaidic_args map[string]int
@ -26,6 +27,7 @@ mut:
inside_ternary bool // ?: comma separated statements on a single line inside_ternary bool // ?: comma separated statements on a single line
stmt_start_pos int stmt_start_pos int
right_is_opt bool right_is_opt bool
autofree bool
} }
pub fn cgen(files []ast.File, table &table.Table) string { pub fn cgen(files []ast.File, table &table.Table) string {
@ -37,9 +39,16 @@ pub fn cgen(files []ast.File, table &table.Table) string {
inits: strings.new_builder(100) inits: strings.new_builder(100)
table: table table: table
fn_decl: 0 fn_decl: 0
autofree: true
} }
g.init() g.init()
for file in files { for file in files {
// println('cgen "$g.file.path" $file.stmts.len')
g.file = file
if g.file.path == '' || g.file.path.ends_with('.vv') {
// cgen test
g.autofree = false
}
g.stmts(file.stmts) g.stmts(file.stmts)
} }
g.write_variadic_types() g.write_variadic_types()
@ -498,6 +507,9 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
if name == 'exit' { if name == 'exit' {
name = 'v_exit' name = 'v_exit'
} }
if name == 'free' {
name = 'v_free'
}
// type_name := g.table.type_to_str(it.return_type) // type_name := g.table.type_to_str(it.return_type)
type_name := g.typ(it.return_type) type_name := g.typ(it.return_type)
g.write('$type_name ${name}(') g.write('$type_name ${name}(')
@ -528,13 +540,31 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
} }
if is_main { if is_main {
g.writeln('_vinit();') g.writeln('_vinit();')
if g.autofree {
g.writeln('free(os__args.data); // empty, inited in _vinit()')
}
g.writeln('os__args = os__init_os_args(argc, (byteptr*)argv);') g.writeln('os__args = os__init_os_args(argc, (byteptr*)argv);')
} }
for stmt in it.stmts { for stmt in it.stmts {
// g.write('\t') // g.write('\t')
g.stmt(stmt) g.stmt(stmt)
} }
// ////////////
if g.autofree && false {
scope := g.file.scope.innermost(it.pos.pos - 1)
for i, var in scope.vars {
sym := g.table.get_type_symbol(var.typ)
if sym.kind == .array && !table.type_is_optional(var.typ) {
g.writeln('array_free($var.name); // autofree')
}
println(var.name)
}
}
// /////////
if is_main { if is_main {
if g.autofree {
g.writeln('_vcleanup();')
}
g.writeln('return 0;') g.writeln('return 0;')
} }
g.writeln('}') g.writeln('}')
@ -592,13 +622,18 @@ fn (g mut Gen) expr(node ast.Expr) {
if type_sym.kind != .array_fixed { if type_sym.kind != .array_fixed {
elem_sym := g.table.get_type_symbol(it.elem_type) elem_sym := g.table.get_type_symbol(it.elem_type)
elem_type_str := g.typ(it.elem_type) elem_type_str := g.typ(it.elem_type)
g.write('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($elem_type_str), ') if it.exprs.len == 0 {
g.writeln('($elem_type_str[]){\t') g.write('new_array($it.exprs.len, $it.exprs.len, sizeof($elem_type_str))')
for expr in it.exprs { }
g.expr(expr) else {
g.write(', ') g.write('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($elem_type_str), ')
g.writeln('($elem_type_str[]){\t')
for expr in it.exprs {
g.expr(expr)
g.write(', ')
}
g.write('\n})')
} }
g.write('\n})')
} }
else {} else {}
} }
@ -661,29 +696,7 @@ fn (g mut Gen) expr(node ast.Expr) {
g.write(it.val.str()) g.write(it.val.str())
} }
ast.CallExpr { ast.CallExpr {
mut name := it.name.replace('.', '__') g.call_expr(it)
if name == 'exit' {
name = 'v_exit'
}
if it.is_c {
// Skip "C__"
g.is_c_call = true
name = name[3..]
}
g.write('${name}(')
if name == 'println' && it.args[0].typ != table.string_type_idx {
// `println(int_str(10))`
// sym := g.table.get_type_symbol(it.args[0].typ)
styp := g.typ(it.args[0].typ)
g.write('${styp}_str(')
g.expr(it.args[0].expr)
g.write('))')
}
else {
g.call_args(it.args)
g.write(')')
}
g.is_c_call = false
} }
ast.CastExpr { ast.CastExpr {
// g.write('/*cast*/') // g.write('/*cast*/')
@ -1561,6 +1574,13 @@ fn (g mut Gen) write_init_function() {
g.writeln('void _vinit() {') g.writeln('void _vinit() {')
g.writeln(g.inits.str()) g.writeln(g.inits.str())
g.writeln('}') g.writeln('}')
if g.autofree {
g.writeln('void _vcleanup() {')
g.writeln('puts("cleaning up...");')
g.writeln('free(os__args.data);')
g.writeln('free(strconv__ftoa__powers_of_10.data);')
g.writeln('}')
}
} }
fn (g mut Gen) write_str_definitions() { fn (g mut Gen) write_str_definitions() {
@ -1737,13 +1757,13 @@ fn (g mut Gen) string_inter_literal(node ast.StringInterLiteral) {
} }
// TODO: fix match, sum type false positive // TODO: fix match, sum type false positive
// match node.expr_types[i] { // match node.expr_types[i] {
// table.string_type { // table.string_type {
// g.write('%.*s') // g.write('%.*s')
// } // }
// table.int_type { // table.int_type {
// g.write('%d') // g.write('%d')
// } // }
// else {} // else {}
// } // }
if node.expr_types[i] == table.string_type { if node.expr_types[i] == table.string_type {
g.write('%.*s') g.write('%.*s')
@ -1802,6 +1822,59 @@ fn (g mut Gen) gen_filter(node ast.MethodCallExpr) {
g.write(tmp) g.write(tmp)
} }
fn (g mut Gen) call_expr(it ast.CallExpr) {
mut name := it.name.replace('.', '__')
if name == 'exit' {
name = 'v_exit'
}
if name == 'free' {
name = 'v_free'
}
is_print := name == 'println'
if it.is_c {
// Skip "C__"
g.is_c_call = true
name = name[3..]
}
// Generate tmp vars for values that have to be freed.
mut tmps := []string
/*
for arg in it.args {
if arg.typ == table.string_type_idx || is_print {
tmp := g.new_tmp_var()
tmps << tmp
g.write('string $tmp = ')
g.expr(arg.expr)
g.writeln('; //memory')
}
}
*/
if is_print && it.args[0].typ != table.string_type_idx {
styp := g.typ(it.args[0].typ)
if g.autofree {
tmp := g.new_tmp_var()
// tmps << tmp
g.write('string $tmp = ${styp}_str(')
g.expr(it.args[0].expr)
g.writeln('); println($tmp); string_free($tmp); //MEM2')
}
else {
// `println(int_str(10))`
// sym := g.table.get_type_symbol(it.args[0].typ)
g.write('println(${styp}_str(')
g.expr(it.args[0].expr)
g.write('))')
}
}
else {
g.write('${name}(')
g.call_args(it.args)
g.write(')')
}
g.is_c_call = false
}
// `a in [1,2,3]` => `a == 1 || a == 2 || a == 3` // `a in [1,2,3]` => `a == 1 || a == 2 || a == 3`
fn (g mut Gen) in_optimization(left ast.Expr, right ast.ArrayInit) { fn (g mut Gen) in_optimization(left ast.Expr, right ast.ArrayInit) {
is_str := right.elem_type == table.string_type is_str := right.elem_type == table.string_type

View File

@ -189,6 +189,7 @@ byte g_str_buf[1024];
int load_so(byteptr); int load_so(byteptr);
void reload_so(); void reload_so();
void _vinit(); void _vinit();
void _vcleanup();
// ============== wyhash ============== // ============== wyhash ==============
// Author: Wang Yi // Author: Wang Yi

View File

@ -177,6 +177,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
rec_mut: rec_mut rec_mut: rec_mut
is_c: is_c is_c: is_c
no_body: no_body no_body: no_body
pos: p.tok.position()
} }
} }