scanner, token: add column information to tokens (#9407)
							parent
							
								
									3753a58ce0
								
							
						
					
					
						commit
						aa4e22c287
					
				|  | @ -1440,6 +1440,7 @@ pub fn (expr Expr) position() token.Position { | ||||||
| 				line_nr: expr.pos.line_nr | 				line_nr: expr.pos.line_nr | ||||||
| 				pos: left_pos.pos | 				pos: left_pos.pos | ||||||
| 				len: right_pos.pos - left_pos.pos + right_pos.len | 				len: right_pos.pos - left_pos.pos + right_pos.len | ||||||
|  | 				col: left_pos.col | ||||||
| 				last_line: right_pos.last_line | 				last_line: right_pos.last_line | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | @ -1563,6 +1564,7 @@ pub fn (node Node) position() token.Position { | ||||||
| 						line_nr: -1 | 						line_nr: -1 | ||||||
| 						pos: -1 | 						pos: -1 | ||||||
| 						last_line: -1 | 						last_line: -1 | ||||||
|  | 						col: -1 | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | @ -4402,8 +4402,7 @@ fn (mut c Checker) at_expr(mut node ast.AtExpr) table.Type { | ||||||
| 			node.val = (node.pos.line_nr + 1).str() | 			node.val = (node.pos.line_nr + 1).str() | ||||||
| 		} | 		} | ||||||
| 		.column_nr { | 		.column_nr { | ||||||
| 			_, column := util.filepath_pos_to_source_and_column(c.file.path, node.pos) | 			node.val = (node.pos.col + 1).str() | ||||||
| 			node.val = (column + 1).str() |  | ||||||
| 		} | 		} | ||||||
| 		.vhash { | 		.vhash { | ||||||
| 			node.val = util.vhash() | 			node.val = util.vhash() | ||||||
|  |  | ||||||
|  | @ -257,6 +257,7 @@ fn (mut p Parser) match_expr() ast.MatchExpr { | ||||||
| 		line_nr: match_first_pos.line_nr | 		line_nr: match_first_pos.line_nr | ||||||
| 		pos: match_first_pos.pos | 		pos: match_first_pos.pos | ||||||
| 		len: match_last_pos.pos - match_first_pos.pos + match_last_pos.len | 		len: match_last_pos.pos - match_first_pos.pos + match_last_pos.len | ||||||
|  | 		col: match_first_pos.col | ||||||
| 	} | 	} | ||||||
| 	if p.tok.kind == .rcbr { | 	if p.tok.kind == .rcbr { | ||||||
| 		p.check(.rcbr) | 		p.check(.rcbr) | ||||||
|  | @ -401,6 +402,7 @@ fn (mut p Parser) select_expr() ast.SelectExpr { | ||||||
| 			line_nr: branch_first_pos.line_nr | 			line_nr: branch_first_pos.line_nr | ||||||
| 			pos: branch_first_pos.pos | 			pos: branch_first_pos.pos | ||||||
| 			len: branch_last_pos.pos - branch_first_pos.pos + branch_last_pos.len | 			len: branch_last_pos.pos - branch_first_pos.pos + branch_last_pos.len | ||||||
|  | 			col: branch_first_pos.col | ||||||
| 		} | 		} | ||||||
| 		post_comments := p.eat_comments({}) | 		post_comments := p.eat_comments({}) | ||||||
| 		pos.update_last_line(p.prev_tok.line_nr) | 		pos.update_last_line(p.prev_tok.line_nr) | ||||||
|  | @ -425,6 +427,7 @@ fn (mut p Parser) select_expr() ast.SelectExpr { | ||||||
| 		line_nr: match_first_pos.line_nr | 		line_nr: match_first_pos.line_nr | ||||||
| 		pos: match_first_pos.pos | 		pos: match_first_pos.pos | ||||||
| 		len: match_last_pos.pos - match_first_pos.pos + match_last_pos.len | 		len: match_last_pos.pos - match_first_pos.pos + match_last_pos.len | ||||||
|  | 		col: match_first_pos.col | ||||||
| 	} | 	} | ||||||
| 	if p.tok.kind == .rcbr { | 	if p.tok.kind == .rcbr { | ||||||
| 		p.check(.rcbr) | 		p.check(.rcbr) | ||||||
|  |  | ||||||
|  | @ -389,6 +389,7 @@ fn (mut p Parser) struct_init(short_syntax bool) ast.StructInit { | ||||||
| 				line_nr: first_field_pos.line_nr | 				line_nr: first_field_pos.line_nr | ||||||
| 				pos: first_field_pos.pos | 				pos: first_field_pos.pos | ||||||
| 				len: field_len | 				len: field_len | ||||||
|  | 				col: first_field_pos.col | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		i++ | 		i++ | ||||||
|  |  | ||||||
|  | @ -26,7 +26,8 @@ pub mut: | ||||||
| 	text              string // the whole text of the file
 | 	text              string // the whole text of the file
 | ||||||
| 	pos               int    // current position in the file, first character is s.text[0]
 | 	pos               int    // current position in the file, first character is s.text[0]
 | ||||||
| 	line_nr           int    // current line number
 | 	line_nr           int    // current line number
 | ||||||
| 	last_nl_pos       int    // for calculating column
 | 	last_nl_pos       int = -1 // for calculating column
 | ||||||
|  | 	is_crlf           bool   // special check when computing columns
 | ||||||
| 	is_inside_string  bool   // set to true in a string, *at the start* of an $var or ${expr}
 | 	is_inside_string  bool   // set to true in a string, *at the start* of an $var or ${expr}
 | ||||||
| 	is_inter_start    bool   // for hacky string interpolation TODO simplify
 | 	is_inter_start    bool   // for hacky string interpolation TODO simplify
 | ||||||
| 	is_inter_end      bool | 	is_inter_end      bool | ||||||
|  | @ -177,6 +178,7 @@ fn (mut s Scanner) new_token(tok_kind token.Kind, lit string, len int) token.Tok | ||||||
| 		kind: tok_kind | 		kind: tok_kind | ||||||
| 		lit: lit | 		lit: lit | ||||||
| 		line_nr: s.line_nr + line_offset | 		line_nr: s.line_nr + line_offset | ||||||
|  | 		col: mu.max(1, s.current_column() - len + 1) | ||||||
| 		pos: s.pos - len + 1 | 		pos: s.pos - len + 1 | ||||||
| 		len: len | 		len: len | ||||||
| 		tidx: cidx | 		tidx: cidx | ||||||
|  | @ -189,6 +191,7 @@ fn (s &Scanner) new_eof_token() token.Token { | ||||||
| 		kind: .eof | 		kind: .eof | ||||||
| 		lit: '' | 		lit: '' | ||||||
| 		line_nr: s.line_nr + 1 | 		line_nr: s.line_nr + 1 | ||||||
|  | 		col: 1 | ||||||
| 		pos: s.pos | 		pos: s.pos | ||||||
| 		len: 1 | 		len: 1 | ||||||
| 		tidx: s.tidx | 		tidx: s.tidx | ||||||
|  | @ -203,6 +206,7 @@ fn (mut s Scanner) new_multiline_token(tok_kind token.Kind, lit string, len int, | ||||||
| 		kind: tok_kind | 		kind: tok_kind | ||||||
| 		lit: lit | 		lit: lit | ||||||
| 		line_nr: start_line + 1 | 		line_nr: start_line + 1 | ||||||
|  | 		col: mu.max(1, s.current_column() - len + 1) | ||||||
| 		pos: s.pos - len + 1 | 		pos: s.pos - len + 1 | ||||||
| 		len: len | 		len: len | ||||||
| 		tidx: cidx | 		tidx: cidx | ||||||
|  | @ -495,6 +499,9 @@ fn (mut s Scanner) skip_whitespace() { | ||||||
| 		if util.is_nl(s.text[s.pos]) && s.is_vh { | 		if util.is_nl(s.text[s.pos]) && s.is_vh { | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  | 		if s.pos + 1 < s.text.len && s.text[s.pos] == `\r` && s.text[s.pos + 1] == `\n` { | ||||||
|  | 			s.is_crlf = true | ||||||
|  | 		} | ||||||
| 		// Count \r\n as one line
 | 		// Count \r\n as one line
 | ||||||
| 		if util.is_nl(s.text[s.pos]) && !s.expect('\r\n', s.pos - 1) { | 		if util.is_nl(s.text[s.pos]) && !s.expect('\r\n', s.pos - 1) { | ||||||
| 			s.inc_line_number() | 			s.inc_line_number() | ||||||
|  | @ -863,19 +870,6 @@ fn (mut s Scanner) text_scan() token.Token { | ||||||
| 				} | 				} | ||||||
| 				return s.new_token(.name, name, name.len) | 				return s.new_token(.name, name, name.len) | ||||||
| 			} | 			} | ||||||
| 			/* |  | ||||||
| 			case `\r`: |  | ||||||
| 		if nextc == `\n` { |  | ||||||
| 			s.pos++ |  | ||||||
| 			s.last_nl_pos = s.pos |  | ||||||
| 			return s.new_token(.nl, '') |  | ||||||
| 		} |  | ||||||
| 	 } |  | ||||||
| 	case `\n`: |  | ||||||
| 		s.last_nl_pos = s.pos |  | ||||||
| 		return s.new_token(.nl, '') |  | ||||||
| 	 } |  | ||||||
| 			*/ |  | ||||||
| 			`.` { | 			`.` { | ||||||
| 				if nextc == `.` { | 				if nextc == `.` { | ||||||
| 					s.pos++ | 					s.pos++ | ||||||
|  | @ -1298,7 +1292,10 @@ fn (mut s Scanner) eat_to_end_of_line() { | ||||||
| 
 | 
 | ||||||
| [inline] | [inline] | ||||||
| fn (mut s Scanner) inc_line_number() { | fn (mut s Scanner) inc_line_number() { | ||||||
| 	s.last_nl_pos = s.pos | 	s.last_nl_pos = mu.min(s.text.len - 1, s.pos) | ||||||
|  | 	if s.is_crlf { | ||||||
|  | 		s.last_nl_pos++ | ||||||
|  | 	} | ||||||
| 	s.line_nr++ | 	s.line_nr++ | ||||||
| 	s.line_ends << s.pos | 	s.line_ends << s.pos | ||||||
| 	if s.line_nr > s.nr_lines { | 	if s.line_nr > s.nr_lines { | ||||||
|  | @ -1331,6 +1328,7 @@ pub fn (mut s Scanner) warn(msg string) { | ||||||
| 	pos := token.Position{ | 	pos := token.Position{ | ||||||
| 		line_nr: s.line_nr | 		line_nr: s.line_nr | ||||||
| 		pos: s.pos | 		pos: s.pos | ||||||
|  | 		col: s.current_column() - 1 | ||||||
| 	} | 	} | ||||||
| 	if s.pref.output_mode == .stdout { | 	if s.pref.output_mode == .stdout { | ||||||
| 		eprintln(util.formatted_error('warning:', msg, s.file_path, pos)) | 		eprintln(util.formatted_error('warning:', msg, s.file_path, pos)) | ||||||
|  | @ -1348,6 +1346,7 @@ pub fn (mut s Scanner) error(msg string) { | ||||||
| 	pos := token.Position{ | 	pos := token.Position{ | ||||||
| 		line_nr: s.line_nr | 		line_nr: s.line_nr | ||||||
| 		pos: s.pos | 		pos: s.pos | ||||||
|  | 		col: s.current_column() - 1 | ||||||
| 	} | 	} | ||||||
| 	if s.pref.output_mode == .stdout { | 	if s.pref.output_mode == .stdout { | ||||||
| 		eprintln(util.formatted_error('error:', msg, s.file_path, pos)) | 		eprintln(util.formatted_error('error:', msg, s.file_path, pos)) | ||||||
|  | @ -1371,6 +1370,7 @@ fn (mut s Scanner) vet_error(msg string, fix vet.FixKind) { | ||||||
| 		file_path: s.file_path | 		file_path: s.file_path | ||||||
| 		pos: token.Position{ | 		pos: token.Position{ | ||||||
| 			line_nr: s.line_nr | 			line_nr: s.line_nr | ||||||
|  | 			col: s.current_column() - 1 | ||||||
| 		} | 		} | ||||||
| 		kind: .error | 		kind: .error | ||||||
| 		fix: fix | 		fix: fix | ||||||
|  |  | ||||||
|  | @ -8,12 +8,13 @@ pub: | ||||||
| 	len     int // length of the literal in the source
 | 	len     int // length of the literal in the source
 | ||||||
| 	line_nr int // the line number in the source where the token occured
 | 	line_nr int // the line number in the source where the token occured
 | ||||||
| 	pos     int // the position of the token in scanner text
 | 	pos     int // the position of the token in scanner text
 | ||||||
|  | 	col     int // the column in the source where the token occured
 | ||||||
| pub mut: | pub mut: | ||||||
| 	last_line int // the line number where the ast object ends (used by vfmt)
 | 	last_line int // the line number where the ast object ends (used by vfmt)
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn (pos Position) str() string { | pub fn (pos Position) str() string { | ||||||
| 	return 'Position{ line_nr: $pos.line_nr, last_line: $pos.last_line, pos: $pos.pos, len: $pos.len }' | 	return 'Position{ line_nr: $pos.line_nr, last_line: $pos.last_line, pos: $pos.pos, col: $pos.col, len: $pos.len }' | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn (pos Position) extend(end Position) Position { | pub fn (pos Position) extend(end Position) Position { | ||||||
|  | @ -30,6 +31,7 @@ pub fn (pos Position) extend_with_last_line(end Position, last_line int) Positio | ||||||
| 		line_nr: pos.line_nr | 		line_nr: pos.line_nr | ||||||
| 		last_line: last_line - 1 | 		last_line: last_line - 1 | ||||||
| 		pos: pos.pos | 		pos: pos.pos | ||||||
|  | 		col: pos.col | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -44,5 +46,6 @@ pub fn (tok &Token) position() Position { | ||||||
| 		line_nr: tok.line_nr - 1 | 		line_nr: tok.line_nr - 1 | ||||||
| 		pos: tok.pos | 		pos: tok.pos | ||||||
| 		last_line: tok.line_nr - 1 | 		last_line: tok.line_nr - 1 | ||||||
|  | 		col: tok.col - 1 | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ pub: | ||||||
| 	kind    Kind   // the token number/enum; for quick comparisons
 | 	kind    Kind   // the token number/enum; for quick comparisons
 | ||||||
| 	lit     string // literal representation of the token
 | 	lit     string // literal representation of the token
 | ||||||
| 	line_nr int    // the line number in the source where the token occured
 | 	line_nr int    // the line number in the source where the token occured
 | ||||||
|  | 	col     int    // the column in the source where the token occured
 | ||||||
| 	// name_idx int // name table index for O(1) lookup
 | 	// name_idx int // name table index for O(1) lookup
 | ||||||
| 	pos  int // the position of the token in scanner text
 | 	pos  int // the position of the token in scanner text
 | ||||||
| 	len  int // length of the literal
 | 	len  int // length of the literal
 | ||||||
|  |  | ||||||
|  | @ -83,9 +83,9 @@ pub fn formatted_error(kind string, omsg string, filepath string, pos token.Posi | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	//
 | 	//
 | ||||||
| 	source, column := filepath_pos_to_source_and_column(filepath, pos) | 	source := read_file(filepath) or { '' } | ||||||
| 	position := '$path:${pos.line_nr + 1}:${mu.max(1, column + 1)}:' | 	position := '$path:${pos.line_nr + 1}:${mu.max(1, pos.col + 1)}:' | ||||||
| 	scontext := source_context(kind, source, column, pos).join('\n') | 	scontext := source_context(kind, source, pos).join('\n') | ||||||
| 	final_position := bold(position) | 	final_position := bold(position) | ||||||
| 	final_kind := bold(color(kind, kind)) | 	final_kind := bold(color(kind, kind)) | ||||||
| 	final_msg := emsg | 	final_msg := emsg | ||||||
|  | @ -94,23 +94,7 @@ pub fn formatted_error(kind string, omsg string, filepath string, pos token.Posi | ||||||
| 	return '$final_position $final_kind $final_msg$final_context'.trim_space() | 	return '$final_position $final_kind $final_msg$final_context'.trim_space() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn filepath_pos_to_source_and_column(filepath string, pos token.Position) (string, int) { | pub fn source_context(kind string, source string, pos token.Position) []string { | ||||||
| 	// TODO: optimize this; may be use a cache.
 |  | ||||||
| 	// The column should not be so computationally hard to get.
 |  | ||||||
| 	source := read_file(filepath) or { '' } |  | ||||||
| 	mut p := mu.max(0, mu.min(source.len - 1, pos.pos)) |  | ||||||
| 	if source.len > 0 { |  | ||||||
| 		for ; p >= 0; p-- { |  | ||||||
| 			if source[p] == `\n` || source[p] == `\r` { |  | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	column := mu.max(0, pos.pos - p - 1) |  | ||||||
| 	return source, column |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub fn source_context(kind string, source string, column int, pos token.Position) []string { |  | ||||||
| 	mut clines := []string{} | 	mut clines := []string{} | ||||||
| 	if source.len == 0 { | 	if source.len == 0 { | ||||||
| 		return clines | 		return clines | ||||||
|  | @ -121,8 +105,8 @@ pub fn source_context(kind string, source string, column int, pos token.Position | ||||||
| 	tab_spaces := '    ' | 	tab_spaces := '    ' | ||||||
| 	for iline := bline; iline <= aline; iline++ { | 	for iline := bline; iline <= aline; iline++ { | ||||||
| 		sline := source_lines[iline] | 		sline := source_lines[iline] | ||||||
| 		start_column := mu.max(0, mu.min(column, sline.len)) | 		start_column := mu.max(0, mu.min(pos.col, sline.len)) | ||||||
| 		end_column := mu.max(0, mu.min(column + mu.max(0, pos.len), sline.len)) | 		end_column := mu.max(0, mu.min(pos.col + mu.max(0, pos.len), sline.len)) | ||||||
| 		cline := if iline == pos.line_nr { | 		cline := if iline == pos.line_nr { | ||||||
| 			sline[..start_column] + color(kind, sline[start_column..end_column]) + | 			sline[..start_column] + color(kind, sline[start_column..end_column]) + | ||||||
| 				sline[end_column..] | 				sline[end_column..] | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue