aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorDanielGavin <danielgavin5@hotmail.com>2024-04-22 19:43:55 +0200
committerDanielGavin <danielgavin5@hotmail.com>2024-04-22 19:43:55 +0200
commit6ce95de7909837c4e03b0338400f0b38ae8c912a (patch)
tree8cf0ab4dfef1f6804dfa7ac580c7da97a91e7e94 /src/server
parent81c84f9683a40d60c0d1ae347c175d9205d186f8 (diff)
Use json now to parse errors in check
Diffstat (limited to 'src/server')
-rw-r--r--src/server/check.odin186
1 files changed, 54 insertions, 132 deletions
diff --git a/src/server/check.odin b/src/server/check.odin
index a3804df..47f1d9a 100644
--- a/src/server/check.odin
+++ b/src/server/check.odin
@@ -21,6 +21,25 @@ import "src:common"
//Store uris we have reported on since last save. We use this to clear them on next save.
uris_reported := make([dynamic]string)
+Json_Error :: struct {
+ type: string,
+ pos: Json_Type_Error,
+ msgs: []string,
+}
+
+Json_Type_Error :: struct {
+ file: string,
+ offset: int,
+ line: int,
+ column: int,
+ end_column: int,
+}
+
+Json_Errors :: struct {
+ error_count: int,
+ errors: []Json_Error,
+}
+
//If the user does not specify where to call odin check, it'll just find all directory with odin, and call them seperately.
fallback_find_odin_directories :: proc(config: ^common.Config) -> []string {
@@ -101,12 +120,13 @@ check :: proc(paths: []string, writer: ^Writer, config: ^common.Config) {
if code, ok, buffer = common.run_executable(
fmt.tprintf(
- "%v check %s %s %s %s %s",
+ "%v check %s %s %s %s %s %s",
command,
path,
strings.to_string(collection_builder),
entry_point_opt,
config.checker_args,
+ "-json-errors",
ODIN_OS == .Linux || ODIN_OS == .Darwin ? "2>&1" : "",
),
&data,
@@ -119,161 +139,58 @@ check :: proc(paths: []string, writer: ^Writer, config: ^common.Config) {
return
}
- s: scanner.Scanner
-
- scanner.init(&s, string(buffer))
-
- s.whitespace = {'\t', ' '}
-
- current: rune
-
- ErrorSeperator :: struct {
- message: string,
- line: int,
- column: int,
- uri: string,
+ if len(buffer) == 0 {
+ continue
}
- error_seperators := make(
- [dynamic]ErrorSeperator,
- context.temp_allocator,
- )
-
- //find all the signatures string(digit:digit)
- loop: for scanner.peek(&s) != scanner.EOF {
-
- scan_line: {
- error: ErrorSeperator
-
- source_pos := s.src_pos
-
- if source_pos == 1 {
- source_pos = 0
- }
-
- for scanner.peek(&s) != '(' {
- n := scanner.scan(&s)
-
- if n == scanner.EOF {
- break loop
- }
- if n == '\n' {
- source_pos = s.src_pos - 1
- }
- }
-
- error.uri = strings.clone(
- string(buffer[source_pos:s.src_pos - 1]),
- context.temp_allocator,
- )
-
- left_paren := scanner.scan(&s)
-
- if left_paren != '(' {
- break scan_line
- }
-
- lhs_digit := scanner.scan(&s)
-
- if lhs_digit != scanner.Int {
- break scan_line
- }
+ json_errors: Json_Errors
- line, column: int
- ok: bool
-
- line, ok = strconv.parse_int(scanner.token_text(&s))
-
- if !ok {
- break scan_line
- }
-
- seperator := scanner.scan(&s)
-
- if seperator != ':' {
- break scan_line
- }
-
- rhs_digit := scanner.scan(&s)
-
- if rhs_digit != scanner.Int {
- break scan_line
- }
-
- column, ok = strconv.parse_int(scanner.token_text(&s))
-
- if !ok {
- break scan_line
- }
-
- right_paren := scanner.scan(&s)
-
- if right_paren != ')' {
- break scan_line
- }
-
- source_pos = s.src_pos
-
- for scanner.peek(&s) != '\n' {
- n := scanner.scan(&s)
-
- if n == scanner.EOF {
- break
- }
- }
-
- if source_pos == s.src_pos {
- continue
- }
-
- error.message = strings.clone(
- string(buffer[source_pos:s.src_pos - 1]),
- context.temp_allocator,
- )
- error.column = column
- error.line = line
+ if res := json.unmarshal(
+ buffer,
+ &json_errors,
+ json.DEFAULT_SPECIFICATION,
+ context.temp_allocator,
+ ); res != nil {
+ log.errorf("Failed to unmarshal check results: %v", res)
+ }
- append(&error_seperators, error)
- continue loop
+ for error in json_errors.errors {
+ if len(error.msgs) == 0 {
+ break
}
- // line scan failed, skip to the next line
- for scanner.peek(&s) != '\n' {
- n := scanner.scan(&s)
- if n == scanner.EOF {
- break
- }
- }
- }
+ message := strings.join(error.msgs, " ", context.temp_allocator)
- for error in error_seperators {
if strings.contains(
- error.message,
+ message,
"Redeclaration of 'main' in this scope",
) {
continue
}
- if error.uri not_in errors {
- errors[error.uri] = make(
+ if error.pos.file not_in errors {
+ errors[error.pos.file] = make(
[dynamic]Diagnostic,
context.temp_allocator,
)
}
append(
- &errors[error.uri],
+ &errors[error.pos.file],
Diagnostic {
code = "checker",
- severity = .Error,
+ severity = .Error if error.type == "error" else .Warning,
range = {
start = {
- character = error.column,
- line = error.line - 1,
+ character = error.pos.column - 1,
+ line = error.pos.line - 1,
+ },
+ end = {
+ character = error.pos.end_column - 1,
+ line = error.pos.line - 1,
},
- end = {character = 0, line = error.line},
},
- message = error.message,
+ message = message,
},
)
}
@@ -303,9 +220,12 @@ check :: proc(paths: []string, writer: ^Writer, config: ^common.Config) {
for k, v in errors {
uri := common.create_uri(k, context.temp_allocator)
+ //Find the unique diagnostics, since some poor profile settings make the checker check the same file multiple times
+ unique := slice.unique(v[:])
+
params := NotificationPublishDiagnosticsParams {
uri = uri.uri,
- diagnostics = v[:],
+ diagnostics = unique,
}
notifaction := Notification {
@@ -320,4 +240,6 @@ check :: proc(paths: []string, writer: ^Writer, config: ^common.Config) {
send_notification(notifaction, writer)
}
}
+
+
}