compiler: multiple return - allow mut decl & disallow assignment with deceleration (#2251)

pull/2254/head
joe-conigliaro 2019-10-07 21:19:44 +11:00 committed by GitHub
parent ac5241b5bd
commit 8fea5170be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 66 additions and 56 deletions

View File

@ -1426,27 +1426,31 @@ fn (p mut Parser) var_decl() {
p.fspace() p.fspace()
} }
mut names := []string mut var_token_idxs := [p.cur_tok_index()]
mut vtoken_idxs := []int mut var_mut := [is_mut] // add first var mut
mut var_names := [p.check_name()] // add first variable
vtoken_idxs << p.cur_tok_index() p.scanner.validate_var_name(var_names[0])
// first variable // mut new_vars := 0
names << p.check_name() // if var_names[0] != '_' && !p.known_var(var_names[0]) {
p.scanner.validate_var_name(names[0]) // new_vars++
mut new_vars := 0 // }
if names[0] != '_' && !p.known_var(names[0]) {
new_vars++
}
// more than 1 vars (multiple returns) // more than 1 vars (multiple returns)
for p.tok == .comma { for p.tok == .comma {
p.check(.comma) p.check(.comma)
vtoken_idxs << p.cur_tok_index() if p.tok == .key_mut {
name := p.check_name() p.check(.key_mut)
names << name var_mut << true
p.scanner.validate_var_name(name) } else {
if name != '_' && !p.known_var(name) { var_mut << false
new_vars++
} }
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_assign := p.tok == .assign
is_decl_assign := p.tok == .decl_assign is_decl_assign := p.tok == .decl_assign
@ -1458,72 +1462,78 @@ fn (p mut Parser) var_decl() {
p.error('expected `=` or `:=`') p.error('expected `=` or `:=`')
} }
// all vars on left of `:=` already defined // all vars on left of `:=` already defined
if is_decl_assign && names.len > 1 && new_vars == 0 { // if is_decl_assign && var_names.len > 1 && new_vars == 0 {
p.error('no new variables on left side of `:=`') // p.error_with_token_index('no new variables on left side of `:=`', var_token_idxs.last())
} // }
p.var_decl_name = if names.len > 1 { '__ret_'+names.join('_') } else { names[0] } 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) t := p.gen_var_decl(p.var_decl_name, is_static)
mut types := [t] mut var_types := [t]
// multiple returns types // multiple returns types
if names.len > 1 { if var_names.len > 1 {
// should we register __ret var? var_types = t.replace('_V_MulRet_', '').replace('_PTR_', '*').split('_V_')
types = t.replace('_V_MulRet_', '').replace('_PTR_', '*').split('_V_')
} }
for i, name in names { // mismatched number of return & assignment vars
var_token_idx := vtoken_idxs[i] if var_names.len != var_types.len {
if name == '_' { 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 continue
} }
typ := types[i] var_is_mut := var_mut[i]
// println('var decl tok=${p.strtok()} ismut=$is_mut') 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 // Don't allow declaring a variable with the same name. Even in a child scope
// (shadowing is not allowed) // if var_names.len == 1 && !p.builtin_mod && known_var {
known_var := p.known_var(name) if is_decl_assign && known_var {
// single var decl, already exists p.error_with_token_index('redefinition of `$var_name`', var_token_idx)
if names.len == 1 && !p.builtin_mod && known_var { }
p.error_with_token_index('redefinition of `$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 // assignment, but var does not exist
if names.len > 1 && is_assign && !known_var { if is_assign && !known_var {
suggested := p.find_misspelled_local_var(name, 50) suggested := p.find_misspelled_local_var(var_name, 50)
if suggested != '' { 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) 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 // multiple return
if names.len > 1 { if var_names.len > 1 {
p.gen(';\n') p.gen(';\n')
// assigment // assigment
if !p.builtin_mod && known_var { // if !p.builtin_mod && known_var {
v := p.find_var(name) or { if known_var {
p.error_with_token_index('cannot find `$name`', var_token_idx) v := p.find_var(var_name) or {
p.error_with_token_index('cannot find `$var_name`', var_token_idx)
break 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 { if !v.is_mut {
p.error_with_token_index('`$v.name` is immutable', var_token_idx) p.error_with_token_index('`$v.name` is immutable', var_token_idx)
} }
p.mark_var_used(v)
p.mark_var_changed(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 continue
} }
// decleration // 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 { p.register_var(Var {
name: name name: var_name
typ: typ typ: var_type
is_mut: is_mut is_mut: var_is_mut
is_alloc: p.is_alloc || typ.starts_with('array_') is_alloc: p.is_alloc || var_type.starts_with('array_')
line_nr: p.tokens[ var_token_idx ].line_nr line_nr: p.tokens[ var_token_idx ].line_nr
token_idx: var_token_idx token_idx: var_token_idx
}) })