syntax: new global variable declaration syntax (#6540)
parent
8ac0bd44bd
commit
c9574ae7d7
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 )
|
||||
| ^
|
|
@ -0,0 +1 @@
|
|||
__global ( test = 0 )
|
|
@ -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 )
|
||||
| ^
|
|
@ -0,0 +1 @@
|
|||
__global ( test = int )
|
|
@ -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) )
|
||||
| ^
|
||||
|
|
|
@ -1 +1 @@
|
|||
__global A int = 1
|
||||
__global ( A = int(1) )
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
vlib/v/checker/tests/globals/no_type.vv:1:17: error: bad type syntax
|
||||
1 | __global ( test )
|
||||
| ^
|
|
@ -0,0 +1 @@
|
|||
__global ( test )
|
|
@ -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(){
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
__global rfcnt int
|
||||
__global ( rfcnt int )
|
||||
|
||||
fn abc(){
|
||||
rfcnt = 2
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue