ast: expr.Position; struct field refactoring
							parent
							
								
									8bb11d9035
								
							
						
					
					
						commit
						402e55d115
					
				
							
								
								
									
										103
									
								
								vlib/v/ast/ast.v
								
								
								
								
							
							
						
						
									
										103
									
								
								vlib/v/ast/ast.v
								
								
								
								
							|  | @ -157,15 +157,23 @@ pub: | |||
| 	field_names []string | ||||
| } | ||||
| 
 | ||||
| pub struct StructInitField { | ||||
| pub: | ||||
| 	name          string | ||||
| 	expr          Expr | ||||
| 	pos			  token.Position | ||||
| mut: | ||||
| 	typ           table.Type | ||||
| 	expected_type table.Type | ||||
| } | ||||
| 
 | ||||
| pub struct StructInit { | ||||
| pub: | ||||
| 	pos            token.Position | ||||
| 	fields         []string | ||||
| 	exprs          []Expr | ||||
| 	pos      token.Position | ||||
| 	fields   []StructInitField | ||||
| 	is_short bool | ||||
| mut: | ||||
| 	typ            table.Type | ||||
| 	expr_types     []table.Type | ||||
| 	expected_types []table.Type | ||||
| 	typ      table.Type | ||||
| } | ||||
| 
 | ||||
| // import statement
 | ||||
