syntax: new global variable declaration syntax (#6540)

pull/6474/head
Henrixounez 2020-10-03 07:03:44 +02:00 committed by GitHub
parent 8ac0bd44bd
commit c9574ae7d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 174 additions and 52 deletions

View File

@ -21,7 +21,7 @@ pub type Stmt = AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDe
GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | Return | SqlStmt |
StructDecl | TypeDecl
pub type ScopeObject = ConstField | GlobalDecl | Var
pub type ScopeObject = ConstField | GlobalField | Var
pub struct Type {
pub:
@ -346,7 +346,7 @@ pub mut:
is_changed bool // to detect mutable vars that are never changed
}
pub struct GlobalDecl {
pub struct GlobalField {
pub:
name string
expr Expr
@ -354,6 +354,15 @@ pub:
pos token.Position
pub mut:
typ table.Type
comments []Comment
}
pub struct GlobalDecl {
pub:
pos token.Position
pub mut:
fields []GlobalField
end_comments []Comment
}
pub struct File {

View File

@ -38,6 +38,7 @@ pub mut:
const_decl string
const_deps []string
const_names []string
global_names []string
locked_names []string // vars that are currently locked
rlocked_names []string // vars that are currently read-locked
pref &pref.Preferences // Preferences shared from V struct
@ -1954,7 +1955,7 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
if left_type != 0 {
match mut left.obj as v {
ast.Var { v.typ = left_type }
ast.GlobalDecl { v.typ = left_type }
ast.GlobalField { v.typ = left_type }
else {}
}
/*
@ -2372,7 +2373,13 @@ fn (mut c Checker) stmt(node ast.Stmt) {
c.in_for_count--
}
ast.GlobalDecl {
c.check_valid_snake_case(node.name, 'global name', node.pos)
for field in node.fields {
c.check_valid_snake_case(field.name, 'global name', field.pos)
if field.name in c.global_names {
c.error('duplicate global `$field.name`', field.pos)
}
c.global_names << field.name
}
}
ast.GoStmt {
if node.call_expr !is ast.CallExpr {
@ -2865,7 +2872,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
start_scope := c.file.scope.innermost(ident.pos.pos)
if obj1 := start_scope.find(ident.name) {
match mut obj1 as obj {
ast.GlobalDecl {
ast.GlobalField {
ident.kind = .global
ident.info = ast.IdentVar{
typ: obj.typ

View File

@ -0,0 +1,3 @@
vlib/v/checker/tests/globals/assign_no_type.vv:1:21: error: global assign must have a type and value, use `__global ( name = type(value) )` or `__global ( name type )`
1 | __global ( test = 0 )
| ^

View File

@ -0,0 +1 @@
__global ( test = 0 )

View File

@ -0,0 +1,3 @@
vlib/v/checker/tests/globals/assign_no_value.vv:1:23: error: global assign must have a type and value, use `__global ( name = type(value) )` or `__global ( name type )`
1 | __global ( test = int )
| ^

View File

@ -0,0 +1 @@
__global ( test = int )

View File

@ -1,3 +1,3 @@
vlib/v/checker/tests/globals/incorrect_name_global.vv:1:1: error: global name `A` cannot contain uppercase letters, use snake_case instead
1 | __global A int = 1
| ~~~~~~~~~~
vlib/v/checker/tests/globals/incorrect_name_global.vv:1:12: error: global name `A` cannot contain uppercase letters, use snake_case instead
1 | __global ( A = int(1) )
| ^

View File

@ -1 +1 @@
__global A int = 1
__global ( A = int(1) )

View File

@ -0,0 +1,3 @@
vlib/v/checker/tests/globals/no_type.vv:1:17: error: bad type syntax
1 | __global ( test )
| ^

View File

@ -0,0 +1 @@
__global ( test )

View File

@ -1,6 +1,6 @@
vlib/v/checker/tests/globals_error.vv:2:1: error: use `v --enable-globals ...` to enable globals
1 |
2 | __global rfcnt int
2 | __global ( rfcnt int )
| ~~~~~~~~
3 |
4 | fn abc(){

View File

@ -1,5 +1,5 @@
__global rfcnt int
__global ( rfcnt int )
fn abc(){
rfcnt = 2

View File

@ -399,13 +399,7 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
f.writeln('}')
}
ast.GlobalDecl {
f.write('__global $it.name ')
f.write(f.type_to_str(it.typ))
if it.has_expr {
f.write(' = ')
f.expr(it.expr)
}
f.writeln('')
f.global_decl(it)
}
ast.GoStmt {
f.write('go ')
@ -1885,6 +1879,58 @@ pub fn (mut f Fmt) const_decl(it ast.ConstDecl) {
f.writeln(')\n')
}
fn (mut f Fmt) global_decl(it ast.GlobalDecl) {
single := it.fields.len == 1
if single {
f.write('__global ( ')
} else {
f.write('__global (')
f.writeln('')
f.indent++
}
mut max := 0
mut has_assign := false
for field in it.fields {
if field.name.len > max {
max = field.name.len
}
if field.has_expr {
has_assign = true
}
}
for field in it.fields {
comments := field.comments
for comment in comments {
f.comment(comment, {
inline: true
})
f.writeln('')
}
f.write('$field.name ')
f.write(strings.repeat(` `, max - field.name.len))
if field.has_expr {
f.write('= ')
f.write(f.type_to_str(field.typ))
f.write('(')
f.expr(field.expr)
f.write(')')
} else {
if !single && has_assign {
f.write(' ')
}
f.write('${f.type_to_str(field.typ)} ')
}
if !single {
f.writeln('')
}
}
if !single {
f.indent--
}
f.comments_after_last_field(it.end_comments)
f.writeln(')\n')
}
fn (mut f Fmt) is_external_name(name string) bool {
if name.len > 2 && name[0] == `C` && name[1] == `.` {
return true

View File

@ -937,8 +937,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
g.writeln('}')
}
ast.GlobalDecl {
styp := g.typ(node.typ)
g.definitions.writeln('$styp $node.name; // global')
g.global_decl(node)
}
ast.GoStmt {
g.go_stmt(node)
@ -3662,6 +3661,17 @@ fn (mut g Gen) const_decl_init_later(mod, name, val string, typ table.Type) {
}
}
fn (mut g Gen) global_decl(node ast.GlobalDecl) {
for field in node.fields {
styp := g.typ(field.typ)
if field.has_expr {
g.definitions.writeln('$styp $field.name = $field.expr; // global')
} else {
g.definitions.writeln('$styp $field.name; // global')
}
}
}
fn (mut g Gen) go_back_out(n int) {
g.out.go_back(n)
}

View File

@ -1676,41 +1676,79 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
p.error('use `v --enable-globals ...` to enable globals')
}
start_pos := p.tok.position()
p.next()
pos := start_pos.extend(p.tok.position())
name := p.check_name()
// println(name)
typ := p.parse_type()
mut expr := ast.Expr{}
has_expr := p.tok.kind == .assign
if has_expr {
p.next()
expr = p.expr(0)
end_pos := p.tok.position()
p.check(.key_global)
if p.tok.kind != .lpar {
// Need to work for intermediate V Compiler for PRs process
// p.error('globals must be grouped, e.g. `__global ( a = int(1) )`')
pos := p.tok.position()
name := p.check_name()
typ := p.parse_type()
mut expr := ast.Expr{}
has_expr := p.tok.kind == .assign
if has_expr {
p.next()
expr = p.expr(0)
}
mut fields := []ast.GlobalField{}
field := ast.GlobalField{
name: name
has_expr: has_expr
expr: expr
pos: pos
typ: typ
comments: []ast.Comment{}
}
fields << field
p.global_scope.register(field.name, field)
return ast.GlobalDecl{
fields: fields
pos: start_pos.extend(end_pos)
end_comments: []ast.Comment{}
}
}
// p.genln(p.table.cgen_name_type_pair(name, typ))
/*
mut g := p.table.cgen_name_type_pair(name, typ)
if p.tok == .assign {
p.next()
g += ' = '
_,expr := p.tmp_expr()
g += expr
p.next() // (
mut fields := []ast.GlobalField{}
mut comments := []ast.Comment{}
for {
comments = p.eat_comments()
if p.tok.kind == .rpar {
break
}
pos := p.tok.position()
name := p.check_name()
has_expr := p.tok.kind == .assign
if has_expr {
p.next() // =
}
typ := p.parse_type()
mut expr := ast.Expr{}
if has_expr {
if p.tok.kind != .lpar {
p.error('global assign must have a type and value, use `__global ( name = type(value) )` or `__global ( name type )`')
}
p.next() // (
expr = p.expr(0)
p.check(.rpar)
}
field := ast.GlobalField{
name: name
has_expr: has_expr
expr: expr
pos: pos
typ: typ
comments: comments
}
fields << field
p.global_scope.register(field.name, field)
comments = []
}
// p.genln('; // global')
g += '; // global'
if !p.cgen.nogen {
p.cgen.consts << g
p.check(.rpar)
return ast.GlobalDecl{
pos: start_pos.extend(end_pos)
fields: fields
end_comments: comments
}
*/
glob := ast.GlobalDecl{
name: name
typ: typ
pos: pos
has_expr: has_expr
expr: expr
}
p.global_scope.register(name, glob)
return glob
}
fn (mut p Parser) enum_decl() ast.EnumDecl {