compiler: multiple return - allow mut decl & disallow assignment with deceleration (#2251)
							parent
							
								
									ac5241b5bd
								
							
						
					
					
						commit
						8fea5170be
					
				|  | @ -1425,28 +1425,32 @@ fn (p mut Parser) var_decl() { | |||
| 		p.check(.key_static) | ||||
| 		p.fspace() | ||||
| 	} | ||||
| 
 | ||||
| 	mut var_token_idxs := [p.cur_tok_index()] | ||||
| 	mut var_mut := [is_mut] // add first var mut
 | ||||
| 	mut var_names := [p.check_name()] // add first variable
 | ||||
| 	 | ||||
| 	mut names := []string | ||||
| 	mut vtoken_idxs := []int | ||||
| 	 | ||||
| 	vtoken_idxs << p.cur_tok_index() | ||||
| 	// first variable
 | ||||
| 	names << p.check_name() | ||||
| 	p.scanner.validate_var_name(names[0]) | ||||
| 	mut new_vars := 0 | ||||
| 	if names[0] != '_' && !p.known_var(names[0]) { | ||||
| 		new_vars++ | ||||
| 	} | ||||
| 	p.scanner.validate_var_name(var_names[0]) | ||||
| 	// mut new_vars := 0
 | ||||
| 	// if var_names[0] != '_' && !p.known_var(var_names[0]) {
 | ||||
| 	// 	new_vars++
 | ||||
| 	// }
 | ||||
| 	// more than 1 vars (multiple returns)
 | ||||
| 	for p.tok == .comma { | ||||
| 		p.check(.comma) | ||||
| 		vtoken_idxs << p.cur_tok_index() | ||||
| 		name := p.check_name() | ||||
| 		names << name | ||||
| 		p.scanner.validate_var_name(name) | ||||
| 		if name != '_' && !p.known_var(name) { | ||||
| 			new_vars++ | ||||
| 		if p.tok == .key_mut { | ||||
| 			p.check(.key_mut) | ||||
| 			var_mut << true | ||||
| 		} else { | ||||
| 			var_mut << false | ||||
| 		} | ||||
| 		var_token_idxs << p.cur_tok_index() | ||||
| 		var_name := p.check_name() | ||||
| 		p.scanner.validate_var_name(var_name) | ||||
| 		// if var_name != '_' && !p.known_var(var_name) {
 | ||||
| 		// 	new_vars++
 | ||||
| 		// }
 | ||||
| 		var_names << var_name | ||||
| 	} | ||||
| 	is_assign := p.tok == .assign | ||||
| 	is_decl_assign := p.tok == .decl_assign | ||||
|  | @ -1458,72 +1462,78 @@ fn (p mut Parser) var_decl() { | |||
| 		p.error('expected `=` or `:=`') | ||||
| 	} | ||||
| 	// all vars on left of `:=` already defined
 | ||||
| 	if is_decl_assign && names.len > 1 && new_vars == 0 { | ||||
| 		p.error('no new variables on left side of `:=`') | ||||
| 	} | ||||
| 	p.var_decl_name = if names.len > 1 { '__ret_'+names.join('_') } else { names[0] } | ||||
| 	// if is_decl_assign && var_names.len > 1 && new_vars == 0 {
 | ||||
| 	// 	p.error_with_token_index('no new variables on left side of `:=`', var_token_idxs.last())
 | ||||
| 	// }
 | ||||
| 	p.var_decl_name = if var_names.len > 1 { '_V_mret_'+var_names.join('_') } else { var_names[0] } | ||||
| 	t := p.gen_var_decl(p.var_decl_name, is_static) | ||||
| 	mut types := [t] | ||||
| 	mut var_types := [t] | ||||
| 	// multiple returns types
 | ||||
| 	if names.len > 1 { | ||||
| 		// should we register __ret var?
 | ||||
| 		types = t.replace('_V_MulRet_', '').replace('_PTR_', '*').split('_V_') | ||||
| 	if var_names.len > 1 { | ||||
| 		var_types = t.replace('_V_MulRet_', '').replace('_PTR_', '*').split('_V_') | ||||
| 	} | ||||
| 	for i, name in names { | ||||
| 		var_token_idx := vtoken_idxs[i] | ||||
| 		if name == '_' { | ||||
| 	// mismatched number of return & assignment vars
 | ||||
| 	if var_names.len != var_types.len { | ||||
| 		mr_fn := p.cgen.cur_line.find_between('=', '(').trim_space() | ||||
| 		p.error_with_token_index('assignment mismatch: ${var_names.len} variables but `$mr_fn` returns $var_types.len values', var_token_idxs.last()) | ||||
| 	} | ||||
| 	for i, var_name in var_names { | ||||
| 		var_token_idx := var_token_idxs[i] | ||||
| 		if var_name == '_' { | ||||
| 			continue | ||||
| 		} | ||||
| 		typ := types[i] | ||||
| 		// println('var decl tok=${p.strtok()} ismut=$is_mut')
 | ||||
| 		var_is_mut := var_mut[i] | ||||
| 		var_type := var_types[i] | ||||
| 		known_var := p.known_var(var_name) | ||||
| 		// println('var decl tok=${p.strtok()} name=type=$var_name type=$var_type ismut=$var_is_mut')
 | ||||
| 		// var decl, already exists (shadowing is not allowed)
 | ||||
| 		// Don't allow declaring a variable with the same name. Even in a child scope
 | ||||
| 		// (shadowing is not allowed)
 | ||||
| 		known_var := p.known_var(name) | ||||
| 		// single var decl, already exists
 | ||||
| 		if names.len == 1 && !p.builtin_mod && known_var { | ||||
| 			p.error_with_token_index('redefinition of `$name`', var_token_idx) | ||||
| 		// if var_names.len == 1 && !p.builtin_mod && known_var {
 | ||||
| 		if is_decl_assign && known_var { | ||||
| 			p.error_with_token_index('redefinition of `$var_name`', var_token_idx) | ||||
| 		} | ||||
| 		// mut specified with assignment
 | ||||
| 		if /*is_assign && implicit*/ known_var && var_is_mut { | ||||
| 			p.error_with_token_index('cannot specify mutability for existing var `$var_name`, only for new vars', var_token_idx) | ||||
| 		} | ||||
| 		// assignment, but var does not exist
 | ||||
| 		if names.len > 1 && is_assign && !known_var { | ||||
| 			suggested := p.find_misspelled_local_var(name, 50) | ||||
| 		if is_assign && !known_var { | ||||
| 			suggested := p.find_misspelled_local_var(var_name, 50) | ||||
| 			if suggested != '' { | ||||
| 				p.error_with_token_index('undefined: `$name`. did you mean:$suggested', var_token_idx) | ||||
| 				p.error_with_token_index('undefined: `$var_name`. did you mean:$suggested', var_token_idx) | ||||
| 			} | ||||
| 			p.error_with_token_index('undefined: `$name`.', var_token_idx) | ||||
| 			p.error_with_token_index('undefined: `$var_name`.', var_token_idx) | ||||
| 		} | ||||
| 		if name.len > 1 && contains_capital(name) { | ||||
| 		if var_name.len > 1 && contains_capital(var_name) { | ||||
| 			p.error_with_token_index('variable names cannot contain uppercase letters, use snake_case instead', var_token_idx) | ||||
| 		} | ||||
| 		// mismatched number of return & assignment vars
 | ||||
| 		if names.len != types.len { | ||||
| 			mr_fn := p.cgen.cur_line.find_between('=', '(').trim_space() | ||||
| 			p.error_with_token_index('assignment mismatch: ${names.len} variables but `$mr_fn` returns $types.len values', var_token_idx) | ||||
| 		} | ||||
| 		// multiple return
 | ||||
| 		if names.len > 1 { | ||||
| 		if var_names.len > 1 { | ||||
| 			p.gen(';\n') | ||||
| 			// assigment
 | ||||
| 			if !p.builtin_mod && known_var { | ||||
| 				v := p.find_var(name) or { | ||||
| 					p.error_with_token_index('cannot find `$name`', var_token_idx) | ||||
| 			// if !p.builtin_mod && known_var {
 | ||||
| 			if known_var { | ||||
| 				v := p.find_var(var_name) or { | ||||
| 					p.error_with_token_index('cannot find `$var_name`', var_token_idx) | ||||
| 					break | ||||
| 				} | ||||
| 				p.check_types_with_token_index(typ, v.typ, var_token_idx) | ||||
| 				p.check_types_with_token_index(var_type, v.typ, var_token_idx) | ||||
| 				if !v.is_mut { | ||||
| 					p.error_with_token_index('`$v.name` is immutable', var_token_idx) | ||||
| 				} | ||||
| 				p.mark_var_used(v) | ||||
| 				p.mark_var_changed(v) | ||||
| 				p.gen('$name = ${p.var_decl_name}.var_$i') | ||||
| 				p.gen('$var_name = ${p.var_decl_name}.var_$i') | ||||
| 				continue | ||||
| 			} | ||||
| 			// decleration
 | ||||
| 			p.gen('$typ $name = ${p.var_decl_name}.var_$i') | ||||
| 			p.gen('$var_type $var_name = ${p.var_decl_name}.var_$i') | ||||
| 		} | ||||
| 		p.register_var(Var { | ||||
| 			name: name | ||||
| 			typ: typ | ||||
| 			is_mut: is_mut | ||||
| 			is_alloc: p.is_alloc || typ.starts_with('array_') | ||||
| 			name: var_name | ||||
| 			typ: var_type | ||||
| 			is_mut: var_is_mut | ||||
| 			is_alloc: p.is_alloc || var_type.starts_with('array_') | ||||
| 			line_nr: p.tokens[ var_token_idx ].line_nr | ||||
| 			token_idx: var_token_idx | ||||
| 		}) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue