From 1b518c158b3f5ec4ac9ddecad5b7e499867fdc2a Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Sun, 20 Oct 2019 19:59:53 +0300 Subject: [PATCH] unsafe keyword + make array.free() an unsafe method --- vlib/builtin/array.v | 1 + vlib/compiler/enum.v | 63 +++++++++++++++++++++++++++++++++++++ vlib/compiler/fn.v | 16 +++++++--- vlib/compiler/main.v | 2 ++ vlib/compiler/parser.v | 71 +++++++++--------------------------------- vlib/compiler/token.v | 2 ++ 6 files changed, 93 insertions(+), 62 deletions(-) create mode 100644 vlib/compiler/enum.v diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index d9d4742c33..bdf73ed750 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -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 diff --git a/vlib/compiler/enum.v b/vlib/compiler/enum.v new file mode 100644 index 0000000000..6a207c4e52 --- /dev/null +++ b/vlib/compiler/enum.v @@ -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') + } +} + + diff --git a/vlib/compiler/fn.v b/vlib/compiler/fn.v index e7e2d9f891..a478b98549 100644 --- a/vlib/compiler/fn.v +++ b/vlib/compiler/fn.v @@ -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_' } diff --git a/vlib/compiler/main.v b/vlib/compiler/main.v index 616f88186d..8b73397fce 100644 --- a/vlib/compiler/main.v +++ b/vlib/compiler/main.v @@ -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!') + */ } } diff --git a/vlib/compiler/parser.v b/vlib/compiler/parser.v index 7792face67..3b480ea034 100644 --- a/vlib/compiler/parser.v +++ b/vlib/compiler/parser.v @@ -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) && diff --git a/vlib/compiler/token.v b/vlib/compiler/token.v index d5edf087c7..99cd980900 100644 --- a/vlib/compiler/token.v +++ b/vlib/compiler/token.v @@ -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'