From 8fea5170bedb538fba45386262c785055f64b425 Mon Sep 17 00:00:00 2001 From: joe-conigliaro Date: Mon, 7 Oct 2019 21:19:44 +1100 Subject: [PATCH] compiler: multiple return - allow mut decl & disallow assignment with deceleration (#2251) --- compiler/parser.v | 122 +++++++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 56 deletions(-) diff --git a/compiler/parser.v b/compiler/parser.v index e2c1268dbf..e8460b037e 100644 --- a/compiler/parser.v +++ b/compiler/parser.v @@ -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 })