|  | @ -723,3 +731,86 @@ pub fn expr_is_call(expr Expr) bool { | |||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn (expr Expr) position() token.Position { | ||||
| 	// all uncommented have to be implemented
 | ||||
| 	match mut expr { | ||||
| 		ArrayInit { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		AsCast { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.Ident { }
 | ||||
| 		AssignExpr { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.CastExpr { }
 | ||||
| 		Assoc { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.BoolLiteral { }
 | ||||
| 		CallExpr { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.CharLiteral { }
 | ||||
| 		EnumVal { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.FloatLiteral { }
 | ||||
| 		IfExpr { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.IfGuardExpr { }
 | ||||
| 		IndexExpr { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		InfixExpr { | ||||
| 			left_pos := it.left.position() | ||||
| 			right_pos := it.right.position() | ||||
| 			if left_pos.pos == 0 || right_pos.pos == 0 { | ||||
| 				return it.pos | ||||
| 			} | ||||
| 			return token.Position{ | ||||
| 				line_nr: it.pos.line_nr | ||||
| 				pos: left_pos.pos | ||||
| 				len: right_pos.pos - left_pos.pos + right_pos.len | ||||
| 			} | ||||
| 		} | ||||
| 		IntegerLiteral { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		MapInit { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		MatchExpr { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		PostfixExpr { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.None { }
 | ||||
| 		PrefixExpr { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.ParExpr { }
 | ||||
| 		SelectorExpr { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.SizeOf { }
 | ||||
| 		StringLiteral { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		StringInterLiteral { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.Type { }
 | ||||
| 		StructInit { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.TypeOf { }
 | ||||
| 		else { | ||||
| 			return token.Position{} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -123,56 +123,51 @@ pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type { | |||
| 		// string & array are also structs but .kind of string/array
 | ||||
| 		.struct_, .string, .array { | ||||
| 			info := type_sym.info as table.Struct | ||||
| 			is_short_syntax := struct_init.fields.len == 0 | ||||
| 			if struct_init.exprs.len > info.fields.len { | ||||
| 			if struct_init.is_short && struct_init.fields.len > info.fields.len { | ||||
| 				c.error('too many fields', struct_init.pos) | ||||
| 			} | ||||
| 			mut inited_fields := []string | ||||
| 			for i, expr in struct_init.exprs { | ||||
| 				if is_short_syntax && i >= info.fields.len { | ||||
| 					// It doesn't make sense to check for fields that don't exist.
 | ||||
| 					// We should just stop here.
 | ||||
| 					break | ||||
| 				} | ||||
| 				// struct_field info.
 | ||||
| 				field_name := if is_short_syntax { info.fields[i].name } else { struct_init.fields[i] } | ||||
| 				if field_name in inited_fields { | ||||
| 					c.error('duplicate field name in struct literal: `$field_name`', struct_init.pos) | ||||
| 					continue | ||||
| 				} | ||||
| 				inited_fields << field_name | ||||
| 				mut field := if is_short_syntax { | ||||
| 					info.fields[i] | ||||
| 			for i, field in struct_init.fields { | ||||
| 				mut info_field := table.Field{} | ||||
| 				mut field_name := '' | ||||
| 				if struct_init.is_short { | ||||
| 					if i >= info.fields.len { | ||||
| 						// It doesn't make sense to check for fields that don't exist.
 | ||||
| 						// We should just stop here.
 | ||||
| 						break | ||||
| 					} | ||||
| 					info_field = info.fields[i] | ||||
| 					field_name = info_field.name | ||||
| 					struct_init.fields[i].name = field_name | ||||
| 				} else { | ||||
| 					// There is no guarantee that `i` will not be out of bounds of `info.fields`
 | ||||
| 					// So we just use an empty field as placeholder here.
 | ||||
| 					table.Field{} | ||||
| 				} | ||||
| 				if !is_short_syntax { | ||||
| 					mut found_field := false | ||||
| 					field_name = field.name | ||||
| 					mut exists := false | ||||
| 					for f in info.fields { | ||||
| 						if f.name == field_name { | ||||
| 							field = f | ||||
| 							found_field = true | ||||
| 							info_field = f | ||||
| 							exists = true | ||||
| 							break | ||||
| 						} | ||||
| 					} | ||||
| 					if !found_field { | ||||
| 						c.error('struct init: no such field `$field_name` for struct `$type_sym.name`', | ||||
| 							struct_init.pos) | ||||
| 					if !exists { | ||||
| 						c.error('struct init: no such field `$field.name` for struct `$type_sym.name`', field.pos) | ||||
| 						continue | ||||
| 					} | ||||
| 					if field_name in inited_fields { | ||||
| 						c.error('duplicate field name in struct literal: `$field_name`', field.pos) | ||||
| 						continue | ||||
| 					} | ||||
| 				} | ||||
| 				c.expected_type = field.typ | ||||
| 				expr_type := c.expr(expr) | ||||
| 				inited_fields << field_name | ||||
| 				c.expected_type = info_field.typ | ||||
| 				expr_type := c.expr(field.expr) | ||||
| 				expr_type_sym := c.table.get_type_symbol(expr_type) | ||||
| 				field_type_sym := c.table.get_type_symbol(field.typ) | ||||
| 				if !c.table.check(expr_type, field.typ) { | ||||
| 					c.error('cannot assign `$expr_type_sym.name` as `$field_type_sym.name` for field `$field.name`', | ||||
| 						struct_init.pos) | ||||
| 				field_type_sym := c.table.get_type_symbol(info_field.typ) | ||||
| 				if !c.table.check(expr_type, info_field.typ) { | ||||
| 					c.error('cannot assign `$expr_type_sym.name` as `$field_type_sym.name` for field `$info_field.name`', field.pos) | ||||
| 				} | ||||
| 				struct_init.expr_types << expr_type | ||||
| 				struct_init.expected_types << field.typ | ||||
| 				struct_init.fields[i].typ = expr_type | ||||
| 				struct_init.fields[i].expected_type = info_field.typ | ||||
| 			} | ||||
| 			// Check uninitialized refs
 | ||||
| 			for field in info.fields { | ||||
|  | @ -206,7 +201,7 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type { | |||
| 	if infix_expr.op == .left_shift { | ||||
| 		if left.kind != .array && !left.is_int() { | ||||
| 			// c.error('<< can only be used with numbers and arrays', infix_expr.pos)
 | ||||
| 			c.error('cannot shift type $right.name into $left.name', expr_pos(infix_expr.right)) | ||||
| 			c.error('cannot shift type $right.name into $left.name', infix_expr.right.position()) | ||||
| 			return table.void_type | ||||
| 		} | ||||
| 		if left.kind == .array { | ||||
|  | @ -220,7 +215,7 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type { | |||
| 				// []T << []T
 | ||||
| 				return table.void_type | ||||
| 			} | ||||
| 			c.error('cannot shift type $right.name into $left.name', expr_pos(infix_expr.right)) | ||||
| 			c.error('cannot shift type $right.name into $left.name', infix_expr.right.position()) | ||||
| 			return table.void_type | ||||
| 		} | ||||
| 	} | ||||
|  | @ -279,7 +274,7 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) { | |||
| 		left_type_sym := c.table.get_type_symbol(left_type) | ||||
| 		right_type_sym := c.table.get_type_symbol(right_type) | ||||
| 		c.error('cannot assign `$right_type_sym.name` to variable `${assign_expr.left.str()}` of type `$left_type_sym.name`', | ||||
| 			expr_pos(assign_expr.val)) | ||||
| 			assign_expr.val.position()) | ||||
| 	} | ||||
| 	c.check_expr_opt_call(assign_expr.val, right_type, true) | ||||
| } | ||||
|  | @ -662,7 +657,7 @@ pub fn (c mut Checker) enum_decl(decl ast.EnumDecl) { | |||
| 				ast.IntegerLiteral {} | ||||
| 				ast.PrefixExpr {} | ||||
| 				else { | ||||
| 					mut pos := expr_pos(field.expr) | ||||
| 					mut pos := field.expr.position() | ||||
| 					if pos.pos == 0 { | ||||
| 						pos = field.pos | ||||
| 					} | ||||
|  | @ -999,7 +994,7 @@ fn (c mut Checker) stmt(node ast.Stmt) { | |||
| 				value_type := c.table.value_type(typ) | ||||
| 				if value_type == table.void_type { | ||||
| 					typ_sym := c.table.get_type_symbol(typ) | ||||
| 					c.error('for in: cannot index `$typ_sym.name`', expr_pos(it.cond)) | ||||
| 					c.error('for in: cannot index `$typ_sym.name`', it.cond.position()) | ||||
| 				} | ||||
| 				it.cond_type = typ | ||||
| 				it.kind = sym.kind | ||||
|  | @ -1011,7 +1006,7 @@ fn (c mut Checker) stmt(node ast.Stmt) { | |||
| 		} | ||||
| 		ast.GoStmt { | ||||
| 			if !is_call_expr(it.call_expr) { | ||||
| 				c.error('expression in `go` must be a function call', expr_pos(it.call_expr))1 | ||||
| 				c.error('expression in `go` must be a function call', it.call_expr.position()) | ||||
| 			} | ||||
| 			c.expr(it.call_expr) | ||||
| 		} | ||||
|  | @ -1196,89 +1191,6 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type { | |||
| 	return table.void_type | ||||
| } | ||||
| 
 | ||||
| fn expr_pos(node ast.Expr) token.Position { | ||||
| 	// all uncommented have to be implemented
 | ||||
| 	match mut node { | ||||
| 		ast.ArrayInit { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		ast.AsCast { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.Ident { }
 | ||||
| 		ast.AssignExpr { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.CastExpr { }
 | ||||
| 		ast.Assoc { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.BoolLiteral { }
 | ||||
| 		ast.CallExpr { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.CharLiteral { }
 | ||||
| 		ast.EnumVal { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.FloatLiteral { }
 | ||||
| 		ast.IfExpr { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.IfGuardExpr { }
 | ||||
| 		ast.IndexExpr { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		ast.InfixExpr { | ||||
| 			left_pos := expr_pos(it.left) | ||||
| 			right_pos := expr_pos(it.right) | ||||
| 			if left_pos.pos == 0 || right_pos.pos == 0 { | ||||
| 				return it.pos | ||||
| 			} | ||||
| 			return token.Position{ | ||||
| 				line_nr: it.pos.line_nr | ||||
| 				pos: left_pos.pos | ||||
| 				len: right_pos.pos - left_pos.pos + right_pos.len | ||||
| 			} | ||||
| 		} | ||||
| 		ast.IntegerLiteral { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		ast.MapInit { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		ast.MatchExpr { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		ast.PostfixExpr { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.None { }
 | ||||
| 		ast.PrefixExpr { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.ParExpr { }
 | ||||
| 		ast.SelectorExpr { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.SizeOf { }
 | ||||
| 		ast.StringLiteral { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		ast.StringInterLiteral { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.Type { }
 | ||||
| 		ast.StructInit { | ||||
| 			return it.pos | ||||
| 		} | ||||
| 		// ast.TypeOf { }
 | ||||
| 		else { | ||||
| 			return token.Position{} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type { | ||||
| 	if ident.name == c.var_decl_name {		// c.checked_ident {
 | ||||
| 		c.error('unresolved: `$ident.name`', ident.pos) | ||||
|  |  | |||
|  | @ -0,0 +1,6 @@ | |||
| vlib/v/checker/tests/inout/short_struct_too_many.v:6:7: error: too many fields | ||||
|     4| | ||||
|     5| fn main() { | ||||
|     6|     t := Test{true, false} | ||||
|                 ~~~~~~~~~~~~~~~~~ | ||||
|     7| } | ||||
|  | @ -0,0 +1,7 @@ | |||
| struct Test { | ||||
| 	foo bool | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
| 	t := Test{true, false} | ||||
| } | ||||
|  | @ -0,0 +1,7 @@ | |||
| vlib/v/checker/tests/inout/struct_unknown_field.v:8:9: error: struct init: no such field `bar` for struct `Test` | ||||
|     6|     t := Test{ | ||||
|     7|         foo: true | ||||
|     8|         bar: false | ||||
|                ^ | ||||
|     9|     } | ||||
|    10| } | ||||
|  | @ -0,0 +1,10 @@ | |||
| struct Test { | ||||
| 	foo bool | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
| 	t := Test{ | ||||
|         foo: true | ||||
|         bar: false | ||||
|     } | ||||
| } | ||||
|  | @ -695,15 +695,15 @@ fn (f mut Fmt) expr(node ast.Expr) { | |||
| 			if name == 'void' { | ||||
| 				name = '' | ||||
| 			} | ||||
| 			if it.fields.len == 0 && it.exprs.len == 0 { | ||||
| 			if it.fields.len == 0 { | ||||
| 				// `Foo{}` on one line if there are no fields
 | ||||
| 				f.write('$name{}') | ||||
| 			} else if it.fields.len == 0 { | ||||
| 				// `Foo{1,2,3}` (short syntax )
 | ||||
| 				f.write('$name{') | ||||
| 				for i, expr in it.exprs { | ||||
| 					f.expr(expr) | ||||
| 					if i < it.exprs.len - 1 { | ||||
| 				for i, field in it.fields { | ||||
| 					f.expr(field.expr) | ||||
| 					if i < it.fields.len - 1 { | ||||
| 						f.write(', ') | ||||
| 					} | ||||
| 				} | ||||
|  | @ -712,8 +712,8 @@ fn (f mut Fmt) expr(node ast.Expr) { | |||
| 				f.writeln('$name{') | ||||
| 				f.indent++ | ||||
| 				for i, field in it.fields { | ||||
| 					f.write('$field: ') | ||||
| 					f.expr(it.exprs[i]) | ||||
| 					f.write('$field.name: ') | ||||
| 					f.expr(field.expr) | ||||
| 					f.writeln('') | ||||
| 				} | ||||
| 				f.indent-- | ||||
|  |  | |||
|  | @ -1918,22 +1918,22 @@ fn (var g Gen) struct_init(struct_init ast.StructInit) { | |||
| 	} else { | ||||
| 		g.writeln('($styp){') | ||||
| 	} | ||||
| 	var fields := []string | ||||
| 	// var fields := []string
 | ||||
| 	var inited_fields := []string	// TODO this is done in checker, move to ast node
 | ||||
| 	if struct_init.fields.len == 0 && struct_init.exprs.len > 0 { | ||||
| 	/*if struct_init.fields.len == 0 && struct_init.exprs.len > 0 { | ||||
| 		// Get fields for {a,b} short syntax. Fields array wasn't set in the parser.
 | ||||
| 		for f in info.fields { | ||||
| 			fields << f.name | ||||
| 		} | ||||
| 	} else { | ||||
| 		fields = struct_init.fields | ||||
| 	} | ||||
| 	}*/ | ||||
| 	// User set fields
 | ||||
| 	for i, field in fields { | ||||
| 		field_name := c_name(field) | ||||
| 		inited_fields << field | ||||
| 	for i, field in struct_init.fields { | ||||
| 		field_name := c_name(field.name) | ||||
| 		inited_fields << field.name | ||||
| 		g.write('\t.$field_name = ') | ||||
| 		g.expr_with_cast(struct_init.exprs[i], struct_init.expr_types[i], struct_init.expected_types[i]) | ||||
| 		g.expr_with_cast(field.expr, field.typ, field.expected_type) | ||||
| 		g.writeln(',') | ||||
| 	} | ||||
| 	// The rest of the fields are zeroed.
 | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ struct JsGen { | |||
| 	pref            &pref.Preferences | ||||
| 	doc				&JsDoc | ||||
| 	mut: | ||||
| 	constants		strings.Builder // all global V constants 
 | ||||
| 	constants		strings.Builder // all global V constants
 | ||||
| 	file			ast.File | ||||
| 	tmp_count		int | ||||
| 	inside_ternary  bool | ||||
|  | @ -178,7 +178,7 @@ fn (g mut JsGen) to_js_typ(typ string) string { | |||
| 		} | ||||
| 		'voidptr' { | ||||
| 			styp = 'Object' | ||||
| 		}  | ||||
| 		} | ||||
| 		'byteptr' { | ||||
| 			styp = 'string' | ||||
| 		} | ||||
|  | @ -196,7 +196,7 @@ fn (g mut JsGen) to_js_typ(typ string) string { | |||
| 		} | ||||
| 	} | ||||
| 	return styp | ||||
| }  | ||||
| } | ||||
| 
 | ||||
| pub fn (g &JsGen) save() {} | ||||
| 
 | ||||
|  | @ -385,12 +385,12 @@ fn (g mut JsGen) expr(node ast.Expr) { | |||
| 		} | ||||
| 		ast.InfixExpr { | ||||
| 			g.expr(it.left) | ||||
| 			 | ||||
| 
 | ||||
| 			mut op := it.op.str() | ||||
| 			// in js == is non-strict & === is strict, always do strict
 | ||||
| 			if op == '==' { op = '===' } | ||||
| 			else if op == '!=' { op = '!==' } | ||||
| 			 | ||||
| 
 | ||||
| 			g.write(' $op ') | ||||
| 			g.expr(it.right) | ||||
| 		} | ||||
|  | @ -461,7 +461,7 @@ fn (g mut JsGen) gen_string_inter_literal(it ast.StringInterLiteral) { | |||
| 				.struct_ { | ||||
| 					g.expr(expr) | ||||
| 					if sym.has_method('str') { | ||||
| 						g.write('.str()')					 | ||||
| 						g.write('.str()') | ||||
| 					} | ||||
| 				} | ||||
| 				else { | ||||
|  | @ -543,7 +543,7 @@ fn (g mut JsGen) gen_assign_stmt(it ast.AssignStmt) { | |||
| 			val := it.right[i] | ||||
| 			ident_var_info := ident.var_info() | ||||
| 			mut styp := g.typ(ident_var_info.typ) | ||||
| 		 | ||||
| 
 | ||||
| 			match val { | ||||
| 				ast.EnumVal { | ||||
| 					// we want the type of the enum value not the enum
 | ||||
|  | @ -554,11 +554,11 @@ fn (g mut JsGen) gen_assign_stmt(it ast.AssignStmt) { | |||
| 					styp = '' | ||||
| 				} else {} | ||||
| 			} | ||||
| 			 | ||||
| 
 | ||||
| 			if !g.inside_loop && styp.len > 0 { | ||||
| 				g.writeln(g.doc.gen_typ(styp, ident.name)) | ||||
| 			} | ||||
| 			 | ||||
| 
 | ||||
| 			if g.inside_loop || ident.is_mut { | ||||
| 				g.write('let ') | ||||
| 			} else { | ||||
|  | @ -726,7 +726,7 @@ fn (g mut JsGen) gen_method_decl(it ast.FnDecl) { | |||
| 		g.write(')();') | ||||
| 	} | ||||
| 	g.writeln('') | ||||
| 	 | ||||
| 
 | ||||
| 	g.fn_decl = 0 | ||||
| } | ||||
| 
 | ||||
|  | @ -835,7 +835,7 @@ fn (g mut JsGen) fn_args(args []table.Arg, is_variadic bool) { | |||
| fn (g mut JsGen) gen_go_stmt(node ast.GoStmt) { | ||||
| 	// x := node.call_expr as ast.CallEpxr // TODO
 | ||||
| 	match node.call_expr { | ||||
| 		ast.CallExpr {  | ||||
| 		ast.CallExpr { | ||||
| 			mut name := it.name | ||||
| 			if it.is_method { | ||||
| 				receiver_sym := g.table.get_type_symbol(it.receiver_type) | ||||
|  | @ -964,10 +964,10 @@ fn (g mut JsGen) gen_struct_init(it ast.StructInit) { | |||
| 	g.writeln('new ${type_sym.name}({') | ||||
| 	g.inc_indent() | ||||
| 	for i, field in it.fields { | ||||
| 		g.write('$field: ') | ||||
| 		g.expr(it.exprs[i]) | ||||
| 		g.write('$field.name: ') | ||||
| 		g.expr(field.expr) | ||||
| 		if i < it.fields.len - 1 { | ||||
| 			g.write(', ')				 | ||||
| 			g.write(', ') | ||||
| 		} | ||||
| 		g.writeln('') | ||||
| 	} | ||||
|  | @ -975,7 +975,7 @@ fn (g mut JsGen) gen_struct_init(it ast.StructInit) { | |||
| 	g.write('})') | ||||
| } | ||||
| 
 | ||||
| fn (g mut JsGen) gen_ident(node ast.Ident) {	 | ||||
| fn (g mut JsGen) gen_ident(node ast.Ident) { | ||||
| 	if node.kind == .constant { | ||||
| 		g.write('CONSTANTS.') | ||||
| 	} | ||||
|  | @ -1061,4 +1061,4 @@ fn fn_has_go(it ast.FnDecl) bool { | |||
| 		} | ||||
| 	} | ||||
| 	return has_go | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -570,6 +570,7 @@ pub fn (var p Parser) parse_ident(is_c, is_js bool) ast.Ident { | |||
| } | ||||
| 
 | ||||
| fn (var p Parser) struct_init(short_syntax bool) ast.StructInit { | ||||
| 	first_pos := p.tok.position() | ||||
| 	typ := if short_syntax { table.void_type } else { p.parse_type() } | ||||
| 	p.expr_mod = '' | ||||
| 	// sym := p.table.get_type_symbol(typ)
 | ||||
|  | @ -577,8 +578,7 @@ fn (var p Parser) struct_init(short_syntax bool) ast.StructInit { | |||
| 	if !short_syntax { | ||||
| 		p.check(.lcbr) | ||||
| 	} | ||||
| 	var field_names := []string | ||||
| 	var exprs := []ast.Expr | ||||
| 	var fields := []ast.StructInitField | ||||
| 	var i := 0 | ||||
| 	is_short_syntax := p.peek_tok.kind != .colon && p.tok.kind != .rcbr	// `Vec{a,b,c}
 | ||||
| 	// p.warn(is_short_syntax.str())
 | ||||
|  | @ -587,15 +587,27 @@ fn (var p Parser) struct_init(short_syntax bool) ast.StructInit { | |||
| 		var field_name := '' | ||||
| 		if is_short_syntax { | ||||
| 			expr := p.expr(0) | ||||
| 			exprs << expr | ||||
| 			fields << ast.StructInitField{ | ||||
| 				// name will be set later in checker
 | ||||
| 				expr: expr | ||||
| 				pos: expr.position() | ||||
| 			} | ||||
| 		} else { | ||||
| 			first_field_pos := p.tok.position() | ||||
| 			field_name = p.check_name() | ||||
| 			field_names << field_name | ||||
| 		} | ||||
| 		if !is_short_syntax { | ||||
| 			p.check(.colon) | ||||
| 			expr := p.expr(0) | ||||
| 			exprs << expr | ||||
| 			last_field_pos := expr.position() | ||||
| 			field_pos := token.Position{ | ||||
| 				line_nr: first_field_pos.line_nr | ||||
| 				pos: first_field_pos.pos | ||||
| 				len: last_field_pos.pos - first_field_pos.pos + last_field_pos.len | ||||
| 			} | ||||
| 			fields << ast.StructInitField{ | ||||
| 				name: field_name | ||||
| 				expr: expr | ||||
| 				pos: field_pos | ||||
| 			} | ||||
| 		} | ||||
| 		i++ | ||||
| 		if p.tok.kind == .comma { | ||||
|  | @ -603,15 +615,20 @@ fn (var p Parser) struct_init(short_syntax bool) ast.StructInit { | |||
| 		} | ||||
| 		p.check_comment() | ||||
| 	} | ||||
| 	node := ast.StructInit{ | ||||
| 		typ: typ | ||||
| 		exprs: exprs | ||||
| 		fields: field_names | ||||
| 		pos: p.tok.position() | ||||
| 	} | ||||
| 	last_pos := p.tok.position() | ||||
| 	if !short_syntax { | ||||
| 		p.check(.rcbr) | ||||
| 	} | ||||
| 	node := ast.StructInit{ | ||||
| 		typ: typ | ||||
| 		fields: fields | ||||
| 		pos: token.Position{ | ||||
| 			line_nr: first_pos.line_nr | ||||
| 			pos: first_pos.pos | ||||
| 			len: last_pos.pos - first_pos.pos + last_pos.len | ||||
| 		} | ||||
| 		is_short: is_short_syntax | ||||
| 	} | ||||
| 	return node | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue