diff options
| author | DanielGavin <danielgavin5@hotmail.com> | 2020-12-05 00:39:50 +0100 |
|---|---|---|
| committer | DanielGavin <danielgavin5@hotmail.com> | 2020-12-05 00:39:50 +0100 |
| commit | 498e8a3895cd5b1db756b7f61eb48d1fd4211460 (patch) | |
| tree | 71f35915bc9c449f762c1b7e25014fc6f7685e39 /src/server | |
| parent | efd2930b74943a4dbe463810f0c7b3e9ede0ab84 (diff) | |
added allocator - no more parsing the file every request
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/analysis.odin | 1 | ||||
| -rw-r--r-- | src/server/documents.odin | 55 | ||||
| -rw-r--r-- | src/server/requests.odin | 330 |
3 files changed, 256 insertions, 130 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 245ca33..b84379f 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -67,7 +67,6 @@ make_ast_context :: proc(file: ast.File, imports: [] Package, package_name: stri document_package = package_name, current_package = package_name, }; - return ast_context; } diff --git a/src/server/documents.odin b/src/server/documents.odin index 7f14252..5a0261c 100644 --- a/src/server/documents.odin +++ b/src/server/documents.odin @@ -35,10 +35,12 @@ Document :: struct { ast: ast.File, imports: [] Package, package_name: string, + allocator: ^common.Scratch_Allocator, //because does not support freeing I use arena allocators for each document }; DocumentStorage :: struct { documents: map [string] Document, + free_allocators: [dynamic] ^common.Scratch_Allocator, }; document_storage: DocumentStorage; @@ -47,6 +49,24 @@ document_storage_shutdown :: proc() { delete(document_storage.documents); } +document_get_allocator :: proc() -> ^common.Scratch_Allocator { + + if len(document_storage.free_allocators) > 0 { + return pop(&document_storage.free_allocators); + } + + else { + allocator := new(common.Scratch_Allocator); + common.scratch_allocator_init(allocator, mem.megabytes(1)); + return allocator; + } + +} + +document_free_allocator :: proc(allocator: ^common.Scratch_Allocator) { + append(&document_storage.free_allocators, allocator); +} + document_get :: proc(uri_string: string) -> ^Document { uri, parsed_ok := common.parse_uri(uri_string, context.temp_allocator); @@ -84,6 +104,7 @@ document_open :: proc(uri_string: string, text: string, config: ^common.Config, document.client_owned = true; document.text = transmute([] u8)text; document.used_text = len(document.text); + document.allocator = document_get_allocator(); if err := document_refresh(document, config, writer); err != .None { return err; @@ -98,6 +119,7 @@ document_open :: proc(uri_string: string, text: string, config: ^common.Config, text = transmute([] u8)text, client_owned = true, used_text = len(text), + allocator = document_get_allocator(), }; if err := document_refresh(&document, config, writer); err != .None { @@ -221,9 +243,9 @@ document_close :: proc(uri_string: string) -> common.Error { return .InvalidRequest; } - //free_imports(document); - - //common.free_ast_file(document.ast); + free_all(common.scratch_allocator(document.allocator)); + document_free_allocator(document.allocator); + document.allocator = nil; document.client_owned = false; @@ -246,7 +268,6 @@ document_refresh :: proc(document: ^Document, config: ^common.Config, writer: ^W return .ParseError; } - //right now we don't allow to writer errors out from files read from the file directory, core files, etc. if writer != nil && len(errors) > 0 { document.diagnosed_errors = true; @@ -322,24 +343,8 @@ parser_warning_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) { } -free_imports :: proc(document: ^Document) { - if document.imports != nil { - - for imp in document.imports { - delete(imp.name); - } - - delete(document.imports); - delete(document.package_name); - - document.imports = nil; - } -} - parse_document :: proc(document: ^Document, config: ^common.Config) -> ([] ParserError, bool) { - context.allocator = context.temp_allocator; - p := parser.Parser { err = parser_error_handler, warn = parser_warning_handler, @@ -347,7 +352,9 @@ parse_document :: proc(document: ^Document, config: ^common.Config) -> ([] Parse current_errors = make([dynamic] ParserError, context.temp_allocator); - //common.free_ast_file(document.ast); + free_all(common.scratch_allocator(document.allocator)); + + context.allocator = common.scratch_allocator(document.allocator); document.ast = ast.File { fullpath = document.uri.path, @@ -356,10 +363,8 @@ parse_document :: proc(document: ^Document, config: ^common.Config) -> ([] Parse parser.parse_file(&p, &document.ast); - //free_imports(document); - - document.imports = make([]Package, len(document.ast.imports), context.temp_allocator); - document.package_name = strings.to_lower(path.dir(document.uri.path, context.temp_allocator), context.temp_allocator); + document.imports = make([]Package, len(document.ast.imports)); + document.package_name = strings.to_lower(path.dir(document.uri.path, context.temp_allocator)); for imp, index in document.ast.imports { diff --git a/src/server/requests.odin b/src/server/requests.odin index 3347544..96146a1 100644 --- a/src/server/requests.odin +++ b/src/server/requests.odin @@ -20,9 +20,39 @@ Header :: struct { content_type: string, }; +RequestType :: enum { + Initialize, + Initialized, + Shutdown, + Exit, + DidOpen, + DidChange, + DidClose, + DidSave, + Definition, + Completion, + SignatureHelp, + DocumentSymbol, + SemanticTokensFull, + SemanticTokensRange, +}; + +RequestInfo :: struct { + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, + result: common.Error, +}; + + pool: thread.Pool; +get_request_info :: proc(task: ^thread.Task) -> ^RequestInfo { + return cast(^RequestInfo)task.data; +} + make_response_message :: proc(id: RequestId, params: ResponseParams) -> ResponseMessage { return ResponseMessage { @@ -136,22 +166,35 @@ read_and_parse_body :: proc(reader: ^Reader, header: Header) -> (json.Value, boo return value, true; } +request_map : map [string] RequestType = + {"initialize" = .Initialize, + "initialized" = .Initialized, + "shutdown" = .Shutdown, + "exit" = .Exit, + "textDocument/didOpen" = .DidOpen, + "textDocument/didChange" = .DidChange, + "textDocument/didClose" = .DidClose, + "textDocument/didSave" = .DidSave, + "textDocument/definition" = .Definition, + "textDocument/completion" = .Completion, + "textDocument/signatureHelp" = .SignatureHelp, + "textDocument/documentSymbol" = .DocumentSymbol, + "textDocument/semanticTokens/full" = .SemanticTokensFull, + "textDocument/semanticTokens/range" = .SemanticTokensRange}; + +handle_error :: proc(err: common.Error, id: RequestId, writer: ^Writer) { + + if err != .None { -call_map : map [string] proc(json.Value, RequestId, ^common.Config, ^Writer) -> common.Error = - {"initialize" = request_initialize, - "initialized" = request_initialized, - "shutdown" = request_shutdown, - "exit" = notification_exit, - "textDocument/didOpen" = notification_did_open, - "textDocument/didChange" = notification_did_change, - "textDocument/didClose" = notification_did_close, - "textDocument/didSave" = notification_did_save, - "textDocument/definition" = request_definition, - "textDocument/completion" = request_completion, - "textDocument/signatureHelp" = request_signature_help, - "textDocument/documentSymbol" = request_document_symbols, - "textDocument/semanticTokens/full" = request_semantic_token_full, - "textDocument/semanticTokens/range" = request_semantic_token_range}; + response := make_response_message_error( + id = id, + error = ResponseError {code = err, message = ""} + ); + + send_error(response, writer); + } + +} handle_request :: proc(request: json.Value, config: ^common.Config, writer: ^Writer) -> bool { @@ -180,8 +223,8 @@ handle_request :: proc(request: json.Value, config: ^common.Config, writer: ^Wri method := root["method"].value.(json.String); - fn: proc(json.Value, RequestId, ^common.Config, ^Writer) -> common.Error; - fn, ok = call_map[method]; + request_type: RequestType; + request_type, ok = request_map[method]; if !ok { @@ -194,35 +237,78 @@ handle_request :: proc(request: json.Value, config: ^common.Config, writer: ^Wri } else { - err := fn(root["params"], id, config, writer); - if err != .None { + info := new(RequestInfo); + + info.params = root["params"]; + info.id = id; + info.config = config; + info.writer = writer; + + task_proc: thread.Task_Proc; + + switch request_type { + case .Initialize: + task_proc = request_initialize; + case .Initialized: + task_proc = request_initialized; + case .Shutdown: + task_proc = request_shutdown; + case .Exit: + task_proc = notification_exit; + case .DidOpen: + task_proc = notification_did_open; + case .DidChange: + task_proc = notification_did_change; + case .DidClose: + task_proc = notification_did_close; + case .DidSave: + task_proc = notification_did_save; + case .Definition: + task_proc = request_definition; + case .Completion: + task_proc = request_completion; + case .SignatureHelp: + task_proc = request_signature_help; + case .DocumentSymbol: + task_proc = request_document_symbols; + case .SemanticTokensFull: + task_proc = request_semantic_token_full; + case .SemanticTokensRange: + task_proc = request_semantic_token_range; + } - response := make_response_message_error( - id = id, - error = ResponseError {code = err, message = ""} - ); + task := thread.Task { + data = info, + procedure = task_proc, + }; + + task_proc(&task); - send_error(response, writer); - } } return true; } -request_initialize :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_initialize :: proc(task: ^thread.Task) { + + info := get_request_info(task); + + using info; params_object, ok := params.value.(json.Object); if !ok { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } initialize_params: RequestInitializeParams; if unmarshal(params, initialize_params, context.temp_allocator) != .None { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } config.workspace_folders = make([dynamic]common.WorkspaceFolder); @@ -298,7 +384,7 @@ request_initialize :: proc(params: json.Value, id: RequestId, config: ^common.Co }, semanticTokensProvider = SemanticTokensOptions { range = true, - full = false, + full = true, legend = SemanticTokensLegend { tokenTypes = token_types, tokenModifiers = token_modifiers, @@ -319,15 +405,17 @@ request_initialize :: proc(params: json.Value, id: RequestId, config: ^common.Co index.build_static_index(context.allocator, config); log.info("Finished indexing"); - - return .None; } -request_initialized :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { - return .None; +request_initialized :: proc(task: ^thread.Task) { + } -request_shutdown :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_shutdown :: proc(task: ^thread.Task) { + + info := get_request_info(task); + + using info; response := make_response_message( params = nil, @@ -335,32 +423,35 @@ request_shutdown :: proc(params: json.Value, id: RequestId, config: ^common.Conf ); send_response(response, writer); - - return .None; } -request_definition :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_definition :: proc(task: ^thread.Task) { + + info := get_request_info(task); + + using info; params_object, ok := params.value.(json.Object); if !ok { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } definition_params: TextDocumentPositionParams; if unmarshal(params, definition_params, context.temp_allocator) != .None { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } document := document_get(definition_params.textDocument.uri); if document == nil { - return .InternalError; + handle_error(.InternalError, id, writer); + return; } - document_refresh(document, config, nil); - location, ok2 := get_definition_location(document, definition_params.position); if !ok2 { @@ -373,18 +464,20 @@ request_definition :: proc(params: json.Value, id: RequestId, config: ^common.Co ); send_response(response, writer); +} - return .None; -} +request_completion :: proc(task: ^thread.Task) { + info := get_request_info(task); -request_completion :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { + using info; params_object, ok := params.value.(json.Object); if !ok { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } completition_params: CompletionParams; @@ -392,22 +485,23 @@ request_completion :: proc(params: json.Value, id: RequestId, config: ^common.Co if unmarshal(params, completition_params, context.temp_allocator) != .None { log.error("Failed to unmarshal completion request"); - return .ParseError; + handle_error(.ParseError, id, writer); + return; } document := document_get(completition_params.textDocument.uri); if document == nil { - return .InternalError; + handle_error(.InternalError, id, writer); + return; } - document_refresh(document, config, nil); - list: CompletionList; list, ok = get_completion_list(document, completition_params.position); if !ok { - return .InternalError; + handle_error(.InternalError, id, writer); + return; } response := make_response_message( @@ -416,32 +510,35 @@ request_completion :: proc(params: json.Value, id: RequestId, config: ^common.Co ); send_response(response, writer); - - return .None; } -request_signature_help :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_signature_help :: proc(task: ^thread.Task) { + + info := get_request_info(task); + + using info; params_object, ok := params.value.(json.Object); if !ok { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } signature_params: SignatureHelpParams; if unmarshal(params, signature_params, context.temp_allocator) != .None { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } document := document_get(signature_params.textDocument.uri); if document == nil { - return .InternalError; + handle_error(.InternalError, id, writer); + return; } - document_refresh(document, config, nil); - help: SignatureHelp; help, ok = get_signature_information(document, signature_params.position); @@ -451,100 +548,123 @@ request_signature_help :: proc(params: json.Value, id: RequestId, config: ^commo ); send_response(response, writer); - - return .None; } -notification_exit :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +notification_exit :: proc(task: ^thread.Task) { + info := get_request_info(task); + using info; config.running = false; - return .None; } -notification_did_open :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +notification_did_open :: proc(task: ^thread.Task) { + + info := get_request_info(task); + + using info; params_object, ok := params.value.(json.Object); if !ok { log.error("Failed to parse open document notification"); - return .ParseError; + handle_error(.ParseError, id, writer); + return; } open_params: DidOpenTextDocumentParams; if unmarshal(params, open_params, context.allocator) != .None { log.error("Failed to parse open document notification"); - return .ParseError; + handle_error(.ParseError, id, writer); + return; } - return document_open(open_params.textDocument.uri, open_params.textDocument.text, config, writer); + if n := document_open(open_params.textDocument.uri, open_params.textDocument.text, config, writer); n != .None { + handle_error(n, id, writer); + } } -notification_did_change :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +notification_did_change :: proc(task: ^thread.Task) { + + info := get_request_info(task); + + using info; params_object, ok := params.value.(json.Object); if !ok { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } change_params: DidChangeTextDocumentParams; if unmarshal(params, change_params, context.temp_allocator) != .None { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } document_apply_changes(change_params.textDocument.uri, change_params.contentChanges, config, writer); - - return .None; } -notification_did_close :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +notification_did_close :: proc(task: ^thread.Task) { + + info := get_request_info(task); + + using info; params_object, ok := params.value.(json.Object); if !ok { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } close_params: DidCloseTextDocumentParams; if unmarshal(params, close_params, context.temp_allocator) != .None { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } - return document_close(close_params.textDocument.uri); + if n := document_close(close_params.textDocument.uri); n != .None { + handle_error(n, id, writer); + return; + } } -notification_did_save :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { - +notification_did_save :: proc(task: ^thread.Task) { - return .None; } -request_semantic_token_full :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_semantic_token_full :: proc(task: ^thread.Task) { + + info := get_request_info(task); + + using info; params_object, ok := params.value.(json.Object); if !ok { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } semantic_params: SemanticTokensParams; if unmarshal(params, semantic_params, context.temp_allocator) != .None { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } document := document_get(semantic_params.textDocument.uri); if document == nil { - return .InternalError; + handle_error(.InternalError, id, writer); + return; } - document_refresh(document, config, nil); - range := common.Range { start = common.Position { line = 0, @@ -564,32 +684,35 @@ request_semantic_token_full :: proc(params: json.Value, id: RequestId, config: ^ ); send_response(response, writer); - - return .None; } -request_semantic_token_range :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_semantic_token_range :: proc(task: ^thread.Task) { + + info := get_request_info(task); + + using info; params_object, ok := params.value.(json.Object); if !ok { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } semantic_params: SemanticTokensRangeParams; if unmarshal(params, semantic_params, context.temp_allocator) != .None { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } document := document_get(semantic_params.textDocument.uri); if document == nil { - return .InternalError; + handle_error(.InternalError, id, writer); + return; } - document_refresh(document, config, nil); - //symbols: SemanticTokens; symbols := get_semantic_tokens(document, semantic_params.range); @@ -599,42 +722,41 @@ request_semantic_token_range :: proc(params: json.Value, id: RequestId, config: ); send_response(response, writer); - - return .None; } -request_document_symbols :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_document_symbols :: proc(task: ^thread.Task) { + + info := get_request_info(task); + using info; params_object, ok := params.value.(json.Object); if !ok { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } symbol_params: DocumentSymbolParams; if unmarshal(params, symbol_params, context.temp_allocator) != .None { - return .ParseError; + handle_error(.ParseError, id, writer); + return; } document := document_get(symbol_params.textDocument.uri); if document == nil { - return .InternalError; + handle_error(.InternalError, id, writer); + return; } - document_refresh(document, config, nil); - symbols := get_document_symbols(document); - response := make_response_message( params = symbols, id = id, ); send_response(response, writer); - - return .None; }
\ No newline at end of file |