unsafe keyword + make array.free() an unsafe method

pull/2460/head
Alexander Medvednikov 2019-10-20 19:59:53 +03:00
parent f7c00b8180
commit 1b518c158b
6 changed files with 93 additions and 62 deletions

View File

@ -234,6 +234,7 @@ pub fn (a array) clone() array {
}
//pub fn (a []int) free() {
[unsafe_fn]
pub fn (a array) free() {
//if a.is_slice {
//return

View File

@ -0,0 +1,63 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module compiler
fn (p mut Parser) enum_decl(_enum_name string) {
mut enum_name := _enum_name
// Specify full type name
if !p.builtin_mod && p.mod != 'main' {
enum_name = p.prepend_mod(enum_name)
}
// Skip empty enums
if enum_name != 'int' && !p.first_pass() {
p.cgen.typedefs << 'typedef int $enum_name;'
}
p.check(.lcbr)
mut val := 0
mut fields := []string
for p.tok == .name {
field := p.check_name()
fields << field
p.fgenln('')
name := '${mod_gen_name(p.mod)}__${enum_name}_$field'
if p.pass == .main {
p.cgen.consts << '#define $name $val'
}
if p.tok == .comma {
p.next()
}
// !!!! NAME free
if p.first_pass() {
p.table.register_const(name, enum_name, p.mod)
}
val++
}
p.table.register_type2(Type {
name: enum_name
mod: p.mod
parent: 'int'
cat: TypeCategory.enum_
enum_vals: fields.clone()
})
p.check(.rcbr)
p.fgenln('\n')
}
fn (p mut Parser) check_enum_member_access() {
T := p.find_type(p.expected_type)
if T.cat == .enum_ {
p.check(.dot)
val := p.check_name()
// Make sure this enum value exists
if !T.has_enum_val(val) {
p.error('enum `$T.name` does not have value `$val`')
}
p.gen(mod_gen_name(T.mod) + '__' + p.expected_type + '_' + val)
} else {
p.error('`$T.name` is not an enum')
}
}

View File

@ -31,6 +31,7 @@ mut:
is_method bool
returns_error bool
is_decl bool // type myfn fn(int, int)
is_unsafe bool
defer_text []string
is_generic bool
type_pars []string
@ -158,10 +159,11 @@ fn (p mut Parser) clear_vars() {
p.var_idx = 0
if p.local_vars.len > 0 {
if p.pref.autofree {
p.local_vars.free()
//p.local_vars.free()
}
p.local_vars = []Var
}
}
// Function signatures are added to the top of the .c file in the first run.
@ -182,9 +184,10 @@ fn (p mut Parser) fn_decl() {
}
*/
mut f := Fn{
mod: p.mod
is_public: p.tok == .key_pub
}
mod: p.mod
is_public: p.tok == .key_pub
is_unsafe: p.attr == 'unsafe_fn'
}
is_live := p.attr == 'live' && !p.pref.is_so && p.pref.is_live
if p.attr == 'live' && p.first_pass() && !p.pref.is_live && !p.pref.is_so {
println('INFO: run `v -live program.v` if you want to use [live] functions')
@ -631,6 +634,9 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
// p.tok == fn_name
fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type string) {
if f.is_unsafe && !p.builtin_mod && !p.inside_unsafe {
p.error('you are calling an unsafe function outside of an unsafe block')
}
if !f.is_public && !f.is_c && !p.pref.is_test && !f.is_interface && f.mod != p.mod {
if f.name == 'contains' {
println('use `value in numbers` instead of `numbers.contains(value)`')
@ -1154,7 +1160,7 @@ fn (p mut Parser) replace_type_params(f &Fn, ti TypeInst) []string {
r << fr
continue
}
for fi.starts_with('array_') {
for fi.starts_with('array_') {
fi = fi.right(6)
fr += 'array_'
}

View File

@ -117,6 +117,7 @@ pub mut:
pub fn (v mut V) finalize_compilation(){
// TODO remove
if v.pref.autofree {
/*
println('started freeing v struct')
v.table.typesmap.free()
v.table.obf_ids.free()
@ -131,6 +132,7 @@ pub fn (v mut V) finalize_compilation(){
free(v.table)
//for p in parsers {}
println('done!')
*/
}
}

View File

@ -52,6 +52,7 @@ mut:
inside_if_expr bool
inside_unwrapping_match_statement bool
inside_return_expr bool
inside_unsafe bool
is_struct_init bool
if_expr_cnt int
for_expr_cnt int // to detect whether `continue` can be used
@ -839,47 +840,6 @@ fn (p mut Parser) struct_decl() {
p.fgenln('\n')
}
fn (p mut Parser) enum_decl(_enum_name string) {
mut enum_name := _enum_name
// Specify full type name
if !p.builtin_mod && p.mod != 'main' {
enum_name = p.prepend_mod(enum_name)
}
// Skip empty enums
if enum_name != 'int' && !p.first_pass() {
p.cgen.typedefs << 'typedef int $enum_name;'
}
p.check(.lcbr)
mut val := 0
mut fields := []string
for p.tok == .name {
field := p.check_name()
fields << field
p.fgenln('')
name := '${mod_gen_name(p.mod)}__${enum_name}_$field'
if p.pass == .main {
p.cgen.consts << '#define $name $val'
}
if p.tok == .comma {
p.next()
}
// !!!! NAME free
if p.first_pass() {
p.table.register_const(name, enum_name, p.mod)
}
val++
}
p.table.register_type2(Type {
name: enum_name
mod: p.mod
parent: 'int'
cat: TypeCategory.enum_
enum_vals: fields.clone()
})
p.check(.rcbr)
p.fgenln('\n')
}
// check_name checks for a name token and returns its literal
fn (p mut Parser) check_name() string {
name := p.lit
@ -1316,6 +1276,14 @@ fn (p mut Parser) statement(add_semi bool) string {
case TokenKind.hash:
p.chash()
return ''
case TokenKind.key_unsafe:
p.next()
p.inside_unsafe = true
p.check(.lcbr)
p.genln('{')
p.statements()
p.inside_unsafe = false
//p.check(.rcbr)
case TokenKind.dollar:
p.comp_time()
case TokenKind.key_if:
@ -1828,6 +1796,10 @@ fn (p mut Parser) name_expr() string {
p.next()
p.check(.dot)
val := p.lit
if !enum_type.has_enum_val(val) {
p.error('enum `$enum_type.name` does not have value `$val`')
}
// println('enum val $val')
p.gen(mod_gen_name(enum_type.mod) + '__' + enum_type.name + '_' + val)// `color = main__Color_green`
p.next()
@ -1910,21 +1882,6 @@ fn (p mut Parser) get_struct_type(name_ string, is_c bool, is_ptr bool) string {
return p.struct_init(name)
}
fn (p mut Parser) check_enum_member_access() {
T := p.find_type(p.expected_type)
if T.cat == .enum_ {
p.check(.dot)
val := p.check_name()
// Make sure this enum value exists
if !T.has_enum_val(val) {
p.error('enum `$T.name` does not have value `$val`')
}
p.gen(mod_gen_name(T.mod) + '__' + p.expected_type + '_' + val)
} else {
p.error('`$T.name` is not an enum')
}
}
fn (p mut Parser) get_var_type(name string, is_ptr bool, is_deref bool) string {
v := p.find_var_check_new_var(name) or { return "" }
if name == '_' {
@ -4212,7 +4169,7 @@ fn (p mut Parser) check_unused_imports() {
fn (p mut Parser) is_next_expr_fn_call() (bool, string) {
mut next_expr := p.lit
mut is_fn_call := p.peek() == .lpar
mut is_fn_call := p.peek() == .lpar
if !is_fn_call {
mut i := p.token_idx+1
for (p.tokens[i].tok == .dot || p.tokens[i].tok == .name) &&

View File

@ -110,6 +110,7 @@ enum TokenKind {
key_union
key_pub
key_static
key_unsafe
keyword_end
}
@ -210,6 +211,7 @@ fn build_token_str() []string {
s[TokenKind.key_break] = 'break'
s[TokenKind.key_import] = 'import'
s[TokenKind.key_embed] = 'embed'
s[TokenKind.key_unsafe] = 'unsafe'
//Tokens[key_typeof] = 'typeof'
s[TokenKind.key_default] = 'default'
s[TokenKind.key_enum] = 'enum'