parser: simplify unused vars & add loop/if vars etc

pull/4624/head
joe-conigliaro 2020-04-27 23:16:31 +10:00
parent e67bf674e3
commit 9f76a7b250
No known key found for this signature in database
GPG Key ID: C12F7136C08206F1
15 changed files with 79 additions and 82 deletions

View File

@ -832,7 +832,7 @@ fn (ar []string) contains(val string) bool {
// TODO generic
fn (ar []int) contains(val int) bool {
for i, s in ar {
for s in ar {
if s == val {
return true
}
@ -1206,7 +1206,7 @@ pub fn (a []string) join(del string) string {
return ''
}
mut len := 0
for i, val in a {
for val in a {
len += val.len + del.len
}
len -= del.len

View File

@ -1061,7 +1061,7 @@ pub fn walk_ext(path, ext string) []string {
}
mut res := []string{}
separator := if path.ends_with(os.path_separator) { '' } else { os.path_separator }
for i, file in files {
for file in files {
if file.starts_with('.') {
continue
}

View File

@ -270,12 +270,13 @@ pub struct Stmt {
*/
pub struct Var {
pub:
name string
expr Expr
is_mut bool
name string
expr Expr
is_mut bool
mut:
typ table.Type
pos token.Position
typ table.Type
pos token.Position
is_used bool
}
pub struct GlobalDecl {

View File

@ -12,15 +12,9 @@ mut:
children []&Scope
start_pos int
end_pos int
unused_vars map[string]UnusedVar
objects map[string]ScopeObject
}
pub struct UnusedVar {
name string
pos token.Position
}
pub fn new_scope(parent &Scope, start_pos int) &Scope {
return &ast.Scope{
parent: parent
@ -63,12 +57,12 @@ pub fn (s &Scope) is_known(name string) bool {
return false
}
pub fn (s &Scope) find_var(name string) ?Var {
pub fn (s &Scope) find_var(name string) ?&Var {
if obj := s.find(name) {
v := ScopeObject(obj)
match v {
Var {
return *it
return it
}
else {}
}
@ -76,12 +70,12 @@ pub fn (s &Scope) find_var(name string) ?Var {
return none
}
pub fn (s &Scope) find_const(name string) ?ConstField {
pub fn (s &Scope) find_const(name string) ?&ConstField {
if obj := s.find(name) {
cf := ScopeObject(obj)
match cf {
ConstField {
return *it
return it
}
else {}
}
@ -112,37 +106,13 @@ pub fn (s mut Scope) register(name string, obj ScopeObject) {
if name == '_' {
return
}
if x := s.find(name) {
if _ := s.find(name) {
// println('existing obect: $name')
return
}
s.objects[name] = obj
}
pub fn (s mut Scope) register_unused_var(name string, pos token.Position) {
s.unused_vars[name] = UnusedVar{name, pos}
}
pub fn (s mut Scope) remove_unused_var(name string) {
mut sc := s
for !isnil(sc) {
sc.unused_vars.delete(name)
sc = sc.parent
}
}
pub fn (s mut Scope) unused_vars() []UnusedVar {
ret := []UnusedVar{}
for _, v in s.unused_vars {
ret << v
}
return ret
}
pub fn (s mut Scope) clear_unused_vars() {
s.unused_vars = map[string]UnusedVar
}
pub fn (s &Scope) outermost() &Scope {
mut sc := s
for !isnil(sc.parent) {

View File

@ -203,7 +203,7 @@ pub fn (mut c Checker) struct_decl(decl ast.StructDecl) {
}
c.error('struct name must begin with capital letter', pos)
}
for fi, field in decl.fields {
for field in decl.fields {
sym := c.table.get_type_symbol(field.typ)
if sym.kind == .placeholder && !decl.is_c && !sym.name.starts_with('C.') {
c.error('unknown type `$sym.name`', field.pos)
@ -554,7 +554,7 @@ pub fn (mut c Checker) call_method(call_expr mut ast.CallExpr) table.Type {
mut scope := c.file.scope.innermost(call_expr.pos.pos)
scope.update_var_type('it', array_info.elem_type)
}
for i, arg in call_expr.args {
for arg in call_expr.args {
c.expr(arg.expr)
}
// need to return `array_xxx` instead of `array`

View File

@ -480,7 +480,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
g.typedefs.writeln('typedef enum {')
mut cur_enum_expr := ''
mut cur_enum_offset := 0
for j, field in it.fields {
for field in it.fields {
g.typedefs.write('\t${enum_name}_${field.name}')
if field.has_expr {
g.typedefs.write(' = ')
@ -1918,7 +1918,7 @@ fn (mut g Gen) return_statement(node ast.Return) {
}
fn (mut g Gen) const_decl(node ast.ConstDecl) {
for i, field in node.fields {
for field in node.fields {
name := c_name(field.name)
// TODO hack. Cut the generated value and paste it into definitions.
pos := g.out.len
@ -3061,7 +3061,7 @@ fn (mut g Gen) gen_str_for_enum(info table.Enum, styp, str_fn_name string) {
g.definitions.writeln('string ${str_fn_name}($styp it); // auto')
g.auto_str_funcs.writeln('string ${str_fn_name}($styp it) { /* gen_str_for_enum */')
g.auto_str_funcs.writeln('\tswitch(it) {')
for i, val in info.vals {
for val in info.vals {
g.auto_str_funcs.writeln('\t\tcase ${s}_$val: return tos3("$val");')
}
g.auto_str_funcs.writeln('\t\tdefault: return tos3("unknown enum value");')
@ -3075,7 +3075,7 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp, str_fn_name string) {
mut fnames2strfunc := {
'': ''
} // map[string]string // TODO vfmt bug
for i, field in info.fields {
for field in info.fields {
sym := g.table.get_type_symbol(field.typ)
if sym.kind in [.struct_, .array, .array_fixed, .map, .enum_] {
field_styp := g.typ(field.typ)

View File

@ -426,7 +426,7 @@ fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
is_forwarding_varg := args.len > 0 && args[args.len - 1].typ.flag_is(.variadic)
gen_vargs := is_variadic && !is_forwarding_varg
mut arg_no := 0
for i, arg in args {
for arg in args {
if gen_vargs && arg_no == expected_types.len - 1 {
break
}

View File

@ -600,7 +600,7 @@ fn (mut g Gen) allocate_var(name string, size, initial_val int) {
fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
// `a := 1` | `a,b := 1,2`
for i, ident in node.left {
for ident in node.left {
match node.right[0] {
ast.IntegerLiteral {
g.allocate_var(ident.name, 4, it.val.int())

View File

@ -32,11 +32,13 @@ fn (mut p Parser) assign_stmt() ast.Stmt {
name: ident.name
expr: exprs[i]
is_mut: ident.is_mut || p.inside_for
pos: ident.pos
})
} else {
p.scope.register(ident.name, ast.Var{
name: ident.name
is_mut: ident.is_mut || p.inside_for
pos: ident.pos
})
}
}

View File

@ -37,10 +37,14 @@ pub fn (mut p Parser) call_expr(is_c, is_js bool, mod string) ast.CallExpr {
p.scope.register('err', ast.Var{
name: 'err'
typ: table.string_type
pos: p.tok.position()
is_used: true
})
p.scope.register('errcode', ast.Var{
name: 'errcode'
typ: table.int_type
pos: p.tok.position()
is_used: true
})
is_or_block_used = true
or_stmts = p.parse_block_no_scope()
@ -164,6 +168,8 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
name: arg.name
typ: arg.typ
is_mut: arg.is_mut
pos: p.tok.position()
is_used: true
})
// Do not allow `mut` with simple types
// TODO move to checker?
@ -264,6 +270,8 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
p.scope.register(arg.name, ast.Var{
name: arg.name
typ: arg.typ
pos: p.tok.position()
is_used: true
})
}
mut return_type := table.void_type

View File

@ -67,12 +67,16 @@ fn (mut p Parser) for_stmt() ast.Stmt {
}
} else if p.peek_tok.kind in [.key_in, .comma] {
// `for i in vals`, `for i in start .. end`
mut val_var_pos := p.tok.position()
mut key_var_name := ''
mut val_var_name := p.check_name()
if p.tok.kind == .comma {
p.check(.comma)
key_var_pos := val_var_pos
val_var_pos = p.tok.position()
key_var_name = val_var_name
val_var_name = p.check_name()
if p.scope.known_var(key_var_name) {
p.error('redefinition of key iteration variable `$key_var_name`')
}
@ -82,6 +86,7 @@ fn (mut p Parser) for_stmt() ast.Stmt {
p.scope.register(key_var_name, ast.Var{
name: key_var_name
typ: table.int_type
pos: key_var_pos
})
} else if p.scope.known_var(val_var_name) {
p.error('redefinition of value iteration variable `$val_var_name`')
@ -104,11 +109,13 @@ fn (mut p Parser) for_stmt() ast.Stmt {
p.scope.register(val_var_name, ast.Var{
name: val_var_name
typ: table.int_type
pos: val_var_pos
})
} else {
// this type will be set in checker
p.scope.register(val_var_name, ast.Var{
name: val_var_name
pos: val_var_pos
})
}
p.inside_for = false

View File

@ -43,12 +43,14 @@ fn (mut p Parser) if_expr() ast.IfExpr {
if p.peek_tok.kind == .decl_assign {
is_or = true
p.open_scope()
var_pos := p.tok.position()
var_name := p.check_name()
p.check(.decl_assign)
expr := p.expr(0)
p.scope.register(var_name, ast.Var{
name: var_name
expr: expr
pos: var_pos
})
cond = ast.IfGuardExpr{
var_name: var_name
@ -89,6 +91,7 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
if is_mut {
p.next()
}
cond_pos := p.tok.position()
cond := p.expr(0)
p.inside_match = false
p.check(.lcbr)
@ -119,6 +122,8 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
p.scope.register('it', ast.Var{
name: 'it'
typ: typ.to_ptr()
pos: cond_pos
is_used: true
})
// TODO
if p.tok.kind == .comma {

View File

@ -195,16 +195,22 @@ pub fn (mut p Parser) open_scope() {
}
pub fn (mut p Parser) close_scope() {
if !p.pref.is_repl && !p.pref.is_fmt {
for v in p.scope.unused_vars() {
if p.pref.is_prod {
p.error_with_pos('Unused variable: $v.name', v.pos)
} else {
p.warn_with_pos('Unused variable: $v.name', v.pos)
if !p.pref.is_repl && !p.scanner.is_fmt {
for _, obj in p.scope.objects {
match obj {
ast.Var {
if !it.is_used && !it.name.starts_with('__') {
if p.pref.is_prod {
p.error_with_pos('Unused variable: $it.name', it.pos)
} else {
p.warn_with_pos('Unused variable: $it.name', it.pos)
}
}
}
else {}
}
}
}
p.scope.clear_unused_vars()
p.scope.end_pos = p.tok.pos
p.scope.parent.children << p.scope
p.scope = p.scope.parent
@ -393,9 +399,6 @@ pub fn (mut p Parser) stmt() ast.Stmt {
}
}
.key_mut, .key_static, .key_var {
if p.peek_tok.kind == .name && p.peek_tok.lit != '_' && !p.peek_tok.lit.starts_with('__') {
p.scope.register_unused_var(p.peek_tok.lit, p.peek_tok.position())
}
return p.assign_stmt()
}
.key_for {
@ -457,14 +460,7 @@ pub fn (mut p Parser) stmt() ast.Stmt {
else {
// `x := ...`
if p.tok.kind == .name && p.peek_tok.kind in [.decl_assign, .comma] {
register_unused := p.peek_tok.kind == .decl_assign
lit := p.tok.lit
pos := p.tok.position()
ret := p.assign_stmt()
if register_unused && lit != '_' && !lit.starts_with('__') {
p.scope.register_unused_var(lit, pos)
}
return ret
return p.assign_stmt()
} else if p.tok.kind == .name && p.peek_tok.kind == .colon {
// `label:`
name := p.check_name()
@ -472,8 +468,6 @@ pub fn (mut p Parser) stmt() ast.Stmt {
return ast.GotoLabel{
name: name
}
} else if p.tok.kind == .name {
p.scope.remove_unused_var(p.tok.lit)
}
epos := p.tok.position()
expr := p.expr(0)
@ -609,7 +603,16 @@ pub fn (mut p Parser) name_expr() ast.Expr {
if p.tok.lit in ['r', 'c', 'js'] && p.peek_tok.kind == .string && p.prev_tok.kind != .str_dollar {
return p.string_expr()
}
known_var := p.scope.known_var(p.tok.lit)
mut known_var := false
if obj := p.scope.find(p.tok.lit) {
match mut obj {
ast.Var {
known_var = true
it.is_used = true
}
else {}
}
}
if p.peek_tok.kind == .dot && !known_var && (is_c || is_js || p.known_import(p.tok.lit) ||
p.mod.all_after('.') == p.tok.lit) {
if is_c {
@ -753,6 +756,8 @@ fn (mut p Parser) index_expr(left ast.Expr) ast.IndexExpr {
fn (mut p Parser) filter() {
p.scope.register('it', ast.Var{
name: 'it'
pos: p.tok.position()
is_used: true
})
}
@ -783,10 +788,14 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
p.scope.register('errcode', ast.Var{
name: 'errcode'
typ: table.int_type
pos: p.tok.position()
is_used: true
})
p.scope.register('err', ast.Var{
name: 'err'
typ: table.string_type
pos: p.tok.position()
is_used: true
})
is_or_block_used = true
or_stmts = p.parse_block_no_scope()
@ -1028,9 +1037,6 @@ fn (mut p Parser) return_stmt() ast.Return {
}
}
for {
if p.tok.kind == .name {
p.scope.remove_unused_var(p.tok.lit)
}
expr := p.expr(0)
exprs << expr
if p.tok.kind == .comma {
@ -1220,10 +1226,11 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
fn (mut p Parser) assoc() ast.Assoc {
var_name := p.check_name()
pos := p.tok.position()
v := p.scope.find_var(var_name) or {
mut v := p.scope.find_var(var_name) or {
p.error('unknown variable `$var_name`')
return ast.Assoc{}
}
v.is_used = true
// println('assoc var $name typ=$var.typ')
mut fields := []string{}
mut vals := []ast.Expr{}
@ -1245,7 +1252,7 @@ fn (mut p Parser) assoc() ast.Assoc {
fields: fields
exprs: vals
pos: pos
typ: v.typ
// typ: v.typ
}
}

View File

@ -16,7 +16,6 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
// Prefix
match p.tok.kind {
.name {
p.scope.remove_unused_var(p.tok.lit)
node = p.name_expr()
p.is_stmt_ident = is_stmt_ident
}
@ -79,7 +78,6 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
type_name: p.check_name()
}
} else {
p.scope.remove_unused_var(p.tok.lit)
sizeof_type := p.parse_type()
node = ast.SizeOf{
typ: sizeof_type
@ -104,7 +102,6 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
} else {
// it should be a struct
if p.peek_tok.kind == .pipe {
p.scope.remove_unused_var(p.tok.lit)
node = p.assoc()
} else if p.peek_tok.kind == .colon || p.tok.kind == .rcbr {
node = p.struct_init(true) // short_syntax: true

View File

@ -66,7 +66,7 @@ pub fn (t Type) is_ptr() bool {
[inline]
pub fn (t Type) set_nr_muls(nr_muls int) Type {
if nr_muls < 0 || nr_muls > 255 {
panic('typ_set_nr_muls: nr_muls must be between 0 & 255')
panic('set_nr_muls: nr_muls must be between 0 & 255')
}
return (((int(t) >> 24) & 0xff) << 24) | (nr_muls << 16) | (u16(t) & 0xffff)
}
@ -76,7 +76,7 @@ pub fn (t Type) set_nr_muls(nr_muls int) Type {
pub fn (t Type) to_ptr() Type {
nr_muls := (int(t) >> 16) & 0xff
if nr_muls == 255 {
panic('type_to_pre: nr_muls is already at max of 255')
panic('to_ptr: nr_muls is already at max of 255')
}
return (((int(t) >> 24) & 0xff) << 24) | ((nr_muls + 1) << 16) | (u16(t) & 0xffff)
}