parser,fmt: implement `[manualfree] module abc` for opting out *all* fns in a given .v from autofree

pull/7886/head^2
Delyan Angelov 2021-01-08 17:24:42 +02:00
parent 083dc23db8
commit 46a5c487c1
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
7 changed files with 49 additions and 2 deletions

View File

@ -7,7 +7,7 @@
- `byte.str()` has been fixed and works like with all other numbers. `byte.ascii_str()` has been added.
- Smart cast in for loops: `for mut x is string {}`.
- `[noinit]` struct attribute to disallow direct struct initialization with `Foo{}`.
- `[manualfree]` attribute for functions, that want to do their own memory management.
- support `[manualfree] fn f1(){}` and `[manualfree] module m1`, for functions doing their own memory management.
## V 0.2.1
*30 Dec 2020*

View File

@ -131,6 +131,7 @@ pub fn (e &SelectorExpr) root_ident() Ident {
pub struct Module {
pub:
name string
attrs []table.Attr
pos token.Position
is_skipped bool // module main can be skipped in single file programs
}

View File

@ -193,6 +193,7 @@ pub fn (mut f Fmt) mod(mod ast.Module) {
if mod.is_skipped {
return
}
f.attrs(mod.attrs)
f.writeln('module $mod.name\n')
}

View File

@ -0,0 +1,18 @@
[manualfree]
module main
fn abc() {
x := 'abc should be autofreed'
println(x)
}
[manualfree]
fn xyz() {
x := 'xyz should do its own memory management'
println(x)
}
fn main() {
abc()
xyz()
}

View File

@ -156,7 +156,7 @@ pub fn (mut p Parser) call_args() []ast.CallArg {
fn (mut p Parser) fn_decl() ast.FnDecl {
p.top_level_statement_start()
start_pos := p.tok.position()
is_manualfree := p.attrs.contains('manualfree')
is_manualfree := p.is_manualfree || p.attrs.contains('manualfree')
is_deprecated := p.attrs.contains('deprecated')
is_direct_arr := p.attrs.contains('direct_array_access')
mut is_unsafe := p.attrs.contains('unsafe')

View File

@ -45,6 +45,7 @@ mut:
or_is_handled bool // ignore `or` in this expression
builtin_mod bool // are we in the `builtin` module?
mod string // current module name
is_manualfree bool // true when `[manualfree] module abc`, makes *all* fns in the current .v file, opt out of autofree
attrs []table.Attr // attributes before next decl stmt
expr_mod string // for constructing full type names in parse_type()
scope &ast.Scope
@ -817,10 +818,12 @@ fn (mut p Parser) attributes() {
}
fn (mut p Parser) parse_attr() table.Attr {
apos := p.prev_tok.position()
if p.tok.kind == .key_unsafe {
p.next()
return table.Attr{
name: 'unsafe'
pos: apos.extend(p.tok.position())
}
}
mut is_ctdefine := false
@ -862,6 +865,7 @@ fn (mut p Parser) parse_attr() table.Attr {
is_ctdefine: is_ctdefine
arg: arg
is_string_arg: is_string_arg
pos: apos.extend(p.tok.position())
}
}
@ -1670,10 +1674,16 @@ fn (mut p Parser) parse_number_literal() ast.Expr {
}
fn (mut p Parser) module_decl() ast.Module {
mut module_attrs := []table.Attr{}
if p.tok.kind == .lsbr {
p.attributes()
module_attrs = p.attrs
}
mut name := 'main'
is_skipped := p.tok.kind != .key_module
mut module_pos := token.Position{}
if !is_skipped {
p.attrs = []
module_pos = p.tok.position()
p.next()
mut pos := p.tok.position()
@ -1710,8 +1720,22 @@ fn (mut p Parser) module_decl() ast.Module {
}
p.mod = full_mod
p.builtin_mod = p.mod == 'builtin'
if !is_skipped {
for ma in module_attrs {
match ma.name {
'manualfree' {
p.is_manualfree = true
}
else {
p.error_with_pos('unknown module attribute `[$ma.name]`', ma.pos)
return ast.Module{}
}
}
}
}
return ast.Module{
name: full_mod
attrs: module_attrs
is_skipped: is_skipped
pos: module_pos
}

View File

@ -3,6 +3,8 @@
// that can be found in the LICENSE file.
module table
import v.token
// e.g. `[unsafe]`
pub struct Attr {
pub:
@ -11,6 +13,7 @@ pub:
is_ctdefine bool // [if name]
arg string // [name: arg]
is_string_arg bool // [name: 'arg']
pos token.Position
}
// no square brackets