You've already forked ada_language_server
mirror of
https://github.com/AdaCore/ada_language_server.git
synced 2026-02-12 12:45:50 -08:00
Use P_All_Env_Elements and filter the returned node to find all the function declaration with the same name. Fix param type in the generated spec. Add tests.
572 lines
20 KiB
Python
572 lines
20 KiB
Python
#!/usr/bin/env python
|
|
|
|
import os
|
|
import os.path
|
|
from os.path import join
|
|
|
|
""" Script to generate the 'generated' parts of the code """
|
|
|
|
LSP_Messages_Generic_Header = """-- Automatically generated, do not edit.
|
|
|
|
with Ada.Tags;
|
|
with LSP.Generic_{kind}s;
|
|
with LSP.JSON_Streams;
|
|
with LSP.Server_{kind}_Receivers;
|
|
use LSP.Server_{kind}_Receivers;
|
|
|
|
package LSP.Messages.Server_{kind}s is
|
|
|
|
type Server_{kind} is abstract new LSP.Messages.{kind}Message
|
|
with null record;
|
|
|
|
function Decode
|
|
(JS : not null access LSP.JSON_Streams.JSON_Stream)
|
|
return Server_{kind} is abstract;
|
|
|
|
procedure Visit
|
|
(Self : Server_{kind};
|
|
Handler : access Server_{kind}_Receiver'Class) is abstract;
|
|
|
|
function Method_To_Tag (Method : LSP.Types.LSP_String) return Ada.Tags.Tag;
|
|
-- For given LSP method return a corresponding message type tag
|
|
"""
|
|
|
|
C_Method_Function_Snippet = """
|
|
function On_{request_name}_Request
|
|
(Self : access Server_Request_Handler;
|
|
Request : LSP.Messages.Server_Requests.{request_name}_Request)
|
|
return LSP.Messages.Server_Responses.{response_name}
|
|
is abstract;
|
|
"""
|
|
|
|
C_Method_Procedure_Snippet = """
|
|
procedure On_{request_name}_{kind}
|
|
(Self : access Server_{kind}_Receiver;
|
|
Value : LSP.Messages.{params_name}) is abstract;
|
|
"""
|
|
|
|
C_Method_Procedure_Snippet_Noparam = """
|
|
procedure On_{request_name}_{kind}
|
|
(Self : access Server_{kind}_Receiver) is abstract;
|
|
"""
|
|
|
|
C_Method_Request_Snippet = """
|
|
procedure On_{request_name}_{kind}
|
|
(Self : access Server_{kind}_Receiver;
|
|
Value : LSP.Messages.Server_{kind}s.{request_name}_{kind})
|
|
is abstract;
|
|
"""
|
|
|
|
LSP_Messages_Generic_Body_Header = """-- Automatically generated, do not edit.
|
|
|
|
with Ada.Strings.UTF_Encoding;
|
|
|
|
package body LSP.Messages.Server_{kind}s is
|
|
|
|
-- These messages are sent from client to server.
|
|
|
|
Map : Maps.Map;
|
|
|
|
function Method_To_Tag
|
|
(Method : LSP.Types.LSP_String) return Ada.Tags.Tag is
|
|
begin
|
|
return Method_To_Tag (Map, Method);
|
|
end Method_To_Tag;
|
|
"""
|
|
|
|
C_Method_Visit_Body_Snippet = """
|
|
overriding procedure Visit
|
|
(Self : {request_name}_{kind};
|
|
Handler : access Server_{kind}_Receiver'Class) is
|
|
begin
|
|
Handler.On_{request_name}_{kind} (Self{params});
|
|
end Visit;
|
|
"""
|
|
|
|
C_Method_Visit_Body_Snippet_Noparams = """
|
|
overriding procedure Visit
|
|
(Self : {request_name}_{kind};
|
|
Handler : access Server_{kind}_Receiver'Class)
|
|
is
|
|
pragma Unreferenced (Self);
|
|
begin
|
|
Handler.On_{request_name}_{kind};
|
|
end Visit;
|
|
"""
|
|
|
|
C_Method_Decode_Body_Snippet = """
|
|
overriding function Decode
|
|
(JS : not null access LSP.JSON_Streams.JSON_Stream)
|
|
return {request_name}_{kind} is
|
|
begin
|
|
return V : {request_name}_{kind} do
|
|
{kind}Message'Read (JS, {kind}Message (V));
|
|
end return;
|
|
end Decode;
|
|
"""
|
|
|
|
C_Handler_Procedure_Body = """-- Automatically generated, do not edit.
|
|
|
|
with LSP.Messages.Server_Notifications; use LSP.Messages.Server_Notifications;
|
|
|
|
procedure LSP.Servers.Handle_{kind}
|
|
(Self : not null LSP.Server_Notification_Handlers
|
|
.Server_Notification_Handler_Access;
|
|
{kind} : LSP.Messages.{kind}Message'Class) is
|
|
begin
|
|
{handler_snippets}
|
|
end LSP.Servers.Handle_{kind};
|
|
"""
|
|
|
|
C_Handler_Function_Body = """-- Automatically generated, do not edit.
|
|
|
|
with LSP.Messages.Server_Requests; use LSP.Messages.Server_Requests;
|
|
with Ada.Strings.UTF_Encoding;
|
|
|
|
function LSP.Servers.Handle_{kind}
|
|
(Self : not null Server_Request_Handlers
|
|
.Server_Request_Handler_Access;
|
|
{kind} : LSP.Messages.{kind}Message'Class)
|
|
return LSP.Messages.ResponseMessage'Class
|
|
is
|
|
function "+" (Text : Ada.Strings.UTF_Encoding.UTF_8_String)
|
|
return LSP.Types.LSP_String renames LSP.Types.To_LSP_String;
|
|
begin
|
|
{handler_snippets}
|
|
return LSP.Messages.ResponseMessage'
|
|
(Is_Error => True,
|
|
jsonrpc => <>,
|
|
id => <>,
|
|
error =>
|
|
(Is_Set => True,
|
|
Value =>
|
|
(code => LSP.Messages.MethodNotFound,
|
|
message => +"The {kind} handler doesn't support this",
|
|
others => <>)));
|
|
end LSP.Servers.Handle_{kind};
|
|
"""
|
|
|
|
C_Handler_Snippet_Function = """
|
|
if {kind} in {request_name}_{kind}'Class then
|
|
declare
|
|
R : LSP.Messages.ResponseMessage'Class :=
|
|
Self.On_{request_name}_{kind}
|
|
({request_name}_{kind} ({kind}));
|
|
begin
|
|
R.jsonrpc := +"2.0";
|
|
R.id := Request.id;
|
|
return R;
|
|
end;
|
|
end if;
|
|
"""
|
|
|
|
C_Handler_Snippet_Procedure = """
|
|
if {kind} in {request_name}_{kind}'Class then
|
|
Self.On_{request_name}_{kind}
|
|
(({request_name}_{kind} ({kind}).params));
|
|
return;
|
|
end if;
|
|
"""
|
|
|
|
C_Handler_Snippet_Procedure_Noparams = """
|
|
if {kind} in {request_name}_{kind}'Class then
|
|
Self.On_{request_name}_{kind};
|
|
return;
|
|
end if;
|
|
"""
|
|
|
|
LSP_Messages_Body_Begin = """
|
|
function "+" (Text : Ada.Strings.UTF_Encoding.UTF_8_String)
|
|
return LSP.Types.LSP_String renames
|
|
LSP.Types.To_LSP_String;
|
|
|
|
begin"""
|
|
|
|
LSP_Messages_Insert = """
|
|
|
|
Map.Insert
|
|
(+"{protocol_name}",
|
|
{request_name}_{kind}'Tag);"""
|
|
|
|
LSP_Messages_Generic_Footer = """
|
|
end LSP.Messages.Server_{kind}s;
|
|
"""
|
|
|
|
LSP_Messages_Generic_Type_Snippet = """
|
|
package {request_name}_{kind}s is
|
|
new LSP.Generic_{kind}s
|
|
(Server_{kind},
|
|
{params_name},
|
|
Server_{kind}_Receiver'Class);
|
|
|
|
type {request_name}_{kind} is
|
|
new {request_name}_{kind}s.{kind} with null record;
|
|
|
|
overriding procedure Visit
|
|
(Self : {request_name}_{kind};
|
|
Handler : access Server_{kind}_Receiver'Class);
|
|
"""
|
|
|
|
LSP_Messages_Generic_Type_Snippet_Noparams = """
|
|
type {request_name}_{kind} is new Server_{kind} with null record;
|
|
|
|
overriding function Decode
|
|
(JS : not null access LSP.JSON_Streams.JSON_Stream)
|
|
return {request_name}_{kind};
|
|
|
|
overriding procedure Visit
|
|
(Self : {request_name}_{kind};
|
|
Handler : access Server_{kind}_Receiver'Class);
|
|
"""
|
|
|
|
LSP_Server_Handlers_Header = """-- Automatically generated, do not edit.
|
|
|
|
with LSP.Messages.Server_Requests;
|
|
with LSP.Messages.Server_Responses;
|
|
|
|
package LSP.Server_Request_{handler}s is
|
|
|
|
type Server_Request_{handler} is limited interface;
|
|
type Server_Request_{handler}_Access is
|
|
access all Server_Request_{handler}'Class;
|
|
-- A type which represents a handler which supports reacting
|
|
-- to Requests. Clients implementing this interface should override
|
|
-- the *_Request methods, and clients making use of this interface
|
|
-- should simply call Handle_Request when they want to dispatch
|
|
-- a Request to the handler.
|
|
"""
|
|
|
|
LSP_Server_Handlers_Footer = """
|
|
end LSP.Server_{kind}_{handler}s;
|
|
"""
|
|
|
|
LSP_Server_Recievers_Header = """-- Automatically generated, do not edit.
|
|
|
|
limited with LSP.Messages{extra_with};
|
|
|
|
package LSP.Server_{kind}_{handler}s is
|
|
|
|
type Server_{kind}_{handler} is limited interface;
|
|
type Server_{kind}_{handler}_Access is
|
|
access all Server_{kind}_{handler}'Class;
|
|
-- A type which represents a handler which supports reacting
|
|
-- to {kind}s. Clients implementing this interface should override
|
|
-- the *_{kind} methods, and clients making use of this interface
|
|
-- should simply call corresponding method when they want to dispatch
|
|
-- a {kind} to the handler.
|
|
"""
|
|
|
|
basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
|
|
|
|
|
REQUESTS = [
|
|
('initialize', 'Initialize', 'InitializeParams', 'Initialize_Response'),
|
|
('shutdown', 'Shutdown', None, 'Shutdown_Response'),
|
|
('textDocument/codeAction', 'CodeAction', 'CodeActionParams',
|
|
'CodeAction_Response'),
|
|
('textDocument/completion', 'Completion', 'TextDocumentPositionParams',
|
|
'Completion_Response'),
|
|
('textDocument/definition', 'Definition', 'DefinitionParams',
|
|
'Location_Link_Response'),
|
|
('textDocument/declaration', 'Declaration', 'DeclarationParams',
|
|
'Location_Link_Response'),
|
|
('textDocument/implementation', 'Implementation',
|
|
'ImplementationParams', 'Location_Link_Response'),
|
|
('textDocument/typeDefinition', 'Type_Definition',
|
|
'TextDocumentPositionParams', 'Location_Link_Response'),
|
|
('textDocument/documentHighlight', 'Highlight', 'TextDocumentPositionParams',
|
|
'Highlight_Response'),
|
|
('textDocument/hover', 'Hover', 'TextDocumentPositionParams',
|
|
'Hover_Response'),
|
|
('textDocument/documentLink', 'Document_Links',
|
|
'DocumentLinkParams', 'Links_Response'),
|
|
('textDocument/references', 'References', 'ReferenceParams',
|
|
'Location_Response'),
|
|
('textDocument/signatureHelp', 'Signature_Help',
|
|
'SignatureHelpParams', 'SignatureHelp_Response'),
|
|
('textDocument/documentSymbol', 'Document_Symbols',
|
|
'DocumentSymbolParams', 'Symbol_Response'),
|
|
('textDocument/rename', 'Rename', 'RenameParams', 'Rename_Response'),
|
|
('textDocument/prepareRename', 'Prepare_Rename',
|
|
'PrepareRenameParams', 'Prepare_Rename_Response'),
|
|
('textDocument/executeCommand', 'Execute_Command', 'ExecuteCommandParams',
|
|
'ExecuteCommand_Response'),
|
|
('textDocument/documentColor', 'Document_Color', 'DocumentColorParams',
|
|
'DocumentColor_Response'),
|
|
('textDocument/colorPresentation', 'Color_Presentation',
|
|
'ColorPresentationParams', 'ColorPresentation_Response'),
|
|
('textDocument/foldingRange', 'Folding_Range',
|
|
'FoldingRangeParams', 'FoldingRange_Response'),
|
|
('textDocument/formatting', 'Formatting',
|
|
'DocumentFormattingParams', 'Formatting_Response'),
|
|
('textDocument/rangeFormatting', 'Range_Formatting',
|
|
'DocumentRangeFormattingParams', 'Range_Formatting_Response'),
|
|
('textDocument/selectionRange', 'Selection_Range',
|
|
'SelectionRangeParams', 'SelectionRange_Response'),
|
|
('textDocument/prepareCallHierarchy', 'Prepare_Call_Hierarchy',
|
|
'CallHierarchyPrepareParams', 'PrepareCallHierarchy_Response'),
|
|
('callHierarchy/incomingCalls', 'Incoming_Calls',
|
|
'CallHierarchyIncomingCallsParams', 'IncomingCalls_Response'),
|
|
('callHierarchy/outgoingCalls', 'Outgoing_Calls',
|
|
'CallHierarchyOutgoingCallsParams', 'OutgoingCalls_Response'),
|
|
('workspace/symbol', 'Workspace_Symbols', 'WorkspaceSymbolParams',
|
|
'Symbol_Response'),
|
|
('workspace/executeCommand', 'Workspace_Execute_Command',
|
|
'ExecuteCommandParams', 'ExecuteCommand_Response'),
|
|
|
|
# ALS-specific requests
|
|
('textDocument/alsCalledBy', 'ALS_Called_By', 'TextDocumentPositionParams',
|
|
'ALS_Called_By_Response'),
|
|
('textDocument/alsCalls', 'ALS_Calls', 'TextDocumentPositionParams',
|
|
'ALS_Calls_Response'),
|
|
('textDocument/alsShowDependencies', 'ALS_Show_Dependencies',
|
|
'ALS_ShowDependenciesParams',
|
|
'ALS_ShowDependencies_Response'),
|
|
('$/alsDebug', 'ALS_Debug', 'ALSDebugParams', 'ALS_Debug_Response'),
|
|
]
|
|
# Names of requests in the form (protocol name, Ada name, parameter name,
|
|
# response name)
|
|
|
|
NOTIFICATIONS = [
|
|
('initialized', 'Initialized', None),
|
|
('exit', 'Exit', None),
|
|
|
|
('workspace/didChangeConfiguration', 'DidChangeConfiguration',
|
|
'DidChangeConfigurationParams'),
|
|
('workspace/didChangeWorkspaceFolders', 'DidChangeWorkspaceFolders',
|
|
'DidChangeWorkspaceFoldersParams'),
|
|
('workspace/didChangeWatchedFiles', 'DidChangeWatchedFiles',
|
|
'DidChangeWatchedFilesParams'),
|
|
('$/cancelRequest', 'Cancel', 'CancelParams'),
|
|
|
|
# TODO: rename these to TextDocumentDidOpen/DidChange/DidSave/DidClose?
|
|
('textDocument/didOpen', 'DidOpenTextDocument',
|
|
'DidOpenTextDocumentParams'),
|
|
('textDocument/didChange', 'DidChangeTextDocument',
|
|
'DidChangeTextDocumentParams'),
|
|
('textDocument/didSave', 'DidSaveTextDocument',
|
|
'DidSaveTextDocumentParams'),
|
|
('textDocument/didClose', 'DidCloseTextDocument',
|
|
'DidCloseTextDocumentParams'),
|
|
]
|
|
|
|
|
|
def write_message_types():
|
|
""" Write source/protocol/lsp-messages-request.* """
|
|
|
|
def write_package(data_array, kind, ads_name, handler_is_procedure):
|
|
"""Factorization function"""
|
|
|
|
# Write the .ads
|
|
with open(ads_name, 'w') as ads:
|
|
ads.write(LSP_Messages_Generic_Header.format(kind=kind))
|
|
|
|
for l in data_array:
|
|
request_name = l[1]
|
|
params_name = l[2]
|
|
if params_name:
|
|
ads.write(LSP_Messages_Generic_Type_Snippet.format(
|
|
request_name=request_name,
|
|
params_name=params_name,
|
|
kind=kind))
|
|
else:
|
|
ads.write(
|
|
LSP_Messages_Generic_Type_Snippet_Noparams.format(
|
|
request_name=request_name,
|
|
kind=kind))
|
|
|
|
ads.write(LSP_Messages_Generic_Footer.format(kind=kind))
|
|
|
|
def write_body(data_array, kind, adb_name, handler_is_procedure):
|
|
"""Factorization function"""
|
|
|
|
# Write the .adb
|
|
with open(adb_name, 'w') as adb:
|
|
adb.write(LSP_Messages_Generic_Body_Header.format(kind=kind))
|
|
|
|
for l in data_array:
|
|
request_name = l[1]
|
|
params_name = l[2]
|
|
|
|
if not params_name:
|
|
adb.write(
|
|
C_Method_Decode_Body_Snippet.format(
|
|
request_name=request_name,
|
|
kind=kind))
|
|
|
|
if params_name or not handler_is_procedure:
|
|
adb.write(
|
|
C_Method_Visit_Body_Snippet.format(
|
|
request_name=request_name,
|
|
kind=kind,
|
|
params=".params" if handler_is_procedure else ""))
|
|
else:
|
|
adb.write(
|
|
C_Method_Visit_Body_Snippet_Noparams.format(
|
|
request_name=request_name,
|
|
kind=kind))
|
|
|
|
adb.write(LSP_Messages_Body_Begin.format(kind=kind))
|
|
|
|
for l in data_array:
|
|
protocol_name = l[0]
|
|
request_name = l[1]
|
|
params_name = l[2]
|
|
adb.write(LSP_Messages_Insert.format(
|
|
protocol_name=protocol_name,
|
|
request_name=request_name,
|
|
kind=kind))
|
|
|
|
adb.write(LSP_Messages_Generic_Footer.format(kind=kind))
|
|
|
|
gen_dir = join(basedir, 'source', 'protocol', 'generated')
|
|
write_package(REQUESTS, 'Request',
|
|
join(gen_dir, 'lsp-messages-server_requests.ads'),
|
|
False)
|
|
write_package(NOTIFICATIONS, 'Notification',
|
|
join(gen_dir, 'lsp-messages-server_notifications.ads'),
|
|
True)
|
|
write_body(NOTIFICATIONS, 'Notification',
|
|
join(gen_dir, 'lsp-messages-server_notifications.adb'),
|
|
True)
|
|
write_body(REQUESTS, 'Request',
|
|
join(gen_dir, 'lsp-messages-server_requests.adb'),
|
|
False)
|
|
|
|
|
|
def write_handle_request():
|
|
def write_package(data_array, kind, adb_name, handler_is_procedure):
|
|
"""Factorization function"""
|
|
|
|
# Write the .adb
|
|
with open(adb_name, 'w') as adb:
|
|
handler_snippets = ""
|
|
|
|
# Generate the snippets
|
|
for l in data_array:
|
|
protocol_name = l[0]
|
|
request_name = l[1]
|
|
if handler_is_procedure:
|
|
handler_snippets += \
|
|
C_Handler_Snippet_Procedure.format(
|
|
request_name=request_name,
|
|
kind=kind)
|
|
else:
|
|
handler_snippets += \
|
|
C_Handler_Snippet_Function.format(
|
|
request_name=request_name,
|
|
kind=kind)
|
|
|
|
if handler_is_procedure:
|
|
adb.write(C_Handler_Procedure_Body.format(
|
|
kind=kind,
|
|
handler_snippets=handler_snippets))
|
|
else:
|
|
adb.write(C_Handler_Function_Body.format(
|
|
kind=kind,
|
|
handler_snippets=handler_snippets))
|
|
|
|
gen_dir = join(basedir, 'source', 'server', 'generated')
|
|
write_package(REQUESTS, 'Request',
|
|
join(gen_dir, 'lsp-servers-handle_request.adb'),
|
|
False)
|
|
|
|
|
|
|
|
def write_server_handlers():
|
|
""" Write source/server/lsp-server_{request/notification}_handlers.ads """
|
|
|
|
def write_package(data_array, handler_name,
|
|
ads_name, handler_is_procedure):
|
|
"""Factorization function"""
|
|
|
|
# Write the .ads
|
|
with open(ads_name, 'w') as ads:
|
|
|
|
ads.write(LSP_Server_Handlers_Header.format(
|
|
handler=handler_name))
|
|
|
|
for l in data_array:
|
|
ads.write(
|
|
C_Method_Function_Snippet.format(
|
|
request_name=l[1],
|
|
response_name=l[3]))
|
|
|
|
ads.write("""
|
|
procedure Handle_Error
|
|
(Self : access Server_Request_Handler) is null;
|
|
-- This procedure will be called when an unexpected error is raised in the
|
|
-- request processing loop.
|
|
""")
|
|
|
|
ads.write(LSP_Server_Handlers_Footer.format(
|
|
kind='Request', handler=handler_name))
|
|
|
|
gen_dir = join(basedir, 'source', 'server', 'generated')
|
|
write_package(REQUESTS, 'Handler',
|
|
join(gen_dir, 'lsp-server_request_handlers.ads'),
|
|
False)
|
|
|
|
|
|
def write_server_receivers():
|
|
""" Write source/server/lsp-server_{request/notification}_handlers.ads """
|
|
|
|
def write_package(data_array, kind, handler_name,
|
|
ads_name, is_request):
|
|
"""Factorization function"""
|
|
|
|
# Write the .ads
|
|
with open(ads_name, 'w') as ads:
|
|
ads.write(LSP_Server_Recievers_Header.format(
|
|
kind=kind, handler=handler_name,
|
|
extra_with=".Server_Requests" if is_request else""))
|
|
|
|
for l in data_array:
|
|
request_name = l[1]
|
|
params_name = l[2]
|
|
if params_name:
|
|
if is_request:
|
|
ads.write(
|
|
C_Method_Request_Snippet.format(
|
|
request_name=request_name,
|
|
params_name=params_name,
|
|
response_name=l[3],
|
|
kind=kind))
|
|
else:
|
|
ads.write(
|
|
C_Method_Procedure_Snippet.format(
|
|
request_name=request_name,
|
|
params_name=params_name,
|
|
kind=kind))
|
|
else:
|
|
if is_request:
|
|
ads.write(
|
|
C_Method_Request_Snippet.format(
|
|
request_name=request_name,
|
|
params_name=params_name,
|
|
response_name=l[3],
|
|
kind=kind))
|
|
else:
|
|
ads.write(
|
|
C_Method_Procedure_Snippet_Noparam.format(
|
|
request_name=request_name,
|
|
kind=kind))
|
|
|
|
ads.write(LSP_Server_Handlers_Footer.format(
|
|
kind=kind, handler=handler_name))
|
|
|
|
gen_dir = join(basedir, 'source', 'protocol', 'generated')
|
|
write_package(REQUESTS, 'Request', 'Receiver',
|
|
join(gen_dir, 'lsp-server_request_receivers.ads'),
|
|
True)
|
|
write_package(NOTIFICATIONS, 'Notification', 'Receiver',
|
|
join(gen_dir, 'lsp-server_notification_receivers.ads'),
|
|
False)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
write_message_types()
|
|
write_handle_request()
|
|
write_server_handlers()
|
|
write_server_receivers()
|