compiler: small fixes + some logic for freeing strings
parent
b1f0df0fd1
commit
04e4018228
|
@ -89,6 +89,17 @@ fn (p mut Parser) mark_var_changed(v Var) {
|
||||||
p.local_vars[v.idx].is_changed = true
|
p.local_vars[v.idx].is_changed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (p mut Parser) mark_arg_moved(v Var) {
|
||||||
|
for i, arg in p.cur_fn.args {
|
||||||
|
if arg.name == v.name {
|
||||||
|
//println('setting f $p.cur_fn.name arg $arg.name to is_mut')
|
||||||
|
p.cur_fn.args[i].is_moved = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.table.fns[p.cur_fn.name] = p.cur_fn
|
||||||
|
}
|
||||||
|
|
||||||
fn (p mut Parser) known_var(name string) bool {
|
fn (p mut Parser) known_var(name string) bool {
|
||||||
_ = p.find_var(name) or {
|
_ = p.find_var(name) or {
|
||||||
return false
|
return false
|
||||||
|
@ -818,10 +829,9 @@ fn (p mut Parser) fn_call_args(f mut Fn) &Fn {
|
||||||
'_panic_debug ($p.scanner.line_nr, tos2((byte *)"$file_path"), tos2((byte *)"$mod_name"), tos2((byte *)"$fn_name"), '
|
'_panic_debug ($p.scanner.line_nr, tos2((byte *)"$file_path"), tos2((byte *)"$mod_name"), tos2((byte *)"$fn_name"), '
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
// Receiver - first arg
|
|
||||||
for i, arg in f.args {
|
for i, arg in f.args {
|
||||||
// println('$i) arg=$arg.name')
|
// Receiver is the first arg
|
||||||
// Skip receiver, because it was already generated in the expression
|
// Skip the receiver, because it was already generated in the expression
|
||||||
if i == 0 && f.is_method {
|
if i == 0 && f.is_method {
|
||||||
if f.args.len > 1 && !p.is_js {
|
if f.args.len > 1 && !p.is_js {
|
||||||
p.gen(',')
|
p.gen(',')
|
||||||
|
@ -865,7 +875,14 @@ fn (p mut Parser) fn_call_args(f mut Fn) &Fn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.expected_type = arg.typ
|
p.expected_type = arg.typ
|
||||||
|
clone := p.pref.autofree && arg.typ == 'string' && arg.is_moved && p.mod != 'builtin'
|
||||||
|
if clone {
|
||||||
|
p.gen('/*YY f=$f.name arg=$arg.name is_moved=$arg.is_moved*/string_clone(')
|
||||||
|
}
|
||||||
mut typ := p.bool_expression()
|
mut typ := p.bool_expression()
|
||||||
|
if clone {
|
||||||
|
p.gen(')')
|
||||||
|
}
|
||||||
// Optimize `println`: replace it with `printf` to avoid extra allocations and
|
// Optimize `println`: replace it with `printf` to avoid extra allocations and
|
||||||
// function calls.
|
// function calls.
|
||||||
// `println(777)` => `printf("%d\n", 777)`
|
// `println(777)` => `printf("%d\n", 777)`
|
||||||
|
@ -927,9 +944,20 @@ fn (p mut Parser) fn_call_args(f mut Fn) &Fn {
|
||||||
expected := arg.typ
|
expected := arg.typ
|
||||||
// println('fn arg got="$got" exp="$expected"')
|
// println('fn arg got="$got" exp="$expected"')
|
||||||
if !p.check_types_no_throw(got, expected) {
|
if !p.check_types_no_throw(got, expected) {
|
||||||
mut err := 'Fn "$f.name" wrong arg #${i+1}. '
|
mut j := i
|
||||||
err += 'Expected "$arg.typ" ($arg.name) but got "$typ"'
|
if f.is_method {
|
||||||
p.error(err)
|
j--
|
||||||
|
}
|
||||||
|
mut nr := '${i+1}th'
|
||||||
|
if j == 0 {
|
||||||
|
nr = 'first'
|
||||||
|
} else if j == 1 {
|
||||||
|
nr = 'second'
|
||||||
|
} else if j == 2 {
|
||||||
|
nr = 'third'
|
||||||
|
}
|
||||||
|
p.error('cannot use type `$typ` as type `$arg.typ` in $nr ' +
|
||||||
|
'argument to `$f.name()`')
|
||||||
}
|
}
|
||||||
is_interface := p.table.is_interface(arg.typ)
|
is_interface := p.table.is_interface(arg.typ)
|
||||||
// Add `&` or `*` before an argument?
|
// Add `&` or `*` before an argument?
|
||||||
|
|
|
@ -479,22 +479,23 @@ fn type_default(typ string) string {
|
||||||
return '{0}'
|
return '{0}'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) gen_array_push(ph int, typ, expr_type, tmp, tmp_typ string) {
|
fn (p mut Parser) gen_array_push(ph int, typ, expr_type, tmp, elm_type string) {
|
||||||
|
// Two arrays of the same type?
|
||||||
push_array := typ == expr_type
|
push_array := typ == expr_type
|
||||||
if push_array {
|
if push_array {
|
||||||
p.cgen.set_placeholder(ph, '_PUSH_MANY(&' )
|
p.cgen.set_placeholder(ph, '_PUSH_MANY(&' )
|
||||||
p.gen('), $tmp, $typ)')
|
p.gen('), $tmp, $typ)')
|
||||||
} else {
|
} else {
|
||||||
p.check_types(expr_type, tmp_typ)
|
p.check_types(expr_type, elm_type)
|
||||||
// Pass tmp var info to the _PUSH macro
|
// Pass tmp var info to the _PUSH macro
|
||||||
// Prepend tmp initialisation and push call
|
// Prepend tmp initialisation and push call
|
||||||
// Don't dereference if it's already a mutable array argument (`fn foo(mut []int)`)
|
// Don't dereference if it's already a mutable array argument (`fn foo(mut []int)`)
|
||||||
push_call := if typ.contains('*'){'_PUSH('} else { '_PUSH(&'}
|
push_call := if typ.contains('*'){'_PUSH('} else { '_PUSH(&'}
|
||||||
p.cgen.set_placeholder(ph, push_call)
|
p.cgen.set_placeholder(ph, push_call)
|
||||||
if tmp_typ.ends_with('*') {
|
if elm_type.ends_with('*') {
|
||||||
p.gen('), $tmp, ${tmp_typ.left(tmp_typ.len - 1)})')
|
p.gen('), $tmp, ${elm_type.left(elm_type.len - 1)})')
|
||||||
} else {
|
} else {
|
||||||
p.gen('), $tmp, $tmp_typ)')
|
p.gen('), $tmp, $elm_type)')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,7 +241,7 @@ fn (v mut V) compile() {
|
||||||
for file in v.files {
|
for file in v.files {
|
||||||
mut p := v.new_parser(file)
|
mut p := v.new_parser(file)
|
||||||
p.parse(.decl)
|
p.parse(.decl)
|
||||||
if p.pref.autofree { p.scanner.text.free() free(p.scanner) }
|
//if p.pref.autofree { p.scanner.text.free() free(p.scanner) }
|
||||||
}
|
}
|
||||||
// Main pass
|
// Main pass
|
||||||
cgen.pass = Pass.main
|
cgen.pass = Pass.main
|
||||||
|
@ -307,7 +307,7 @@ fn (v mut V) compile() {
|
||||||
for file in v.files {
|
for file in v.files {
|
||||||
mut p := v.new_parser(file)
|
mut p := v.new_parser(file)
|
||||||
p.parse(.main)
|
p.parse(.main)
|
||||||
if p.pref.autofree { p.scanner.text.free() free(p.scanner) }
|
//if p.pref.autofree { p.scanner.text.free() free(p.scanner) }
|
||||||
// p.g.gen_x64()
|
// p.g.gen_x64()
|
||||||
// Format all files (don't format automatically generated vlib headers)
|
// Format all files (don't format automatically generated vlib headers)
|
||||||
if !v.pref.nofmt && !file.contains('/vlib/') {
|
if !v.pref.nofmt && !file.contains('/vlib/') {
|
||||||
|
@ -569,13 +569,13 @@ fn (v mut V) add_v_files_to_compile() {
|
||||||
for file in v.files {
|
for file in v.files {
|
||||||
mut p := v.new_parser(file)
|
mut p := v.new_parser(file)
|
||||||
p.parse(.imports)
|
p.parse(.imports)
|
||||||
if p.pref.autofree { p.scanner.text.free() free(p.scanner) }
|
//if p.pref.autofree { p.scanner.text.free() free(p.scanner) }
|
||||||
}
|
}
|
||||||
// Parse user imports
|
// Parse user imports
|
||||||
for file in user_files {
|
for file in user_files {
|
||||||
mut p := v.new_parser(file)
|
mut p := v.new_parser(file)
|
||||||
p.parse(.imports)
|
p.parse(.imports)
|
||||||
if p.pref.autofree { p.scanner.text.free() free(p.scanner) }
|
//if p.pref.autofree { p.scanner.text.free() free(p.scanner) }
|
||||||
}
|
}
|
||||||
// Parse lib imports
|
// Parse lib imports
|
||||||
/*
|
/*
|
||||||
|
@ -614,7 +614,7 @@ fn (v mut V) add_v_files_to_compile() {
|
||||||
for file in vfiles {
|
for file in vfiles {
|
||||||
mut p := v.new_parser(file)
|
mut p := v.new_parser(file)
|
||||||
p.parse(.imports)
|
p.parse(.imports)
|
||||||
if p.pref.autofree { p.scanner.text.free() free(p.scanner) }
|
//if p.pref.autofree { p.scanner.text.free() free(p.scanner) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if v.pref.is_verbose {
|
if v.pref.is_verbose {
|
||||||
|
|
|
@ -13,9 +13,10 @@ struct Parser {
|
||||||
file_path string // "/home/user/hello.v"
|
file_path string // "/home/user/hello.v"
|
||||||
file_name string // "hello.v"
|
file_name string // "hello.v"
|
||||||
file_platform string // ".v", "_win.v", "_nix.v", "_mac.v", "_lin.v" ...
|
file_platform string // ".v", "_win.v", "_nix.v", "_mac.v", "_lin.v" ...
|
||||||
file_pcguard string // When p.file_pcguard != '', it contains a
|
// When p.file_pcguard != '', it contains a
|
||||||
// C ifdef guard clause that must be put before
|
// C ifdef guard clause that must be put before
|
||||||
// the #include directives in the parsed .v file
|
// the #include directives in the parsed .v file
|
||||||
|
file_pcguard string
|
||||||
v &V
|
v &V
|
||||||
pref &Preferences // Preferences shared from V struct
|
pref &Preferences // Preferences shared from V struct
|
||||||
mut:
|
mut:
|
||||||
|
@ -36,7 +37,7 @@ mut:
|
||||||
expr_var Var
|
expr_var Var
|
||||||
has_immutable_field bool
|
has_immutable_field bool
|
||||||
first_immutable_field Var
|
first_immutable_field Var
|
||||||
assigned_type string
|
assigned_type string // non-empty if we are in an assignment expression
|
||||||
expected_type string
|
expected_type string
|
||||||
tmp_cnt int
|
tmp_cnt int
|
||||||
is_script bool
|
is_script bool
|
||||||
|
@ -712,6 +713,7 @@ fn (p mut Parser) enum_decl(_enum_name string) {
|
||||||
if p.tok == .comma {
|
if p.tok == .comma {
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
|
// !!!! NAME free
|
||||||
p.table.register_const(name, enum_name, p.mod)
|
p.table.register_const(name, enum_name, p.mod)
|
||||||
val++
|
val++
|
||||||
}
|
}
|
||||||
|
@ -968,7 +970,7 @@ fn (p mut Parser) get_type() string {
|
||||||
typ = p.lit
|
typ = p.lit
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if warn {
|
if warn && p.mod != 'ui' {
|
||||||
p.warn('use `&Foo` instead of `*Foo`')
|
p.warn('use `&Foo` instead of `*Foo`')
|
||||||
}
|
}
|
||||||
// Module specified? (e.g. gx.Image)
|
// Module specified? (e.g. gx.Image)
|
||||||
|
@ -1119,7 +1121,7 @@ fn (p mut Parser) close_scope() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// Clean up memory, only do this if -autofree was passed for now
|
// Clean up memory, only do this if -autofree was passed for now
|
||||||
if p.pref.autofree && v.is_alloc && !p.pref.is_test {
|
if p.pref.autofree && v.is_alloc { // && !p.pref.is_test {
|
||||||
mut free_fn := 'free'
|
mut free_fn := 'free'
|
||||||
if v.typ.starts_with('array_') {
|
if v.typ.starts_with('array_') {
|
||||||
free_fn = 'v_array_free'
|
free_fn = 'v_array_free'
|
||||||
|
@ -1136,6 +1138,7 @@ fn (p mut Parser) close_scope() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if p.returns {
|
if p.returns {
|
||||||
|
// Don't free a variable that's being returned
|
||||||
if !v.is_returned && v.typ != 'FILE*' { //!v.is_c {
|
if !v.is_returned && v.typ != 'FILE*' { //!v.is_c {
|
||||||
prev_line := p.cgen.lines[p.cgen.lines.len-2]
|
prev_line := p.cgen.lines[p.cgen.lines.len-2]
|
||||||
p.cgen.lines[p.cgen.lines.len-2] =
|
p.cgen.lines[p.cgen.lines.len-2] =
|
||||||
|
@ -1608,6 +1611,11 @@ fn (p mut Parser) name_expr() string {
|
||||||
else if deref {
|
else if deref {
|
||||||
p.gen('*')
|
p.gen('*')
|
||||||
}
|
}
|
||||||
|
if p.pref.autofree && v.typ == 'string' && v.is_arg &&
|
||||||
|
p.assigned_type == 'string' {
|
||||||
|
p.warn('setting moved ' + v.typ)
|
||||||
|
p.mark_arg_moved(v)
|
||||||
|
}
|
||||||
mut typ := p.var_expr(v)
|
mut typ := p.var_expr(v)
|
||||||
// *var
|
// *var
|
||||||
if deref {
|
if deref {
|
||||||
|
@ -2108,11 +2116,7 @@ fn (p mut Parser) index_expr(typ_ string, fn_ph int) string {
|
||||||
}
|
}
|
||||||
// TODO move this from index_expr()
|
// TODO move this from index_expr()
|
||||||
// TODO if p.tok in ...
|
// TODO if p.tok in ...
|
||||||
// if p.tok in [.assign, .plus_assign, .minus_assign]
|
if (p.tok == .assign && !p.is_sql) || p.tok.is_assign() {
|
||||||
if (p.tok == .assign && !p.is_sql) || p.tok == .plus_assign || p.tok == .minus_assign ||
|
|
||||||
p.tok == .mult_assign || p.tok == .div_assign || p.tok == .xor_assign || p.tok == .mod_assign ||
|
|
||||||
p.tok == .or_assign || p.tok == .and_assign || p.tok == .righ_shift_assign ||
|
|
||||||
p.tok == .left_shift_assign {
|
|
||||||
if is_indexer && is_str && !p.builtin_mod {
|
if is_indexer && is_str && !p.builtin_mod {
|
||||||
p.error('strings are immutable')
|
p.error('strings are immutable')
|
||||||
}
|
}
|
||||||
|
@ -2219,8 +2223,14 @@ fn (p mut Parser) expression() string {
|
||||||
if !p.expr_var.is_changed {
|
if !p.expr_var.is_changed {
|
||||||
p.mark_var_changed(p.expr_var)
|
p.mark_var_changed(p.expr_var)
|
||||||
}
|
}
|
||||||
|
p.gen('/*typ = $typ tmp_typ=$tmp_typ*/')
|
||||||
|
ph_clone := p.cgen.add_placeholder()
|
||||||
expr_type := p.expression()
|
expr_type := p.expression()
|
||||||
// Two arrays of the same type?
|
// Need to clone the string when appending it to an array?
|
||||||
|
if p.pref.autofree && typ == 'array_string' && expr_type == 'string' {
|
||||||
|
p.cgen.set_placeholder(ph_clone, 'string_clone(')
|
||||||
|
p.gen(')')
|
||||||
|
}
|
||||||
p.gen_array_push(ph, typ, expr_type, tmp, tmp_typ)
|
p.gen_array_push(ph, typ, expr_type, tmp, tmp_typ)
|
||||||
return 'void'
|
return 'void'
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,16 +57,12 @@ fn new_scanner(file_path string) &Scanner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
text := raw_text
|
return &Scanner {
|
||||||
|
|
||||||
scanner := &Scanner {
|
|
||||||
file_path: file_path
|
file_path: file_path
|
||||||
text: text
|
text: raw_text
|
||||||
fmt_out: strings.new_builder(1000)
|
fmt_out: strings.new_builder(1000)
|
||||||
should_print_line_on_error: true
|
should_print_line_on_error: true
|
||||||
}
|
}
|
||||||
|
|
||||||
return scanner
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -670,6 +666,7 @@ fn (s &Scanner) error(msg string) {
|
||||||
// and jump to their source with a keyboard shortcut.
|
// and jump to their source with a keyboard shortcut.
|
||||||
// Using only the filename leads to inability of IDE/editors
|
// Using only the filename leads to inability of IDE/editors
|
||||||
// to find the source file, when it is in another folder.
|
// to find the source file, when it is in another folder.
|
||||||
|
//println('${s.file_path}:${s.line_nr + 1}:${column+1}: $msg')
|
||||||
println('${fullpath}:${s.line_nr + 1}:${column+1}: $msg')
|
println('${fullpath}:${s.line_nr + 1}:${column+1}: $msg')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ mut:
|
||||||
is_changed bool
|
is_changed bool
|
||||||
scope_level int
|
scope_level int
|
||||||
is_c bool // todo remove once `typ` is `Type`, not string
|
is_c bool // todo remove once `typ` is `Type`, not string
|
||||||
moved bool
|
is_moved bool
|
||||||
scanner_pos ScannerPos // TODO: use only scanner_pos, remove line_nr
|
scanner_pos ScannerPos // TODO: use only scanner_pos, remove line_nr
|
||||||
line_nr int
|
line_nr int
|
||||||
}
|
}
|
||||||
|
@ -321,7 +321,8 @@ fn (table &Table) known_type(typ_ string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (table &Table) known_type_fast(t &Type) bool {
|
fn (table &Table) known_type_fast(t &Type) bool {
|
||||||
return t.name.len > 0 && !t.is_placeholder
|
return t.name != '' && !t.is_placeholder
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (t &Table) find_fn(name string) ?Fn {
|
fn (t &Table) find_fn(name string) ?Fn {
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
- ui demo: calculator
|
- ui demo: calculator
|
||||||
- declarative ui with hot reload (similar to swiftui)
|
- declarative ui with hot reload (similar to swiftui)
|
||||||
- "building a simple blog with vweb" tutorial + youtube video
|
- "building a simple blog with vweb" tutorial + youtube video
|
||||||
- webassembly backend (via emscripten)
|
|
||||||
+ javascript backend
|
+ javascript backend
|
||||||
- new playground with a v compiler running in the browser
|
- new playground with a v compiler running in the browser
|
||||||
+ o(log n) type lookup
|
+ o(log n) type lookup
|
||||||
|
|
|
@ -6,8 +6,7 @@ module darwin
|
||||||
struct C.NSString { }
|
struct C.NSString { }
|
||||||
|
|
||||||
// macOS and iOS helpers
|
// macOS and iOS helpers
|
||||||
pub fn nsstring(s string) *NSString {
|
pub fn nsstring(s string) *C.NSString {
|
||||||
// #return @"" ;
|
|
||||||
// println('ns $s len=$s.len')
|
// println('ns $s len=$s.len')
|
||||||
# return [ [ NSString alloc ] initWithBytesNoCopy:s.str length:s.len
|
# return [ [ NSString alloc ] initWithBytesNoCopy:s.str length:s.len
|
||||||
# encoding:NSUTF8StringEncoding freeWhenDone: false];
|
# encoding:NSUTF8StringEncoding freeWhenDone: false];
|
||||||
|
@ -16,7 +15,5 @@ pub fn nsstring(s string) *NSString {
|
||||||
//ns := C.alloc_NSString()
|
//ns := C.alloc_NSString()
|
||||||
//return ns.initWithBytesNoCopy(s.str, length: s.len,
|
//return ns.initWithBytesNoCopy(s.str, length: s.len,
|
||||||
//encoding: NSUTF8StringEncoding, freeWhenDone: false)
|
//encoding: NSUTF8StringEncoding, freeWhenDone: false)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue