import libadalang as lal # The list of types to generate Write procedures: types_to_print = { # 'Message', 'RequestMessage', # 'ResponseMessage', 'NotificationMessage', 'CancelParams', 'Position', 'Span', 'CodeActionKind', 'AlsReferenceKind', 'AlsDisplayMethodAncestryOnNavigationPolicy', # 'AlsReferenceKind_Array', # 'AlsReferenceKind_Set', 'Location', 'LocationLink', # 'Location_Or_Link_Kind', # 'Location_Or_Link_Vector', 'DiagnosticSeverity', 'DiagnosticTag', 'CodeDescription', 'DiagnosticRelatedInformation', 'Diagnostic', # 'Command', 'TextEdit', 'AnnotatedTextEdit', 'TextDocumentIdentifier', 'VersionedTextDocumentIdentifier', 'OptionalVersionedTextDocumentIdentifier', 'TextDocumentEdit', 'FileResourceChangeKind', 'CreateFileOptions', 'CreateFile', 'RenameFileOptions', 'RenameFile', 'DeleteFileOptions', 'DeleteFile', # 'Document_Change_Kind', # 'Document_Change', # 'WorkspaceEdit', 'ChangeAnnotation', 'TextDocumentItem', 'TextDocumentPositionParams', # 'DocumentFilter', # 'DocumentSelector', 'dynamicRegistration', 'ResourceOperationKind', 'FailureHandlingKind', 'AnnotationSupport', 'WorkspaceEditClientCapabilities', 'SymbolKind', 'symbolKindCapabilities', 'Als_Visibility', 'WorkspaceSymbolClientCapabilities', 'WorkspaceClientCapabilities', 'MarkupKind', 'MarkupContent', # 'String_Or_MarkupContent', 'SaveOptions', 'TextDocumentSyncClientCapabilities', 'CompletionItemTag', 'CompletionItemTagSupport', 'resolveSupportCapability', 'InsertTextMode', 'insertTextModeSupportCapability', 'completionItemCapability', 'CompletionItemKind', 'CompletionItemKindSetCapabilities', 'CompletionClientCapabilities', 'HoverClientCapabilities', 'parameterInformation_Capability', 'signatureInformation_Capability', 'SignatureHelpClientCapabilities', 'DocumentSymbolClientCapabilities', 'DeclarationClientCapabilities', 'codeActionKindCapability', 'codeActionLiteralSupport_Capability', 'CodeActionClientCapabilities', 'DocumentLinkClientCapabilities', 'PrepareSupportDefaultBehavior', 'RenameClientCapabilities', 'DiagnosticTagSupport', 'PublishDiagnosticsClientCapabilities', 'FoldingRangeClientCapabilities', 'SemanticTokensFullCapabilities', 'SemanticTokensRequestCapabilities', 'TokenFormat', 'SemanticTokensClientCapabilities', 'TextDocumentClientCapabilities', 'ShowDocumentClientCapabilities', 'MessageActionItemCapabilities', 'ShowMessageRequestClientCapabilities', 'WindowClientCapabilities', 'MarkdownClientCapabilities', 'RegularExpressionsClientCapabilities', 'GeneralClientCapabilities', 'fileOperationsClientCapabilities', 'ClientCapabilities', 'WorkspaceFolder', # 'ProgressParam', 'WorkDoneProgressCreateParams', # 'WorkDoneProgressParams', # 'PartialResultParams', # 'Progress_Partial_Params', # 'Text_Progress_Partial_Params', 'Text_Progress_Params', 'ProgramInfo', 'TraceValue', 'InitializeParams', # 'WorkDoneProgressOptions', 'TextDocumentSyncKind', 'TextDocumentSyncOptions', # 'Optional_TextDocumentSyncOptions', 'CompletionOptions', 'SignatureHelpOptions', 'TextDocumentRegistrationOptions', 'TSW_RegistrationOptions', # 'Provider_Options', 'DocumentSymbolOptions', 'CodeActionOptions', 'CodeLensOptions', 'DocumentOnTypeFormattingOptions', 'RenameOptions', 'DocumentLinkOptions', 'ExecuteCommandOptions', 'WorkspaceFoldersServerCapabilities', 'FileOperationPatternKind', 'FileOperationPatternOptions', 'FileOperationPattern', 'FileOperationFilter', 'FileOperationRegistrationOptions', 'FileOperationsServerCapabilities', 'workspace_Options', 'SemanticTokenTypes', 'SemanticTokenModifiers', 'SemanticTokensLegend', 'SemanticTokensOptions', 'ServerCapabilities', 'InitializeResult', 'InitializedParams', 'LogTraceParams', 'SetTraceParams', # 'InitializeError', 'MessageType', 'ShowMessageParams', 'ShowMessageRequestParams', 'LogMessageParams', 'TextDocumentChangeRegistrationOptions', 'TextDocumentSaveRegistrationOptions', 'CompletionRegistrationOptions', 'SignatureHelpRegistrationOptions', 'CodeLensRegistrationOptions', 'CodeLensWorkspaceClientCapabilities', 'FileOperationsClientCapabilities', 'DocumentLinkRegistrationOptions', 'DocumentOnTypeFormattingRegistrationOptions', 'ExecuteCommandRegistrationOptions', # 'Registration_Option', 'Registration', 'RegistrationParams', 'Unregistration', 'UnregistrationParams', 'DidChangeConfigurationParams', 'DidOpenTextDocumentParams', 'TextDocumentContentChangeEvent', 'DidChangeTextDocumentParams', 'TextDocumentSaveReason', # 'WillSaveTextDocumentParams', 'DidSaveTextDocumentParams', 'DidCloseTextDocumentParams', 'FileChangeType', 'FileEvent', 'DidChangeWatchedFilesParams', 'PublishDiagnosticsParams', 'InsertTextFormat', 'InsertReplaceEdit', 'CompletionItem', 'CompletionList', # 'MarkedString', # 'MarkupContent_Or_MarkedString_Vector', 'Hover', # 'Parameter_Label', 'ParameterInformation', 'SignatureInformation', 'SignatureHelp', 'ReferenceContext', 'ReferenceParams', 'DocumentHighlightKind', 'DocumentHighlight', 'DocumentSymbolParams', 'SymbolTag', 'tagSupportCapability', # 'DocumentSymbol', # 'DocumentSymbol_Tree', 'SymbolInformation', # 'Symbol_Vector', 'WorkspaceSymbolParams', 'CodeActionContext', 'CodeActionParams', # 'CodeLensParams', # 'CodeLens', # 'DocumentLinkParams', # 'DocumentLink', 'FormattingOptions', 'DocumentFormattingParams', 'DocumentRangeFormattingParams', 'DocumentOnTypeFormattingParams', 'RenameParams', # 'ExecuteCommandParams', 'ApplyWorkspaceEditParams', 'ApplyWorkspaceEditResult', 'WorkDoneProgressBegin', 'WorkDoneProgressReport', 'WorkDoneProgressEnd', # 'Progress_Kind', # 'Progress_Params', 'WorkspaceFoldersChangeEvent', 'DidChangeWorkspaceFoldersParams', 'ConfigurationItem', 'ConfigurationParams', # 'WatchKind', # 'WatchKind_Set', 'FileSystemWatcher', 'DidChangeWatchedFilesRegistrationOptions', 'CompletionTriggerKind', 'CompletionContext', 'CompletionParams', 'Disable_Reason', # 'CodeAction', 'CodeActionRegistrationOptions', 'RGBA_Color', 'ColorInformation', 'ColorPresentationParams', 'ColorPresentation', 'RenameRegistrationOptions', 'FoldingRangeParams', 'FoldingRange', 'DocumentColorParams', # 'HoverParams', 'SignatureHelpTriggerKind', 'SignatureHelpContext', 'SignatureHelpParams', # 'DeclarationParams', 'NavigationRequestParams', # 'DefinitionParams', # 'TypeDefinitionParams', # 'ImplementationParams', # 'DocumentHighlightParams', 'SelectionRangeParams', 'SelectionRange', 'LinkedEditingRanges', 'CallHierarchyItem', 'CallHierarchyIncomingCallsParams', 'CallHierarchyIncomingCall', 'CallHierarchyOutgoingCall', 'SemanticTokensParams', 'SemanticTokens', 'SemanticTokensPartialResult', 'SemanticTokensDeltaParams', 'SemanticTokensEdit', 'SemanticTokensDelta', 'SemanticTokensDeltaPartialResult', 'SemanticTokensRangeParams', 'SemanticTokensWorkspaceClientCapabilities', 'UniquenessLevel', 'MonikerKind', 'Moniker', 'ShowDocumentParams', 'ShowDocumentResult', 'CreateFilesParams', 'FileCreate', 'RenameFilesParams', 'FileRename', 'DeleteFilesParams', 'FileDelete', 'ALS_Subprogram_And_References', 'ALS_ShowDependenciesKind', 'ALS_Unit_Description', 'ALS_ShowDependenciesParams', 'ALS_Source_Dir_Description', # 'ALS_Debug_Kinds', # 'ALSDebugParams', 'Search_Kind', # 'ALS_Check_Syntax_Params', # 'ALS_Check_Syntax_Result', } spec_header = """-- Automatically generated, do not edit. with Ada.Streams; with LSP.Messages; package LSP.Message_IO is """ body_header = """-- Automatically generated, do not edit. with Interfaces; with VSS.Strings.Conversions; with LSP.JSON_Streams; with LSP.Messages; use LSP.Messages; with LSP.Types; use LSP.Types; package body LSP.Message_IO is pragma Style_Checks ("M175"); use type Interfaces.Integer_64; use type VSS.Strings.Virtual_String; """ file_footer = """ end LSP.Message_IO; """ io_spec = """ procedure {kind}_{type} (S : access Ada.Streams.Root_Stream_Type'Class; V : {out}LSP.Messages.{type}); """ io_header = """ procedure {kind}_{type} (S : access Ada.Streams.Root_Stream_Type'Class; V : {out}{type}) is {unref} JS : LSP.JSON_Streams.JSON_Stream'Class renames LSP.JSON_Streams.JSON_Stream'Class (S.all); """ io_footer = """\ end {kind}_{type}; """ write_component = { "VSS.Strings.Virtual_String": """\ JS.Key ("{key}"); LSP.Types.Write_String (S, V.{name}); """, "VSS.String_Vectors.Virtual_String_Vector": """\ JS.Key ("{key}"); LSP.Types.Write_String_Vector (S, V.{name}); """, "LSP_String": """\ JS.Key ("{key}"); LSP.Types.Write (S, V.{name}); """, "DocumentUri": """\ JS.Key ("{key}"); LSP.Types.Write_LSP_URI (S, V.{name}); """, "Boolean": """\ {kind}_Boolean (JS, "{key}", V.{name}); """, "UTF_16_Index": """\ JS.Key ("{key}"); LSP.Types.Write_UTF16_Code_Unit_Count (JS, V.{name}); """, "": """\ JS.Key ("{key}"); {type}'{kind} (S, V.{name}); """ } read_component = { "VSS.Strings.Virtual_String": """if Key = "{key}" then LSP.Types.Read_String (S, V.{name}); els""", "VSS.String_Vectors.Virtual_String_Vector": """if Key = "{key}" then LSP.Types.Read_String_Vector (S, V.{name}); els""", "LSP_String": """if Key = "{key}" then LSP.Types.Read (S, V.{name}); els""", "DocumentUri": """if Key = "{key}" then LSP.Types.Read_LSP_URI (S, V.{name}); els""", "Boolean": """if Key = "{key}" then LSP.Types.Read_Boolean (JS, V.{name}); els""", "UTF_16_Index": """if Key = "{key}" then LSP.Types.Read_UTF16_Code_Unit_Count (JS, V.{name}); els""", "": """if Key = "{key}" then {type}'Read (S, V.{name}); els""" } io_component = {'Read': read_component, 'Write': write_component} io_pos_enum = { 'Read': """\ V := {type}'Val (JS.R.Number_Value.Integer_Value - {offset}); JS.R.Read_Next; """, 'Write': """\ JS.Write_Integer (({type}'Pos (V)) + {offset}); """ } io_string_enum_header = { 'Read': """ Text : constant Standard.String := VSS.Strings.Conversions.To_UTF_8_String (JS.R.String_Value); begin JS.R.Read_Next; """, 'Write': """ function To_Virtual_String (Value : {type}) return VSS.Strings.Virtual_String; function To_Virtual_String (Value : {type}) return VSS.Strings.Virtual_String is begin case Value is """ } io_string_enum_case = { 'Read': """if Text = "{key}" then V := {name}; els""", 'Write': """\ when {name} => return "{key}"; """ } io_string_enum_footer = { 'Read': """e V := {type}'First; end if; """, 'Write': """\ end case; end To_Virtual_String; begin JS.Write_String (To_Virtual_String (V)); """ } read_prolog = { 'Read': """ begin pragma Assert (JS.R.Is_Start_Object); JS.R.Read_Next; while not JS.R.Is_End_Object loop pragma Assert (JS.R.Is_Key_Name); declare Key : constant VSS.Strings.Virtual_String := JS.R.Key_Name; begin JS.R.Read_Next; """, 'Write': """ begin JS.Start_Object; """ } read_epilog = { 'Read': """e JS.Skip_Value; end if; end; end loop; JS.R.Read_Next; """, 'Write': """ JS.End_Object; """ } # The list of enumeration type represented as strings enum_as_string = [ 'AlsReferenceKind', 'AlsDisplayMethodAncestryOnNavigationPolicy', 'CodeActionKind', 'FileResourceChangeKind', 'ResourceOperationKind', 'FailureHandlingKind', 'MarkupKind', 'TokenFormat', 'SemanticTokenTypes', 'SemanticTokenModifiers', 'UniquenessLevel', 'MonikerKind', 'FileOperationPatternKind', 'TraceValue'] # The map to substitute words reserved in Ada: reserver_named = \ { "abortapplying": "abort", "access_ref": "access", "first": "start", "last": "end", "loc": "location", # for ALS_Subprogram_And_References "span": "range", "a_type": "type", "simple": "reference", # For AlsReferenceKind "write": "write", "static_call": "call", "dispatching_call": "dispatching call", "overriding_decl": "overriding", "parent": "parent", "child": "child", "empty": "", # For CodeActionKind "quickfix": "quickfix", "refactor": "refactor", "refactorextract": "refactor.extract", "refactorinline": "refactor.inline", "refactorrewrite": "refactor.rewrite", "source": "source", "sourceorganizeimports": "source.organizeImports", "messages_trace": "messages", # for TraceValue "diff": "delta", # for SemanticTokens "an_abstract": "abstract", # for SemanticTokenTypes "an_interface": "interface", "a_function": "function", "a_string": "string", } def get_key(field): lower = field.lower() if lower in reserver_named: return reserver_named[lower] else: return field def write_format(type, kind): if type in io_component[kind]: return io_component[kind][type] else: return io_component[kind][""] def filter(x): return isinstance(x, lal.TypeDecl) \ and not isinstance(x, lal.AnonymousTypeDecl) \ and x.p_defining_name.token_start.text in types_to_print def print_spec(file, node): name = node.p_defining_name.token_start.text print(name) file.write(io_spec.format(type=name, kind='Read', out='out ').encode(encoding='utf-8')) file.write(io_spec.format(type=name, kind='Write', out='').encode(encoding='utf-8')) def get_components(node): if isinstance(node, lal.DerivedTypeDef): parent = node.f_subtype_indication.p_designated_type_decl result = get_components(parent.f_type_def) else: result = [] result += list(node.finditer(lal.ComponentDecl)) return result def print_components(file, kind, node, no_components): file.write(read_prolog[kind].encode(encoding='utf-8')) if kind == 'Read' and no_components: # Write something compilable file.write("""if Key = "" then null; els""".encode(encoding='utf-8')) for x in get_components(node): name = x.p_defining_name.token_start.text tp = x.f_component_def.f_type_expr.f_name.text txt = write_format(tp, kind).format(key=get_key(name), kind=kind, name=name, type=tp) file.write(txt.encode(encoding='utf-8')) file.write(read_epilog[kind].encode(encoding='utf-8')) def print_enums(file, kind, type, node): if type not in enum_as_string: offset = 0 if type == 'TextDocumentSyncKind' else 1 file.write(' begin\n'.encode(encoding='utf-8')) txt = io_pos_enum[kind].format(type=type, offset=offset) else: txt = io_string_enum_header[kind].format(type=type) for x in node.finditer(lal.EnumLiteralDecl): name = x.p_defining_name.token_start.text txt += io_string_enum_case[kind].format(name=name, key=get_key(name)) txt += io_string_enum_footer[kind].format(type=type) file.write(txt.encode(encoding='utf-8')) def print_body(file, node): name = node.p_defining_name.token_start.text unref = ' pragma Unreferenced (V);\n\n' if \ len(list(node.finditer(lal.NullRecordDef))) else '' def print_decls_and_statements(kind): file.write(io_header.format(type=name, kind=kind, out='' if kind == 'Write' else 'out ', unref=unref).encode(encoding='utf-8')) if isinstance(node.f_type_def, lal.EnumTypeDef): print_enums(file, kind, name, node.f_type_def) else: print_components(file, kind, node.f_type_def, unref) file.write(io_footer.format(type=node.p_defining_name.token_start.text, kind=kind).encode(encoding='utf-8')) print_decls_and_statements('Read') print_decls_and_statements('Write') def print_io(): up = lal.UnitProvider.for_project("gnat/lsp.gpr") ctx = lal.AnalysisContext(unit_provider=up) unit = ctx.get_from_file("source/protocol/lsp-messages.ads") ads = open("source/protocol/generated/lsp-message_io.ads", 'wb') ads.write(spec_header.encode(encoding='utf-8')) adb = open("source/protocol/generated/lsp-message_io.adb", 'wb') adb.write(body_header.encode(encoding='utf-8')) for x in unit.root.finditer(filter): print_spec(ads, x) print_body(adb, x) ads.write(file_footer.encode(encoding='utf-8')) adb.write(file_footer.encode(encoding='utf-8')) if __name__ == '__main__': print_io()