parser: simplify unused vars & add loop/if vars etc
parent
e67bf674e3
commit
9f76a7b250
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue