From b0cfd3fa670e6b92aeb14b114829cfc14d9afb04 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 26 May 2020 00:00:48 +0300 Subject: [PATCH] parser: reimplement [flag] enum support. Add p.vcodegen too --- cmd/tools/vtest-fixed.v | 1 - vlib/v/ast/ast.v | 1 + vlib/v/checker/checker.v | 4 ++-- .../tests/assign_expr_undefined_err_a.out | 2 +- .../tests/assign_expr_undefined_err_b.out | 2 +- .../tests/assign_expr_undefined_err_c.out | 2 +- .../tests/assign_expr_undefined_err_d.out | 2 +- vlib/v/checker/tests/match_undefined_cond.out | 2 +- vlib/v/parser/assign.v | 2 +- vlib/v/parser/parser.v | 21 ++++++++++++++++++- vlib/v/scanner/scanner.v | 12 +++++++++++ vlib/v/table/atypes.v | 1 + vlib/v/tests/repl/error.repl | 2 +- 13 files changed, 43 insertions(+), 11 deletions(-) diff --git a/cmd/tools/vtest-fixed.v b/cmd/tools/vtest-fixed.v index 5dc8fb0f21..61a87bf6d7 100644 --- a/cmd/tools/vtest-fixed.v +++ b/cmd/tools/vtest-fixed.v @@ -6,7 +6,6 @@ import v.pref const ( skip_test_files = [ - 'vlib/v/tests/enum_bitfield_test.v', 'vlib/net/http/http_httpbin_test.v', ] skip_on_musl = [ diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index ccec340884..aa0a479de3 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -577,6 +577,7 @@ pub struct EnumDecl { pub: name string is_pub bool + is_flag bool // true when the enum has [flag] tag fields []EnumField pos token.Position } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 32ba69b0cc..9e4f16629e 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1401,7 +1401,7 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type { // scope := c.file.scope.innermost(array_init.pos.pos) // eprintln('scope: ${scope.str()}') // scope.find(it.name) or { - // c.error('undefined: `$it.name`', array_init.pos) + // c.error('undefined ident: `$it.name`', array_init.pos) // } mut full_const_name := if it.mod == 'main' { it.name } else { it.mod + '.' + it.name } @@ -1951,7 +1951,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type { return table.int_type } if ident.name != '_' { - c.error('undefined: `$ident.name`', ident.pos) + c.error('undefined ident: `$ident.name`', ident.pos) } if c.table.known_type(ident.name) { // e.g. `User` in `json.decode(User, '...')` diff --git a/vlib/v/checker/tests/assign_expr_undefined_err_a.out b/vlib/v/checker/tests/assign_expr_undefined_err_a.out index e3525785ca..2d51e38072 100644 --- a/vlib/v/checker/tests/assign_expr_undefined_err_a.out +++ b/vlib/v/checker/tests/assign_expr_undefined_err_a.out @@ -1,4 +1,4 @@ -vlib/v/checker/tests/assign_expr_undefined_err_a.v:2:7: error: undefined: `a` +vlib/v/checker/tests/assign_expr_undefined_err_a.v:2:7: error: undefined variable: `a` 1 | fn main() { 2 | a := a | ^ diff --git a/vlib/v/checker/tests/assign_expr_undefined_err_b.out b/vlib/v/checker/tests/assign_expr_undefined_err_b.out index 9d320e7292..cb320a5733 100644 --- a/vlib/v/checker/tests/assign_expr_undefined_err_b.out +++ b/vlib/v/checker/tests/assign_expr_undefined_err_b.out @@ -1,4 +1,4 @@ -vlib/v/checker/tests/assign_expr_undefined_err_b.v:2:10: error: undefined: `a` +vlib/v/checker/tests/assign_expr_undefined_err_b.v:2:10: error: undefined variable: `a` 1 | fn main() { 2 | a, b := a, b | ^ diff --git a/vlib/v/checker/tests/assign_expr_undefined_err_c.out b/vlib/v/checker/tests/assign_expr_undefined_err_c.out index 47227f236f..ec4032b800 100644 --- a/vlib/v/checker/tests/assign_expr_undefined_err_c.out +++ b/vlib/v/checker/tests/assign_expr_undefined_err_c.out @@ -1,4 +1,4 @@ -vlib/v/checker/tests/assign_expr_undefined_err_c.v:2:10: error: undefined: `a` +vlib/v/checker/tests/assign_expr_undefined_err_c.v:2:10: error: undefined variable: `a` 1 | fn main() { 2 | a, b := a + 1, b * 3 | ^ diff --git a/vlib/v/checker/tests/assign_expr_undefined_err_d.out b/vlib/v/checker/tests/assign_expr_undefined_err_d.out index 79f1fa69c8..449f302481 100644 --- a/vlib/v/checker/tests/assign_expr_undefined_err_d.out +++ b/vlib/v/checker/tests/assign_expr_undefined_err_d.out @@ -1,4 +1,4 @@ -vlib/v/checker/tests/assign_expr_undefined_err_d.v:2:9: error: undefined: `s` +vlib/v/checker/tests/assign_expr_undefined_err_d.v:2:9: error: undefined variable: `s` 1 | fn main() { 2 | s := '$s' | ^ diff --git a/vlib/v/checker/tests/match_undefined_cond.out b/vlib/v/checker/tests/match_undefined_cond.out index f2ea10dbf9..ae8e40e0e7 100644 --- a/vlib/v/checker/tests/match_undefined_cond.out +++ b/vlib/v/checker/tests/match_undefined_cond.out @@ -1,4 +1,4 @@ -vlib/v/checker/tests/match_undefined_cond.v:4:15: error: undefined: `Asd` +vlib/v/checker/tests/match_undefined_cond.v:4:15: error: undefined ident: `Asd` 2 | 3 | fn main() { 4 | res := match Asd { diff --git a/vlib/v/parser/assign.v b/vlib/v/parser/assign.v index 265190900b..646edcf605 100644 --- a/vlib/v/parser/assign.v +++ b/vlib/v/parser/assign.v @@ -14,7 +14,7 @@ fn (mut p Parser) check_undefined_variables(idents []ast.Ident, expr ast.Expr) { ast.Ident { for ident in idents { if ident.name == it.name { - p.error_with_pos('undefined: `$it.name`', it.pos) + p.error_with_pos('undefined variable: `$it.name`', it.pos) } } } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 6b9262d717..ab3301f098 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -94,6 +94,7 @@ pub fn parse_file(path string, b_table &table.Table, comments_mode scanner.Comme global_scope: global_scope } // comments_mode: comments_mode + p.init_parse_fns() p.read_first_token() for p.tok.kind == .comment { stmts << p.comment() @@ -126,6 +127,7 @@ pub fn parse_file(path string, b_table &table.Table, comments_mode scanner.Comme // println('nr stmts = $stmts.len') // println(stmts[0]) p.scope.end_pos = p.tok.pos + // return ast.File{ path: path mod: module_decl @@ -210,7 +212,6 @@ pub fn parse_files(paths []string, table &table.Table, pref &pref.Preferences, g pub fn (p &Parser) init_parse_fns() { // p.prefix_parse_fns = make(100, 100, sizeof(PrefixParseFn)) // p.prefix_parse_fns[token.Kind.name] = parse_name - println('') } pub fn (mut p Parser) read_first_token() { @@ -1371,17 +1372,35 @@ fn (mut p Parser) enum_decl() ast.EnumDecl { } } p.check(.rcbr) + attr := p.attr + is_flag := attr == 'flag' + if is_flag { + if fields.len > 32 { + p.error('when an enum is used as bit field, it must have a max of 32 fields') + } + pubfn := if p.mod == 'main' { 'fn' } else { 'pub fn' } + p.scanner.codegen(' +// +$pubfn ( e &$name) has(flag $name) bool { return (int(*e) & (1 << int(flag))) != 0 } +$pubfn (mut e $name) set(flag $name) { unsafe{ *e = int(*e) | (1 << int(flag)) } } +$pubfn (mut e $name) clear(flag $name) { unsafe{ *e = int(*e) & ~(1 << int(flag)) } } +$pubfn (mut e $name) toggle(flag $name) { unsafe{ *e = int(*e) ^ (1 << int(flag)) } } +// + ') + } p.table.register_type_symbol(table.TypeSymbol{ kind: .enum_ name: name mod: p.mod info: table.Enum{ vals: vals + is_flag: is_flag } }) return ast.EnumDecl{ name: name is_pub: is_pub + is_flag: is_flag fields: fields pos: start_pos.extend(end_pos) } diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v index 9c2de84ebc..e367f41087 100644 --- a/vlib/v/scanner/scanner.v +++ b/vlib/v/scanner/scanner.v @@ -1121,3 +1121,15 @@ pub fn (s &Scanner) error(msg string) { pub fn verror(s string) { util.verror('scanner error', s) } + +pub fn (mut s Scanner) codegen(newtext string) { + // codegen makes sense only during normal compilation + // feeding code generated V code to vfmt or vdoc will + // cause them to output/document ephemeral stuff. + if s.comments_mode == .skip_comments { + s.text += newtext + $if debug_codegen ? { + eprintln('scanner.codegen:\n $newtext') + } + } +} diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index 5d174e4308..9a526090bd 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -611,6 +611,7 @@ pub mut: pub struct Enum { pub: vals []string + is_flag bool } pub struct Alias { diff --git a/vlib/v/tests/repl/error.repl b/vlib/v/tests/repl/error.repl index db674c3b6c..bd73d7237c 100644 --- a/vlib/v/tests/repl/error.repl +++ b/vlib/v/tests/repl/error.repl @@ -1,6 +1,6 @@ println(a) ===output=== -.vrepl.v:2:9: error: undefined: `a` +.vrepl.v:2:9: error: undefined ident: `a` 1 | 2 | println(a) | ^