all: vls mode fixes and improvements; v -json-errors flag

This commit is contained in:
Alexander Medvednikov 2025-08-10 06:45:59 +03:00
parent a11de7263f
commit 652881c73b
7 changed files with 104 additions and 22 deletions

View file

@ -29,35 +29,20 @@ const stderr_value = 2
// (Must be realized in Syscall) (Must be specified)
// ref: http://www.ccfit.nsu.ru/~deviv/courses/unix/unix/ng7c229.html
pub const s_ifmt = 0xF000 // type of file
pub const s_ifdir = 0x4000 // directory
pub const s_ifreg = 0x8000 // regular file
pub const s_iflnk = 0xa000 // link
pub const s_isuid = 0o4000 // SUID
pub const s_isgid = 0o2000 // SGID
pub const s_isvtx = 0o1000 // Sticky
pub const s_irusr = 0o0400 // Read by owner
pub const s_iwusr = 0o0200 // Write by owner
pub const s_ixusr = 0o0100 // Execute by owner
pub const s_irgrp = 0o0040 // Read by group
pub const s_iwgrp = 0o0020 // Write by group
pub const s_ixgrp = 0o0010 // Execute by group
pub const s_iroth = 0o0004 // Read by others
pub const s_iwoth = 0o0002 // Write by others
pub const s_ixoth = 0o0001
fn C.utime(&char, &C.utimbuf) int

24
vlib/os/util/util.v Normal file
View file

@ -0,0 +1,24 @@
module util
import os
// TODO `select` doesn't work with time.Duration for some reason
pub fn execute_with_timeout(cmd string, timeout i64) ?os.Result {
ch := chan os.Result{cap: 1}
spawn fn [cmd] (c chan os.Result) {
res := os.execute(cmd)
c <- res
}(ch)
select {
a := <-ch {
return a
}
// timeout {
// 1000 * time.millisecond {
// timeout * time.millisecond {
timeout * 1_000_000 {
return none
}
}
return os.Result{}
}

View file

@ -14,6 +14,7 @@ import v.markused
import v.depgraph
import v.callgraph
import v.dotgraph
// import x.json2
pub struct Builder {
pub:
@ -475,7 +476,8 @@ pub fn (b &Builder) show_total_warns_and_errors_stats() {
println('checker summary: ${estring} V errors, ${wstring} V warnings, ${nstring} V notices')
}
}
if b.checker.nr_errors > 0 && b.pref.path.ends_with('.v') && os.is_file(b.pref.path) {
if !b.pref.is_vls && b.checker.nr_errors > 0 && b.pref.path.ends_with('.v')
&& os.is_file(b.pref.path) {
if b.checker.errors.any(it.message.starts_with('unknown ')) {
// Sometimes users try to `v main.v`, when they have several .v files in their project.
// Then, they encounter puzzling errors about missing or unknown types. In this case,
@ -519,6 +521,7 @@ pub fn (mut b Builder) print_warnings_and_errors() {
}
}
mut json_errors := []util.JsonError{}
for file in b.parsed_files {
for err in file.errors {
kind := if b.pref.is_verbose {
@ -526,9 +529,24 @@ pub fn (mut b Builder) print_warnings_and_errors() {
} else {
'error:'
}
if b.pref.json_errors {
json_errors << util.JsonError{
message: err.message
path: err.file_path
line_nr: err.pos.line_nr + 1
col: err.pos.col + 1
}
// util.print_json_error(kind, err.CompilerMessage)
} else {
util.show_compiler_message(kind, err.CompilerMessage)
}
}
}
if b.pref.json_errors {
util.print_json_errors(json_errors)
// eprintln(json2.encode_pretty(json_errors))
}
if !b.pref.skip_warnings {
for file in b.parsed_files {

View file

@ -1881,6 +1881,10 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
}
} else {
if unknown_field_msg == '' {
if field_name == '' && c.pref.is_vls {
// VLS will often have `foo.`, skip the no field error
return ast.void_type
}
unknown_field_msg = 'type `${sym.name}` has no field named `${field_name}`'
}
if sym.info is ast.Struct {

View file

@ -252,6 +252,9 @@ pub fn parse_file(path string, mut table ast.Table, comments_mode scanner.Commen
scanner: scanner.new_scanner_file(path, comments_mode, pref_) or { panic(err) }
table: table
pref: pref_
// Only set vls mode if it's the file the user requested via `v -vls-mode file.v`
// Otherwise we'd be parsing entire stdlib in vls mode
is_vls: pref_.is_vls && path == pref_.path
scope: &ast.Scope{
start_pos: 0
parent: table.global_scope

View file

@ -259,6 +259,7 @@ pub mut:
//
subsystem Subsystem // the type of the window app, that is going to be generated; has no effect on !windows
is_vls bool
json_errors bool // -json-errors, for VLS and other tools
}
pub struct LineInfo {
@ -406,6 +407,9 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
'-check' {
res.check_only = true
}
'-vls-mode' {
res.is_vls = true
}
'-?', '-h', '-help', '--help' {
// Note: help is *very important*, just respond to all variations:
res.is_help = true
@ -561,6 +565,9 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
'-repl' {
res.is_repl = true
}
'-json-errors' {
res.json_errors = true
}
'-live' {
res.is_livemain = true
}

View file

@ -210,3 +210,44 @@ pub fn show_compiler_message(kind string, err errors.CompilerMessage) {
eprintln(bold('Details: ') + color('details', err.details))
}
}
pub struct JsonError {
pub:
path string
message string
line_nr int
col int
len int
}
pub fn print_json_errors(errs []JsonError) {
// Can't import x.json2 or json, so have to manually generate json
eprintln('[')
for i, e in errs {
msg := e.message.replace('"', '\\"').replace('\n', '\\n')
eprintln('{
"path":"${e.path}",
"message":"${msg}",
"line_nr":${e.line_nr},
"col":${e.col},
"len":${e.len}
}')
if i < errs.len - 1 {
eprintln(',')
}
}
eprintln(']')
}
/*
pub fn print_json_error(kind string, err errors.CompilerMessage) {
e := JsonError{
message: err.message
path: err.file_path
line_nr: err.pos.line_nr + 1
col: err.pos.col + 1
len: err.pos.len
}
eprintln(json2.encode_pretty(e))
}
*/