memory fixes: 21% of V compiler leaks fixed
parent
9b9c1cc834
commit
956bf23390
|
@ -73,7 +73,7 @@ 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 := 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
|
||||
|
@ -454,7 +454,7 @@ fn (g mut Gen) for_in(it ast.ForInStmt) {
|
|||
g.write('; $i < ')
|
||||
g.expr(it.high)
|
||||
g.writeln('; $i++) { ')
|
||||
g.writeln('int $it.val_var = $i;')
|
||||
g.writeln('\tint $it.val_var = $i;')
|
||||
g.stmts(it.stmts)
|
||||
g.writeln('}')
|
||||
}
|
||||
|
@ -467,7 +467,7 @@ fn (g mut Gen) for_in(it ast.ForInStmt) {
|
|||
g.write('for (int $i = 0; $i < ')
|
||||
g.expr(it.cond)
|
||||
g.writeln('.len; $i++) {')
|
||||
g.write('$styp $it.val_var = (($styp*)')
|
||||
g.write('\t$styp $it.val_var = (($styp*)')
|
||||
g.expr(it.cond)
|
||||
g.writeln('.data)[$i];')
|
||||
g.stmts(it.stmts)
|
||||
|
@ -486,8 +486,8 @@ fn (g mut Gen) for_in(it ast.ForInStmt) {
|
|||
g.expr(it.cond)
|
||||
g.writeln(');')
|
||||
g.writeln('for (int $idx = 0; $idx < ${keys_tmp}.len; $idx++) {')
|
||||
g.writeln('$key_styp $key = (($key_styp*)${keys_tmp}.data)[$idx];')
|
||||
g.write('$val_styp $it.val_var = (*($val_styp*)map_get3(')
|
||||
g.writeln('\t$key_styp $key = (($key_styp*)${keys_tmp}.data)[$idx];')
|
||||
g.write('\t$val_styp $it.val_var = (*($val_styp*)map_get3(')
|
||||
g.expr(it.cond)
|
||||
g.writeln(', $key, &($val_styp[]){ $zero }));')
|
||||
g.stmts(it.stmts)
|
||||
|
@ -641,36 +641,28 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
}
|
||||
}
|
||||
else {
|
||||
mut is_fixed_array_init := false
|
||||
mut is_ident := false
|
||||
right_sym := g.table.get_type_symbol(assign_stmt.right_types[i])
|
||||
mut is_fixed_array_init := false
|
||||
match val {
|
||||
ast.ArrayInit {
|
||||
is_fixed_array_init = right_sym.kind == .array_fixed
|
||||
}
|
||||
ast.Ident {
|
||||
is_ident = true
|
||||
}
|
||||
else {}
|
||||
}
|
||||
is_decl := assign_stmt.op == .decl_assign
|
||||
g.write('/*assign_stmt*/')
|
||||
if is_decl {
|
||||
g.write('$styp ')
|
||||
}
|
||||
g.expr(ident)
|
||||
if g.autofree && right_sym.kind == .array && is_ident {
|
||||
// `arr1 = arr2` => `arr1 = arr2.clone()`
|
||||
g.write(' = array_clone(&')
|
||||
g.expr(val)
|
||||
g.write(')')
|
||||
if g.autofree && right_sym.kind in [.array, .string] {
|
||||
if g.gen_clone_assignment(val, right_sym, true) {
|
||||
g.writeln(';')
|
||||
// g.expr_var_name = ''
|
||||
return
|
||||
}
|
||||
}
|
||||
else if g.autofree && right_sym.kind == .string && is_ident {
|
||||
// `str1 = str2` => `str1 = str2.clone()`
|
||||
g.write(' = string_clone(')
|
||||
g.expr(val)
|
||||
g.write(')')
|
||||
}
|
||||
else if !is_fixed_array_init {
|
||||
if !is_fixed_array_init {
|
||||
g.write(' = ')
|
||||
if !is_decl {
|
||||
g.expr_with_cast(val, assign_stmt.left_types[i], ident_var_info.typ)
|
||||
|
@ -692,6 +684,40 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
}
|
||||
}
|
||||
|
||||
fn (g mut Gen) gen_clone_assignment(val ast.Expr, right_sym table.TypeSymbol, add_eq bool) bool {
|
||||
mut is_ident := false
|
||||
match val {
|
||||
ast.Ident {
|
||||
is_ident = true
|
||||
}
|
||||
ast.SelectorExpr {
|
||||
is_ident = true
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if g.autofree && right_sym.kind == .array && is_ident {
|
||||
// `arr1 = arr2` => `arr1 = arr2.clone()`
|
||||
if add_eq {
|
||||
g.write('=')
|
||||
}
|
||||
g.write(' array_clone(&')
|
||||
g.expr(val)
|
||||
g.write(')')
|
||||
}
|
||||
else if g.autofree && right_sym.kind == .string && is_ident {
|
||||
if add_eq {
|
||||
g.write('=')
|
||||
}
|
||||
// `str1 = str2` => `str1 = str2.clone()`
|
||||
g.write(' string_clone(')
|
||||
g.expr(val)
|
||||
g.write(')')
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
|
||||
if it.is_c {
|
||||
// || it.no_body {
|
||||
|
@ -1173,7 +1199,18 @@ fn (g mut Gen) assign_expr(node ast.AssignExpr) {
|
|||
g.write(', ')
|
||||
}
|
||||
g.is_assign_lhs = false
|
||||
g.expr_with_cast(node.val, node.right_type, node.left_type)
|
||||
right_sym := g.table.get_type_symbol(node.right_type)
|
||||
// left_sym := g.table.get_type_symbol(node.left_type)
|
||||
mut cloned := false
|
||||
// !g.is_array_set
|
||||
if g.autofree && right_sym.kind in [.array, .string] {
|
||||
if g.gen_clone_assignment(node.val, right_sym, false) {
|
||||
cloned = true
|
||||
}
|
||||
}
|
||||
if !cloned {
|
||||
g.expr_with_cast(node.val, node.right_type, node.left_type)
|
||||
}
|
||||
if g.is_array_set {
|
||||
g.write(' })')
|
||||
g.is_array_set = false
|
||||
|
@ -1397,7 +1434,7 @@ fn (g mut Gen) match_expr(node ast.MatchExpr) {
|
|||
ast.Type {
|
||||
it_type := g.typ(it.typ)
|
||||
// g.writeln('$it_type* it = ($it_type*)${tmp}.obj; // ST it')
|
||||
g.write('$it_type* it = ($it_type*)')
|
||||
g.write('\t$it_type* it = ($it_type*)')
|
||||
g.expr(node.cond)
|
||||
g.writeln('.obj; // ST it')
|
||||
}
|
||||
|
@ -2194,53 +2231,64 @@ fn (g mut Gen) call_expr(node ast.CallExpr) {
|
|||
g.write('$styp $tmp_opt = ')
|
||||
}
|
||||
if node.is_method {
|
||||
// TODO: there are still due to unchecked exprs (opt/some fn arg)
|
||||
if node.left_type == 0 {
|
||||
verror('method receiver type is 0, this means there are some uchecked exprs')
|
||||
g.method_call(node)
|
||||
}
|
||||
else {
|
||||
g.fn_call(node)
|
||||
}
|
||||
if gen_or {
|
||||
g.or_block(tmp_opt, node.or_block.stmts, node.return_type)
|
||||
}
|
||||
}
|
||||
|
||||
fn (g mut Gen) method_call(node ast.CallExpr) {
|
||||
// TODO: there are still due to unchecked exprs (opt/some fn arg)
|
||||
if node.left_type == 0 {
|
||||
verror('method receiver type is 0, this means there are some uchecked exprs')
|
||||
}
|
||||
typ_sym := g.table.get_type_symbol(node.receiver_type)
|
||||
// rec_sym := g.table.get_type_symbol(node.receiver_type)
|
||||
mut receiver_name := typ_sym.name
|
||||
if typ_sym.kind == .array && node.name == 'filter' {
|
||||
g.gen_filter(node)
|
||||
return
|
||||
}
|
||||
if typ_sym.kind == .array && node.name in
|
||||
// TODO performance, detect `array` method differently
|
||||
['repeat', 'sort_with_compare', 'free', 'push_many', 'trim',
|
||||
//
|
||||
'first', 'last', 'clone', 'reverse', 'slice'] {
|
||||
// && rec_sym.name == 'array' {
|
||||
// && rec_sym.name == 'array' && receiver_name.starts_with('array') {
|
||||
// `array_byte_clone` => `array_clone`
|
||||
receiver_name = 'array'
|
||||
if node.name in ['last', 'first'] {
|
||||
return_type_str := g.typ(node.return_type)
|
||||
g.write('*($return_type_str*)')
|
||||
}
|
||||
typ_sym := g.table.get_type_symbol(node.receiver_type)
|
||||
// rec_sym := g.table.get_type_symbol(node.receiver_type)
|
||||
mut receiver_name := typ_sym.name
|
||||
if typ_sym.kind == .array && node.name == 'filter' {
|
||||
g.gen_filter(node)
|
||||
return
|
||||
}
|
||||
if typ_sym.kind == .array && node.name in
|
||||
// TODO performance, detect `array` method differently
|
||||
['repeat', 'sort_with_compare', 'free', 'push_many', 'trim',
|
||||
//
|
||||
'first', 'last', 'clone', 'reverse', 'slice'] {
|
||||
// && rec_sym.name == 'array' {
|
||||
// && rec_sym.name == 'array' && receiver_name.starts_with('array') {
|
||||
// `array_byte_clone` => `array_clone`
|
||||
receiver_name = 'array'
|
||||
if node.name in ['last', 'first'] {
|
||||
return_type_str := g.typ(node.return_type)
|
||||
g.write('*($return_type_str*)')
|
||||
}
|
||||
}
|
||||
name := '${receiver_name}_$node.name'.replace('.', '__')
|
||||
// if node.receiver_type != 0 {
|
||||
// g.write('/*${g.typ(node.receiver_type)}*/')
|
||||
// g.write('/*expr_type=${g.typ(node.left_type)} rec type=${g.typ(node.receiver_type)}*/')
|
||||
// }
|
||||
g.write('${name}(')
|
||||
if table.type_is_ptr(node.receiver_type) && !table.type_is_ptr(node.left_type) {
|
||||
// The receiver is a reference, but the caller provided a value
|
||||
// Add `&` automatically.
|
||||
// TODO same logic in call_args()
|
||||
g.write('&')
|
||||
}
|
||||
else if !table.type_is_ptr(node.receiver_type) && table.type_is_ptr(node.left_type) {
|
||||
g.write('/*rec*/*')
|
||||
}
|
||||
g.expr(node.left)
|
||||
is_variadic := node.exp_arg_types.len > 0 && table.type_is_variadic(node.exp_arg_types[node.exp_arg_types.len - 1])
|
||||
if node.args.len > 0 || is_variadic {
|
||||
g.write(', ')
|
||||
}
|
||||
// /////////
|
||||
/*
|
||||
}
|
||||
name := '${receiver_name}_$node.name'.replace('.', '__')
|
||||
// if node.receiver_type != 0 {
|
||||
// g.write('/*${g.typ(node.receiver_type)}*/')
|
||||
// g.write('/*expr_type=${g.typ(node.left_type)} rec type=${g.typ(node.receiver_type)}*/')
|
||||
// }
|
||||
g.write('${name}(')
|
||||
if table.type_is_ptr(node.receiver_type) && !table.type_is_ptr(node.left_type) {
|
||||
// The receiver is a reference, but the caller provided a value
|
||||
// Add `&` automatically.
|
||||
// TODO same logic in call_args()
|
||||
g.write('&')
|
||||
}
|
||||
else if !table.type_is_ptr(node.receiver_type) && table.type_is_ptr(node.left_type) {
|
||||
g.write('/*rec*/*')
|
||||
}
|
||||
g.expr(node.left)
|
||||
is_variadic := node.exp_arg_types.len > 0 && table.type_is_variadic(node.exp_arg_types[node.exp_arg_types.len - 1])
|
||||
if node.args.len > 0 || is_variadic {
|
||||
g.write(', ')
|
||||
}
|
||||
// /////////
|
||||
/*
|
||||
if name.contains('subkeys') {
|
||||
println('call_args $name $node.arg_types.len')
|
||||
for t in node.arg_types {
|
||||
|
@ -2250,23 +2298,27 @@ fn (g mut Gen) call_expr(node ast.CallExpr) {
|
|||
println('')
|
||||
}
|
||||
*/
|
||||
// ///////
|
||||
g.call_args(node.args, node.exp_arg_types)
|
||||
g.write(')')
|
||||
// ///////
|
||||
g.call_args(node.args, node.exp_arg_types)
|
||||
g.write(')')
|
||||
// if node.or_block.stmts.len > 0 {
|
||||
// g.or_block(node.or_block.stmts, node.return_type)
|
||||
// }
|
||||
}
|
||||
|
||||
fn (g mut Gen) fn_call(node ast.CallExpr) {
|
||||
mut name := node.name
|
||||
is_print := name == 'println'
|
||||
if node.is_c {
|
||||
// Skip "C."
|
||||
g.is_c_call = true
|
||||
name = name[2..].replace('.', '__')
|
||||
}
|
||||
else {
|
||||
mut name := node.name
|
||||
is_print := name == 'println'
|
||||
if node.is_c {
|
||||
// Skip "C."
|
||||
g.is_c_call = true
|
||||
name = name[2..].replace('.', '__')
|
||||
}
|
||||
else {
|
||||
name = c_name(name)
|
||||
}
|
||||
// Generate tmp vars for values that have to be freed.
|
||||
/*
|
||||
name = c_name(name)
|
||||
}
|
||||
// Generate tmp vars for values that have to be freed.
|
||||
/*
|
||||
mut tmps := []string
|
||||
for arg in node.args {
|
||||
if arg.typ == table.string_type_idx || is_print {
|
||||
|
@ -2279,43 +2331,42 @@ fn (g mut Gen) call_expr(node ast.CallExpr) {
|
|||
}
|
||||
*/
|
||||
|
||||
if is_print && node.args[0].typ != table.string_type_idx {
|
||||
typ := node.args[0].typ
|
||||
mut styp := g.typ(typ)
|
||||
sym := g.table.get_type_symbol(typ)
|
||||
if !sym.has_method('str') && !(int(typ) in g.str_types) {
|
||||
// Generate an automatic str() method if this type doesn't have it already
|
||||
if table.type_is_ptr(typ) {
|
||||
styp = styp.replace('*', '')
|
||||
}
|
||||
g.str_types << typ
|
||||
g.definitions.writeln('string ${styp}_str($styp* x) { return tos3("TODO_str"); }')
|
||||
}
|
||||
if g.autofree && !table.type_is_optional(typ) {
|
||||
tmp := g.new_tmp_var()
|
||||
// tmps << tmp
|
||||
g.write('string $tmp = ${styp}_str(')
|
||||
g.expr(node.args[0].expr)
|
||||
g.writeln('); println($tmp); string_free($tmp); //MEM2 $styp')
|
||||
}
|
||||
else {
|
||||
// `println(int_str(10))`
|
||||
// sym := g.table.get_type_symbol(node.args[0].typ)
|
||||
g.write('println(${styp}_str(')
|
||||
g.expr(node.args[0].expr)
|
||||
g.write('))')
|
||||
if is_print && node.args[0].typ != table.string_type_idx {
|
||||
typ := node.args[0].typ
|
||||
mut styp := g.typ(typ)
|
||||
sym := g.table.get_type_symbol(typ)
|
||||
if !sym.has_method('str') && !(int(typ) in g.str_types) {
|
||||
// Generate an automatic str() method if this type doesn't have it already
|
||||
if table.type_is_ptr(typ) {
|
||||
styp = styp.replace('*', '')
|
||||
}
|
||||
g.str_types << typ
|
||||
g.definitions.writeln('string ${styp}_str($styp* x) { return tos3("TODO_str"); }')
|
||||
}
|
||||
if g.autofree && !table.type_is_optional(typ) {
|
||||
tmp := g.new_tmp_var()
|
||||
// tmps << tmp
|
||||
g.write('string $tmp = ${styp}_str(')
|
||||
g.expr(node.args[0].expr)
|
||||
g.writeln('); println($tmp); string_free($tmp); //MEM2 $styp')
|
||||
}
|
||||
else {
|
||||
g.write('${name}(')
|
||||
g.call_args(node.args, node.exp_arg_types)
|
||||
g.write(')')
|
||||
// `println(int_str(10))`
|
||||
// sym := g.table.get_type_symbol(node.args[0].typ)
|
||||
g.write('println(${styp}_str(')
|
||||
g.expr(node.args[0].expr)
|
||||
g.write('))')
|
||||
}
|
||||
g.is_c_call = false
|
||||
}
|
||||
if gen_or {
|
||||
g.or_block(tmp_opt, node.or_block.stmts, node.return_type)
|
||||
else {
|
||||
g.write('${name}(')
|
||||
g.call_args(node.args, node.exp_arg_types)
|
||||
g.write(')')
|
||||
}
|
||||
// if node.or_block.stmts.len > 0 {
|
||||
// g.or_block(node.or_block.stmts, node.return_type)
|
||||
// }
|
||||
g.is_c_call = false
|
||||
}
|
||||
|
||||
// If user is accessing the return value eg. in assigment, pass the variable name.
|
||||
|
|
|
@ -26,10 +26,10 @@ fn (p mut Parser) comp_if() ast.CompIf {
|
|||
// `$if os {` for a different target, skip everything inside
|
||||
// to avoid compilation errors (like including <windows.h> or calling WinAPI fns
|
||||
// on non-Windows systems)
|
||||
if ((!is_not && os != p.pref.os) || (is_not && os == p.pref.os)) && !p.pref.output_cross_c {
|
||||
if false && ((!is_not && os != p.pref.os) || (is_not && os == p.pref.os)) && !p.pref.output_cross_c {
|
||||
skip_os = true
|
||||
p.check(.lcbr)
|
||||
//p.warn('skipping $if $val os=$os p.pref.os=$p.pref.os')
|
||||
// p.warn('skipping $if $val os=$os p.pref.os=$p.pref.os')
|
||||
mut stack := 1
|
||||
for {
|
||||
if p.tok.kind == .key_return {
|
||||
|
@ -75,7 +75,7 @@ fn (p mut Parser) comp_if() ast.CompIf {
|
|||
}
|
||||
|
||||
const (
|
||||
todo_delete_me = pref.OS.linux // TODO import warning bug
|
||||
todo_delete_me = pref.OS.linux // TODO import warning bug
|
||||
)
|
||||
|
||||
fn os_from_string(os string) pref.OS {
|
||||
|
|
|
@ -70,9 +70,10 @@ pub fn (p mut Parser) parse_multi_return_type() table.Type {
|
|||
pub fn (p mut Parser) parse_fn_type(name string) table.Type {
|
||||
// p.warn('parse fn')
|
||||
p.check(.key_fn)
|
||||
args, is_variadic := p.fn_args()
|
||||
line_nr := p.tok.line_nr
|
||||
args,is_variadic := p.fn_args()
|
||||
mut return_type := table.void_type
|
||||
if p.tok.kind.is_start_of_type() {
|
||||
if p.tok.line_nr == line_nr && p.tok.kind.is_start_of_type() {
|
||||
return_type = p.parse_type()
|
||||
}
|
||||
func := table.Fn{
|
||||
|
@ -96,7 +97,7 @@ pub fn (p mut Parser) parse_type() table.Type {
|
|||
mut nr_muls := 0
|
||||
for p.tok.kind in [.and, .amp] {
|
||||
if p.tok.kind == .and {
|
||||
nr_muls+=2
|
||||
nr_muls += 2
|
||||
}
|
||||
else {
|
||||
nr_muls++
|
||||
|
|
|
@ -1520,6 +1520,13 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
|
|||
field_name := p.check_name()
|
||||
// p.warn('field $field_name')
|
||||
typ := p.parse_type()
|
||||
/*
|
||||
if name == '_net_module_s' {
|
||||
s := p.table.get_type_symbol(typ)
|
||||
println('XXXX' + s.str())
|
||||
}
|
||||
*/
|
||||
|
||||
// Default value
|
||||
if p.tok.kind == .assign {
|
||||
p.next()
|
||||
|
|
Loading…
Reference in New Issue