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