mirror of
https://github.com/vlang/v.git
synced 2025-09-13 22:42:26 +03:00
checker: more line-info logic
This commit is contained in:
parent
12dd6e8b39
commit
b9a233b1a0
10 changed files with 227 additions and 94 deletions
|
@ -42,6 +42,7 @@
|
||||||
- [ ] 64/32 bit int depending on arch (will remove array.len limitation on 64 bit systems)
|
- [ ] 64/32 bit int depending on arch (will remove array.len limitation on 64 bit systems)
|
||||||
- [ ] `copy()` builtin function (e.g. for easier conversion from `[]Foo` to `[4]Foo`)
|
- [ ] `copy()` builtin function (e.g. for easier conversion from `[]Foo` to `[4]Foo`)
|
||||||
- [ ] Lambdas: `a.sort(|a, b| a > b)`
|
- [ ] Lambdas: `a.sort(|a, b| a > b)`
|
||||||
|
- [ ] Custom attributes.
|
||||||
|
|
||||||
## [Version 1.0]
|
## [Version 1.0]
|
||||||
|
|
||||||
|
|
|
@ -880,3 +880,4 @@ pub fn (f &File) tell() !i64 {
|
||||||
}
|
}
|
||||||
return pos
|
return pos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -552,7 +552,12 @@ pub fn join_path(base string, dirs ...string) string {
|
||||||
sb.write_string(path_separator)
|
sb.write_string(path_separator)
|
||||||
sb.write_string(d)
|
sb.write_string(d)
|
||||||
}
|
}
|
||||||
return sb.str()
|
mut res := sb.str()
|
||||||
|
if res.contains('/./') {
|
||||||
|
// Fix `join_path("/foo/bar", "./file.txt")` => `/foo/bar/./file.txt`
|
||||||
|
res = res.replace('/./', '/')
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// join_path_single appends the `elem` after `base`, using a platform specific
|
// join_path_single appends the `elem` after `base`, using a platform specific
|
||||||
|
|
|
@ -613,6 +613,7 @@ fn test_join() {
|
||||||
assert os.join_path('v', 'vlib', 'os') == 'v\\vlib\\os'
|
assert os.join_path('v', 'vlib', 'os') == 'v\\vlib\\os'
|
||||||
} $else {
|
} $else {
|
||||||
assert os.join_path('v', 'vlib', 'os') == 'v/vlib/os'
|
assert os.join_path('v', 'vlib', 'os') == 'v/vlib/os'
|
||||||
|
assert os.join_path('/foo/bar', './file.txt') == '/foo/bar/file.txt'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
93
vlib/v/checker/autocomplete.v
Normal file
93
vlib/v/checker/autocomplete.v
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
// Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved.
|
||||||
|
// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
|
||||||
|
module checker
|
||||||
|
|
||||||
|
import strings
|
||||||
|
import v.ast
|
||||||
|
import os
|
||||||
|
|
||||||
|
fn (mut c Checker) ident_autocomplete(node ast.Ident) {
|
||||||
|
// Mini LS hack (v -line-info "a.v:16")
|
||||||
|
println(
|
||||||
|
'checker.ident() info.line_nr=${c.pref.linfo.line_nr} node.line_nr=${node.pos.line_nr} ' +
|
||||||
|
' pwd="${os.getwd()}" file="${c.file.path}", ' +
|
||||||
|
' pref.linfo.path="${c.pref.linfo.path}" node.name="${node.name}" expr="${c.pref.linfo.expr}"')
|
||||||
|
// Make sure this ident is on the same line as requeste, in the same file, and has the same name
|
||||||
|
same_line := node.pos.line_nr in [c.pref.linfo.line_nr - 1, c.pref.linfo.line_nr + 1, c.pref.linfo.line_nr]
|
||||||
|
if !same_line {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
same_name := c.pref.linfo.expr == node.name
|
||||||
|
if !same_name {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
abs_path := os.join_path(os.getwd(), c.file.path)
|
||||||
|
if c.pref.linfo.path !in [c.file.path, abs_path] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mut sb := strings.new_builder(10)
|
||||||
|
if node.kind == .unresolved {
|
||||||
|
// println(node)
|
||||||
|
eprintln('unresolved type, maybe "${node.name}" was not defined. otherwise this is a bug, should never happen; please report')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
sym := c.table.sym(c.unwrap_generic(node.obj.typ))
|
||||||
|
// sb.writeln('VAR ${node.name}:${sym.name} ${node.pos.line_nr}')
|
||||||
|
nt := '${node.name}:${sym.name}'
|
||||||
|
if !c.pref.linfo.vars_printed[nt] { // avoid dups
|
||||||
|
sb.writeln('===')
|
||||||
|
sb.writeln('VAR ${nt}') //${node.name}:${sym.name}')
|
||||||
|
/// print_backtrace()
|
||||||
|
/*
|
||||||
|
if sym.kind == .alias {
|
||||||
|
parent_sym := c.table.sym(sym.parent_type)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
mut fields := []ACFieldMethod{cap: 10}
|
||||||
|
if sym.kind == .struct_ {
|
||||||
|
// Add fields, but only if it's a struct.
|
||||||
|
struct_info := sym.info as ast.Struct
|
||||||
|
// match struct_info {
|
||||||
|
// ast.Struct
|
||||||
|
//}
|
||||||
|
for field in struct_info.fields {
|
||||||
|
field_sym := c.table.sym(field.typ)
|
||||||
|
fields << ACFieldMethod{field.name, field_sym.name}
|
||||||
|
}
|
||||||
|
} else if sym.kind == .array {
|
||||||
|
// t := typeof(sym.info).name
|
||||||
|
if sym.info is ast.Aggregate {
|
||||||
|
} else if sym.info is ast.Array {
|
||||||
|
fields << ACFieldMethod{'len', 'int'}
|
||||||
|
fields << ACFieldMethod{'cap', 'int'}
|
||||||
|
}
|
||||||
|
// array_info := sym.info as ast.Array
|
||||||
|
}
|
||||||
|
// Aliases and other types can have methods, add them
|
||||||
|
for method in sym.methods {
|
||||||
|
method_ret_type := c.table.sym(method.return_type)
|
||||||
|
fields << ACFieldMethod{build_method_summary(method), method_ret_type.name}
|
||||||
|
}
|
||||||
|
fields.sort(a.name < b.name)
|
||||||
|
for field in fields {
|
||||||
|
sb.writeln('${field.name}:${field.typ}')
|
||||||
|
}
|
||||||
|
res := sb.str().trim_space()
|
||||||
|
if res != '' {
|
||||||
|
println(res)
|
||||||
|
c.pref.linfo.vars_printed[nt] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_method_summary(method ast.Fn) string {
|
||||||
|
mut s := method.name + '('
|
||||||
|
for i, param in method.params {
|
||||||
|
s += param.name
|
||||||
|
if i < method.params.len - 1 {
|
||||||
|
s += ','
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s + ')'
|
||||||
|
}
|
|
@ -13,7 +13,6 @@ import v.util.version
|
||||||
import v.errors
|
import v.errors
|
||||||
import v.pkgconfig
|
import v.pkgconfig
|
||||||
import v.transformer
|
import v.transformer
|
||||||
import strings
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
int_min = int(0x80000000)
|
int_min = int(0x80000000)
|
||||||
|
@ -44,8 +43,9 @@ pub const (
|
||||||
|
|
||||||
[heap; minify]
|
[heap; minify]
|
||||||
pub struct Checker {
|
pub struct Checker {
|
||||||
pref &pref.Preferences = unsafe { nil } // Preferences shared from V struct
|
|
||||||
pub mut:
|
pub mut:
|
||||||
|
pref &pref.Preferences = unsafe { nil } // Preferences shared from V struct
|
||||||
|
//
|
||||||
table &ast.Table = unsafe { nil }
|
table &ast.Table = unsafe { nil }
|
||||||
file &ast.File = unsafe { nil }
|
file &ast.File = unsafe { nil }
|
||||||
nr_errors int
|
nr_errors int
|
||||||
|
@ -123,13 +123,13 @@ mut:
|
||||||
inside_decl_rhs bool
|
inside_decl_rhs bool
|
||||||
inside_if_guard bool // true inside the guard condition of `if x := opt() {}`
|
inside_if_guard bool // true inside the guard condition of `if x := opt() {}`
|
||||||
inside_assign bool
|
inside_assign bool
|
||||||
doing_line_info int // a quick single file run when called with v -line-info (contains line nr to inspect)
|
// doing_line_info int // a quick single file run when called with v -line-info (contains line nr to inspect)
|
||||||
doing_line_path string // same, but stores the path being parsed
|
// doing_line_path string // same, but stores the path being parsed
|
||||||
is_index_assign bool
|
is_index_assign bool
|
||||||
comptime_call_pos int // needed for correctly checking use before decl for templates
|
comptime_call_pos int // needed for correctly checking use before decl for templates
|
||||||
goto_labels map[string]ast.GotoLabel // to check for unused goto labels
|
goto_labels map[string]ast.GotoLabel // to check for unused goto labels
|
||||||
enum_data_type ast.Type
|
enum_data_type ast.Type
|
||||||
fn_return_type ast.Type
|
fn_return_type ast.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_checker(table &ast.Table, pref_ &pref.Preferences) &Checker {
|
pub fn new_checker(table &ast.Table, pref_ &pref.Preferences) &Checker {
|
||||||
|
@ -293,6 +293,7 @@ pub fn (mut c Checker) change_current_file(file &ast.File) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) check_files(ast_files []&ast.File) {
|
pub fn (mut c Checker) check_files(ast_files []&ast.File) {
|
||||||
|
// println('check_files')
|
||||||
// c.files = ast_files
|
// c.files = ast_files
|
||||||
mut has_main_mod_file := false
|
mut has_main_mod_file := false
|
||||||
mut has_main_fn := false
|
mut has_main_fn := false
|
||||||
|
@ -381,9 +382,27 @@ pub fn (mut c Checker) check_files(ast_files []&ast.File) {
|
||||||
c.error('a _test.v file should have *at least* one `test_` function', token.Pos{})
|
c.error('a _test.v file should have *at least* one `test_` function', token.Pos{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Print line info and exit
|
// After the main checker run, run the line info check, print line info, and exit (if it's present)
|
||||||
if c.pref.line_info != '' && c.doing_line_info == 0 {
|
if c.pref.line_info != '' && !c.pref.linfo.is_running { //'' && c.pref.linfo.line_nr == 0 {
|
||||||
c.do_line_info(c.pref.line_info, ast_files)
|
// c.do_line_info(c.pref.line_info, ast_files)
|
||||||
|
println('setting is_running=true, pref.path=${c.pref.linfo.path} curdir' + os.getwd())
|
||||||
|
c.pref.linfo.is_running = true
|
||||||
|
for i, file in ast_files {
|
||||||
|
// println(file.path)
|
||||||
|
if file.path == c.pref.linfo.path {
|
||||||
|
println('running c.check_files')
|
||||||
|
c.check_files([ast_files[i]])
|
||||||
|
exit(0)
|
||||||
|
} else if file.path.starts_with('./') {
|
||||||
|
// Maybe it's a "./foo.v", linfo.path has an absolute path
|
||||||
|
abs_path := os.join_path(os.getwd(), file.path).replace('/./', '/') // TODO join_path shouldn't have /./
|
||||||
|
if abs_path == c.pref.linfo.path {
|
||||||
|
c.check_files([ast_files[i]])
|
||||||
|
exit(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println('failed to find file "${c.pref.linfo.path}"')
|
||||||
exit(0)
|
exit(0)
|
||||||
}
|
}
|
||||||
// Make sure fn main is defined in non lib builds
|
// Make sure fn main is defined in non lib builds
|
||||||
|
@ -1605,7 +1624,7 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
|
||||||
return ast.int_type
|
return ast.int_type
|
||||||
}
|
}
|
||||||
|
|
||||||
c.error('`${unwrapped_sym.name}` has no property `${node.field_name}`', node.pos)
|
c.error('`${unwrapped_sym.name}` 1has no property `${node.field_name}`', node.pos)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if sym.info is ast.Struct {
|
if sym.info is ast.Struct {
|
||||||
|
@ -3362,34 +3381,9 @@ struct ACFieldMethod {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
|
fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
|
||||||
if c.doing_line_info > 0 {
|
if c.pref.linfo.is_running {
|
||||||
mut sb := strings.new_builder(10)
|
|
||||||
// Mini LS hack (v -line-info "a.v:16")
|
// Mini LS hack (v -line-info "a.v:16")
|
||||||
// println('line_nr=${node.pos.line_nr} doing line nr=${c.doing_line_info}')
|
c.ident_autocomplete(node)
|
||||||
// println('Start line_nr=${node.pos.line_nr} line2=${c.doing_line_info} file="${c.file.path}", pppp="${c.doing_line_path}"')
|
|
||||||
if node.pos.line_nr == c.doing_line_info && c.file.path == c.doing_line_path {
|
|
||||||
sb.writeln('===')
|
|
||||||
sym := c.table.sym(node.obj.typ)
|
|
||||||
sb.writeln('VAR ${node.name}:${sym.name}')
|
|
||||||
mut struct_info := sym.info as ast.Struct
|
|
||||||
mut fields := []ACFieldMethod{cap: struct_info.fields.len}
|
|
||||||
for field in struct_info.fields {
|
|
||||||
field_sym := c.table.sym(field.typ)
|
|
||||||
fields << ACFieldMethod{field.name, field_sym.name}
|
|
||||||
}
|
|
||||||
for method in sym.methods {
|
|
||||||
method_ret_type := c.table.sym(method.return_type)
|
|
||||||
fields << ACFieldMethod{method.name + '()', method_ret_type.name}
|
|
||||||
}
|
|
||||||
fields.sort(a.name < b.name)
|
|
||||||
for field in fields {
|
|
||||||
sb.writeln('${field.name}:${field.typ}')
|
|
||||||
}
|
|
||||||
res := sb.str().trim_space()
|
|
||||||
if res != '' {
|
|
||||||
println(res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// TODO: move this
|
// TODO: move this
|
||||||
if c.const_deps.len > 0 {
|
if c.const_deps.len > 0 {
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
// Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved.
|
|
||||||
// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
|
|
||||||
module checker
|
|
||||||
|
|
||||||
import v.ast
|
|
||||||
// import os
|
|
||||||
|
|
||||||
fn (mut c Checker) do_line_info(line string, all_ast_files []&ast.File) {
|
|
||||||
// println("do_line_info '${line}'")
|
|
||||||
format_err := 'wrong format, use `-line-info "file.v:24"'
|
|
||||||
vals := line.split(':')
|
|
||||||
if vals.len != 2 {
|
|
||||||
eprintln(format_err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
file_name := vals[0]
|
|
||||||
line_nr := vals[1].int() - 1
|
|
||||||
if !file_name.ends_with('.v') || line_nr == -1 {
|
|
||||||
eprintln(format_err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// println('ok ${c.files.len}')
|
|
||||||
// Find which file contains the line
|
|
||||||
mut found := false
|
|
||||||
mut found_path := ''
|
|
||||||
mut found_file_idx := -1
|
|
||||||
for i, file in all_ast_files {
|
|
||||||
// base := os.base(file.path)
|
|
||||||
base := file.path // os.base(file.path)
|
|
||||||
// println(base)
|
|
||||||
if base == file_name {
|
|
||||||
if found {
|
|
||||||
eprintln('more than one "${file_name}" found: "${file.path}" and "${found_path}"')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
found = true
|
|
||||||
found_path = file.path
|
|
||||||
found_file_idx = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
eprintln('file "${file_name}" not found among those parsed')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// println('found ${found_path}')
|
|
||||||
c.doing_line_info = line_nr
|
|
||||||
c.doing_line_path = file_name
|
|
||||||
c.check_files([all_ast_files[found_file_idx]])
|
|
||||||
}
|
|
72
vlib/v/pref/line_info.v
Normal file
72
vlib/v/pref/line_info.v
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
// Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved.
|
||||||
|
// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
|
||||||
|
module pref
|
||||||
|
|
||||||
|
// import v.ast
|
||||||
|
// import v.pref
|
||||||
|
// import os
|
||||||
|
|
||||||
|
// fn (mut p Pref) parse_line_info(line string, all_ast_files []&ast.File) {
|
||||||
|
fn (mut p Preferences) parse_line_info(line string) {
|
||||||
|
// println("parse_line_info '${line}'")
|
||||||
|
format_err := 'wrong format, use `-line-info "file.v:24:expr_to_look_up"'
|
||||||
|
vals := line.split(':')
|
||||||
|
if vals.len != 3 {
|
||||||
|
eprintln(format_err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file_name := vals[0]
|
||||||
|
line_nr := vals[1].int() - 1
|
||||||
|
expr := vals[2]
|
||||||
|
if !file_name.ends_with('.v') || line_nr == -1 {
|
||||||
|
eprintln(format_err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// println('files.len=${c.files.len}')
|
||||||
|
// Find which file contains the line
|
||||||
|
mut found := true // false
|
||||||
|
//// mut found_path := ''
|
||||||
|
// mut found_file_idx := -1
|
||||||
|
/*
|
||||||
|
for i, file in all_ast_files {
|
||||||
|
// base := os.base(file.path)
|
||||||
|
base := file.path // os.base(file.path)
|
||||||
|
// println(base)
|
||||||
|
if base == file_name {
|
||||||
|
if found {
|
||||||
|
eprintln('more than one "${file_name}" found: "${file.path}" and "${found_path}"')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
found = true
|
||||||
|
found_path = file.path
|
||||||
|
found_file_idx = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
eprintln('file "${file_name}" not found among those parsed')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.linfo = LineInfo{
|
||||||
|
line_nr: line_nr
|
||||||
|
path: file_name
|
||||||
|
expr: expr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_line_info_expr_to_program_text(raw_text string, linfo LineInfo) string {
|
||||||
|
lines := raw_text.split('\n')
|
||||||
|
lines_before := lines[..linfo.line_nr].join('\n')
|
||||||
|
mut expr := linfo.expr
|
||||||
|
if !expr.contains('.') {
|
||||||
|
// Single variable, `foo` => `foo.xx`
|
||||||
|
// expr += '.xxx'
|
||||||
|
// expr = '_ = ' + expr
|
||||||
|
expr = 'println(' + expr + ')'
|
||||||
|
}
|
||||||
|
lines_after := lines[linfo.line_nr..].join('\n')
|
||||||
|
return lines_before + '\n' + expr + '\n' + lines_after
|
||||||
|
}
|
|
@ -190,6 +190,7 @@ pub mut:
|
||||||
out_name string
|
out_name string
|
||||||
path string // Path to file/folder to compile
|
path string // Path to file/folder to compile
|
||||||
line_info string // `-line-info="file.v:28"`: for "mini VLS" (shows information about objects on provided line)
|
line_info string // `-line-info="file.v:28"`: for "mini VLS" (shows information about objects on provided line)
|
||||||
|
linfo LineInfo
|
||||||
//
|
//
|
||||||
run_only []string // VTEST_ONLY_FN and -run-only accept comma separated glob patterns.
|
run_only []string // VTEST_ONLY_FN and -run-only accept comma separated glob patterns.
|
||||||
exclude []string // glob patterns for excluding .v files from the list of .v files that otherwise would have been used for a compilation, example: `-exclude @vlib/math/*.c.v`
|
exclude []string // glob patterns for excluding .v files from the list of .v files that otherwise would have been used for a compilation, example: `-exclude @vlib/math/*.c.v`
|
||||||
|
@ -240,6 +241,15 @@ pub mut:
|
||||||
wasm_validate bool // validate webassembly code, by calling `wasm-validate`
|
wasm_validate bool // validate webassembly code, by calling `wasm-validate`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct LineInfo {
|
||||||
|
pub mut:
|
||||||
|
line_nr int // a quick single file run when called with v -line-info (contains line nr to inspect)
|
||||||
|
path string // same, but stores the path being parsed
|
||||||
|
expr string // "foo" or "foo.bar" V code (expression) which needs autocomplete
|
||||||
|
is_running bool // so that line info is fetched only on the second checker run
|
||||||
|
vars_printed map[string]bool // to avoid dups
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_args(known_external_commands []string, args []string) (&Preferences, string) {
|
pub fn parse_args(known_external_commands []string, args []string) (&Preferences, string) {
|
||||||
return parse_args_and_show_errors(known_external_commands, args, false)
|
return parse_args_and_show_errors(known_external_commands, args, false)
|
||||||
}
|
}
|
||||||
|
@ -835,6 +845,7 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
|
||||||
}
|
}
|
||||||
'-line-info' {
|
'-line-info' {
|
||||||
res.line_info = cmdline.option(current_args, arg, '')
|
res.line_info = cmdline.option(current_args, arg, '')
|
||||||
|
res.parse_line_info(res.line_info)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
'-use-coroutines' {
|
'-use-coroutines' {
|
||||||
|
|
|
@ -113,7 +113,14 @@ pub fn new_scanner_file(file_path string, comments_mode CommentsMode, pref_ &pre
|
||||||
if !os.is_file(file_path) {
|
if !os.is_file(file_path) {
|
||||||
return error('${file_path} is not a .v file')
|
return error('${file_path} is not a .v file')
|
||||||
}
|
}
|
||||||
raw_text := util.read_file(file_path) or { return err }
|
mut raw_text := util.read_file(file_path) or { return err }
|
||||||
|
if pref_.line_info != '' {
|
||||||
|
// Add line info expr to the scanner text
|
||||||
|
abs_path := os.join_path(os.getwd(), file_path)
|
||||||
|
if pref_.linfo.path in [file_path, abs_path] {
|
||||||
|
raw_text = pref.add_line_info_expr_to_program_text(raw_text, pref_.linfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
mut s := &Scanner{
|
mut s := &Scanner{
|
||||||
pref: pref_
|
pref: pref_
|
||||||
text: raw_text
|
text: raw_text
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue