diff --git a/compiler/fn.v b/compiler/fn.v index 197ca6ccc0..1143d79173 100644 --- a/compiler/fn.v +++ b/compiler/fn.v @@ -195,6 +195,7 @@ fn (p mut Parser) fn_decl() { ref: is_amp ptr: is_mut line_nr: p.scanner.line_nr + scanner_pos: p.scanner.get_scanner_pos() } f.args << receiver f.register_var(receiver) @@ -539,17 +540,11 @@ fn (p mut Parser) check_unused_variables() { break } if !var.is_used && !p.pref.is_repl && !var.is_arg && !p.pref.translated && var.name != '_' { - p.scanner.line_nr = var.line_nr - 1 - if p.pref.is_prod { - p.error('`$var.name` declared and not used') - } else { - p.warn('`$var.name` declared and not used') - } + p.production_error('`$var.name` declared and not used', var.scanner_pos ) } - if !var.is_changed && var.is_mut && !p.pref.is_repl && - !p.pref.translated && var.name != '_' { - p.scanner.line_nr = var.line_nr - 1 - p.error('`$var.name` is declared as mutable, but it was never changed') + if !var.is_changed && var.is_mut && !p.pref.is_repl && + !p.pref.translated && var.name != '_' { + p.error_with_position( '`$var.name` is declared as mutable, but it was never changed', var.scanner_pos ) } } } @@ -723,6 +718,7 @@ fn (p mut Parser) fn_args(f mut Fn) { is_arg: true // is_mut: is_mut line_nr: p.scanner.line_nr + scanner_pos: p.scanner.get_scanner_pos() } // f.register_var(v) f.args << v @@ -766,6 +762,7 @@ fn (p mut Parser) fn_args(f mut Fn) { is_mut: is_mut ptr: is_mut line_nr: p.scanner.line_nr + scanner_pos: p.scanner.get_scanner_pos() } f.register_var(v) f.args << v diff --git a/compiler/parser.v b/compiler/parser.v index 9a2e7531bc..043d525ac0 100644 --- a/compiler/parser.v +++ b/compiler/parser.v @@ -774,6 +774,25 @@ fn (p &Parser) warn(s string) { println('warning: $p.scanner.file_path:${p.scanner.line_nr+1}: $s') } + +fn (p mut Parser) error_with_position(e string, sp ScannerPos) { + p.scanner.goto_scanner_position( sp ) + p.error( e ) +} + +fn (p mut Parser) production_error(e string, sp ScannerPos) { + if p.pref.is_prod { + p.scanner.goto_scanner_position( sp ) + p.error( e ) + }else { + // on a warning, restore the scanner state after printing the warning: + cpos := p.scanner.get_scanner_pos() + p.scanner.goto_scanner_position( sp ) + p.warn(e) + p.scanner.goto_scanner_position( cpos ) + } +} + fn (p mut Parser) error(s string) { // Dump all vars and types for debugging if p.pref.is_debug { @@ -1301,6 +1320,7 @@ fn (p mut Parser) var_decl() { p.fspace() } // println('var decl tok=${p.strtok()} ismut=$is_mut') + var_scanner_pos := p.scanner.get_scanner_pos() name := p.check_name() p.var_decl_name = name // Don't allow declaring a variable with the same name. Even in a child scope @@ -1319,6 +1339,8 @@ fn (p mut Parser) var_decl() { typ: typ is_mut: is_mut is_alloc: p.is_alloc || typ.starts_with('array_') + scanner_pos: var_scanner_pos + line_nr: var_scanner_pos.line_nr }) //if p.is_alloc { println('REG VAR IS ALLOC $name') } p.var_decl_name = '' @@ -3571,8 +3593,8 @@ fn (p mut Parser) go_statement() { fn (p mut Parser) register_var(v Var) { if v.line_nr == 0 { - //v.line_nr = p.scanner.line_nr - p.cur_fn.register_var({ v | line_nr: p.scanner.line_nr }) + spos := p.scanner.get_scanner_pos() + p.cur_fn.register_var({ v | scanner_pos: spos, line_nr: spos.line_nr }) } else { p.cur_fn.register_var(v) } diff --git a/compiler/scanner.v b/compiler/scanner.v index f8decb967d..98ac6d70bf 100644 --- a/compiler/scanner.v +++ b/compiler/scanner.v @@ -61,6 +61,24 @@ fn new_scanner(file_path string) &Scanner { return scanner } + +struct ScannerPos { +mut: + pos int + line_nr int +} +fn (s ScannerPos) str() string { + return 'ScannerPos{ ${s.pos:5d} , ${s.line_nr:5d} }' +} +fn (s &Scanner) get_scanner_pos() ScannerPos { + return ScannerPos{ pos: s.pos line_nr: s.line_nr } +} +fn (s mut Scanner) goto_scanner_position(scp ScannerPos) { + s.pos = scp.pos + s.line_nr = scp.line_nr +} + + // TODO remove once multiple return values are implemented struct ScanRes { tok Token diff --git a/compiler/table.v b/compiler/table.v index b09524a6c1..fcaa65da00 100644 --- a/compiler/table.v +++ b/compiler/table.v @@ -71,7 +71,6 @@ mut: ref bool parent_fn string // Variables can only be defined in functions mod string // module where this var is stored - line_nr int access_mod AccessMod is_global bool // __global (translated from C only) is_used bool @@ -79,6 +78,8 @@ mut: scope_level int is_c bool // todo remove once `typ` is `Type`, not string moved bool + scanner_pos ScannerPos // TODO: use only scanner_pos, remove line_nr + line_nr int } struct Type {