parser: reimplement [flag] enum support. Add p.vcodegen too

pull/5031/head
Delyan Angelov 2020-05-26 00:00:48 +03:00 committed by GitHub
parent 5825e467b8
commit b0cfd3fa67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 43 additions and 11 deletions

View File

@ -6,7 +6,6 @@ import v.pref
const ( const (
skip_test_files = [ skip_test_files = [
'vlib/v/tests/enum_bitfield_test.v',
'vlib/net/http/http_httpbin_test.v', 'vlib/net/http/http_httpbin_test.v',
] ]
skip_on_musl = [ skip_on_musl = [

View File

@ -577,6 +577,7 @@ pub struct EnumDecl {
pub: pub:
name string name string
is_pub bool is_pub bool
is_flag bool // true when the enum has [flag] tag
fields []EnumField fields []EnumField
pos token.Position pos token.Position
} }

View File

@ -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) // scope := c.file.scope.innermost(array_init.pos.pos)
// eprintln('scope: ${scope.str()}') // eprintln('scope: ${scope.str()}')
// scope.find(it.name) or { // 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 + '.' + mut full_const_name := if it.mod == 'main' { it.name } else { it.mod + '.' +
it.name } it.name }
@ -1951,7 +1951,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
return table.int_type return table.int_type
} }
if ident.name != '_' { 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) { if c.table.known_type(ident.name) {
// e.g. `User` in `json.decode(User, '...')` // e.g. `User` in `json.decode(User, '...')`

View File

@ -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() { 1 | fn main() {
2 | a := a 2 | a := a
| ^ | ^

View File

@ -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() { 1 | fn main() {
2 | a, b := a, b 2 | a, b := a, b
| ^ | ^

View File

@ -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() { 1 | fn main() {
2 | a, b := a + 1, b * 3 2 | a, b := a + 1, b * 3
| ^ | ^

View File

@ -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() { 1 | fn main() {
2 | s := '$s' 2 | s := '$s'
| ^ | ^

View File

@ -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 | 2 |
3 | fn main() { 3 | fn main() {
4 | res := match Asd { 4 | res := match Asd {

View File

@ -14,7 +14,7 @@ fn (mut p Parser) check_undefined_variables(idents []ast.Ident, expr ast.Expr) {
ast.Ident { ast.Ident {
for ident in idents { for ident in idents {
if ident.name == it.name { if ident.name == it.name {
p.error_with_pos('undefined: `$it.name`', it.pos) p.error_with_pos('undefined variable: `$it.name`', it.pos)
} }
} }
} }

View File

@ -94,6 +94,7 @@ pub fn parse_file(path string, b_table &table.Table, comments_mode scanner.Comme
global_scope: global_scope global_scope: global_scope
} }
// comments_mode: comments_mode // comments_mode: comments_mode
p.init_parse_fns()
p.read_first_token() p.read_first_token()
for p.tok.kind == .comment { for p.tok.kind == .comment {
stmts << p.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('nr stmts = $stmts.len')
// println(stmts[0]) // println(stmts[0])
p.scope.end_pos = p.tok.pos p.scope.end_pos = p.tok.pos
//
return ast.File{ return ast.File{
path: path path: path
mod: module_decl 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() { pub fn (p &Parser) init_parse_fns() {
// p.prefix_parse_fns = make(100, 100, sizeof(PrefixParseFn)) // p.prefix_parse_fns = make(100, 100, sizeof(PrefixParseFn))
// p.prefix_parse_fns[token.Kind.name] = parse_name // p.prefix_parse_fns[token.Kind.name] = parse_name
println('')
} }
pub fn (mut p Parser) read_first_token() { pub fn (mut p Parser) read_first_token() {
@ -1371,17 +1372,35 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
} }
} }
p.check(.rcbr) 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{ p.table.register_type_symbol(table.TypeSymbol{
kind: .enum_ kind: .enum_
name: name name: name
mod: p.mod mod: p.mod
info: table.Enum{ info: table.Enum{
vals: vals vals: vals
is_flag: is_flag
} }
}) })
return ast.EnumDecl{ return ast.EnumDecl{
name: name name: name
is_pub: is_pub is_pub: is_pub
is_flag: is_flag
fields: fields fields: fields
pos: start_pos.extend(end_pos) pos: start_pos.extend(end_pos)
} }

View File

@ -1121,3 +1121,15 @@ pub fn (s &Scanner) error(msg string) {
pub fn verror(s string) { pub fn verror(s string) {
util.verror('scanner error', s) 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')
}
}
}

View File

@ -611,6 +611,7 @@ pub mut:
pub struct Enum { pub struct Enum {
pub: pub:
vals []string vals []string
is_flag bool
} }
pub struct Alias { pub struct Alias {

View File

@ -1,6 +1,6 @@
println(a) println(a)
===output=== ===output===
.vrepl.v:2:9: error: undefined: `a` .vrepl.v:2:9: error: undefined ident: `a`
1 | 1 |
2 | println(a) 2 | println(a)
| ^ | ^