jaclang 0.0.5__py3-none-any.whl → 0.0.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of jaclang might be problematic. Click here for more details.
- jaclang/__init__.py +2 -1
- jaclang/cli/__jac_gen__/__init__.py +0 -0
- jaclang/cli/__jac_gen__/cli.py +175 -0
- jaclang/cli/__jac_gen__/cmds.py +132 -0
- jaclang/cli/cli.jac +2 -2
- jaclang/cli/cmds.jac +8 -2
- jaclang/cli/impl/__jac_gen__/__init__.py +0 -0
- jaclang/cli/impl/__jac_gen__/cli_impl.py +16 -0
- jaclang/cli/impl/__jac_gen__/cmds_impl.py +26 -0
- jaclang/cli/impl/cli_impl.jac +25 -8
- jaclang/cli/impl/cmds_impl.jac +35 -6
- jaclang/core/__jac_gen__/__init__.py +0 -0
- jaclang/core/__jac_gen__/primitives.py +567 -0
- jaclang/core/impl/__jac_gen__/__init__.py +0 -0
- jaclang/core/impl/__jac_gen__/arch_impl.py +24 -0
- jaclang/core/impl/__jac_gen__/element_impl.py +26 -0
- jaclang/core/impl/__jac_gen__/exec_ctx_impl.py +12 -0
- jaclang/core/impl/__jac_gen__/memory_impl.py +14 -0
- jaclang/core/impl/element_impl.jac +3 -3
- jaclang/core/impl/exec_ctx_impl.jac +3 -6
- jaclang/core/primitives.jac +4 -3
- jaclang/jac/absyntree.py +555 -180
- jaclang/jac/constant.py +6 -0
- jaclang/jac/importer.py +34 -56
- jaclang/jac/langserve.py +26 -0
- jaclang/jac/lexer.py +35 -3
- jaclang/jac/parser.py +146 -115
- jaclang/jac/passes/blue/__init__.py +8 -3
- jaclang/jac/passes/blue/ast_build_pass.py +454 -305
- jaclang/jac/passes/blue/blue_pygen_pass.py +112 -74
- jaclang/jac/passes/blue/decl_def_match_pass.py +49 -277
- jaclang/jac/passes/blue/import_pass.py +1 -1
- jaclang/jac/passes/blue/pyout_pass.py +74 -0
- jaclang/jac/passes/blue/semantic_check_pass.py +37 -0
- jaclang/jac/passes/blue/sym_tab_build_pass.py +1045 -0
- jaclang/jac/passes/blue/tests/test_ast_build_pass.py +2 -2
- jaclang/jac/passes/blue/tests/test_blue_pygen_pass.py +9 -28
- jaclang/jac/passes/blue/tests/test_decl_def_match_pass.py +13 -22
- jaclang/jac/passes/blue/tests/test_sym_tab_build_pass.py +22 -0
- jaclang/jac/passes/ir_pass.py +8 -6
- jaclang/jac/passes/purple/__jac_gen__/__init__.py +0 -0
- jaclang/jac/passes/purple/__jac_gen__/analyze_pass.py +37 -0
- jaclang/jac/passes/purple/__jac_gen__/purple_pygen_pass.py +305 -0
- jaclang/jac/passes/purple/impl/__jac_gen__/__init__.py +0 -0
- jaclang/jac/passes/purple/impl/__jac_gen__/purple_pygen_pass_impl.py +23 -0
- jaclang/jac/passes/purple/impl/purple_pygen_pass_impl.jac +2 -5
- jaclang/jac/symtable.py +154 -0
- jaclang/jac/tests/fixtures/__jac_gen__/__init__.py +0 -0
- jaclang/jac/tests/fixtures/__jac_gen__/hello_world.py +16 -0
- jaclang/jac/tests/fixtures/fam.jac +7 -8
- jaclang/jac/tests/fixtures/mod_doc_test.jac +1 -0
- jaclang/jac/tests/test_parser.py +8 -0
- jaclang/jac/transform.py +41 -14
- jaclang/jac/transpiler.py +18 -9
- jaclang/utils/fstring_parser.py +2 -2
- jaclang/utils/helpers.py +41 -0
- jaclang/utils/lang_tools.py +12 -2
- jaclang/utils/test.py +41 -0
- jaclang/vendor/__init__.py +1 -0
- jaclang/vendor/pygls/__init__.py +25 -0
- jaclang/vendor/pygls/capabilities.py +502 -0
- jaclang/vendor/pygls/client.py +176 -0
- jaclang/vendor/pygls/constants.py +26 -0
- jaclang/vendor/pygls/exceptions.py +220 -0
- jaclang/vendor/pygls/feature_manager.py +241 -0
- jaclang/vendor/pygls/lsp/__init__.py +139 -0
- jaclang/vendor/pygls/lsp/client.py +2224 -0
- jaclang/vendor/pygls/lsprotocol/__init__.py +2 -0
- jaclang/vendor/pygls/lsprotocol/_hooks.py +1233 -0
- jaclang/vendor/pygls/lsprotocol/converters.py +17 -0
- jaclang/vendor/pygls/lsprotocol/types.py +12820 -0
- jaclang/vendor/pygls/lsprotocol/validators.py +47 -0
- jaclang/vendor/pygls/progress.py +79 -0
- jaclang/vendor/pygls/protocol.py +1184 -0
- jaclang/vendor/pygls/server.py +620 -0
- jaclang/vendor/pygls/uris.py +184 -0
- jaclang/vendor/pygls/workspace/__init__.py +81 -0
- jaclang/vendor/pygls/workspace/position.py +204 -0
- jaclang/vendor/pygls/workspace/text_document.py +234 -0
- jaclang/vendor/pygls/workspace/workspace.py +311 -0
- {jaclang-0.0.5.dist-info → jaclang-0.0.8.dist-info}/METADATA +1 -1
- jaclang-0.0.8.dist-info/RECORD +118 -0
- jaclang/core/jaclang.jac +0 -62
- jaclang/jac/passes/blue/tests/test_type_analyze_pass.py +0 -53
- jaclang/jac/passes/blue/type_analyze_pass.py +0 -728
- jaclang/jac/sym_table.py +0 -127
- jaclang-0.0.5.dist-info/RECORD +0 -73
- /jaclang/{utils → vendor}/sly/__init__.py +0 -0
- /jaclang/{utils → vendor}/sly/docparse.py +0 -0
- /jaclang/{utils → vendor}/sly/lex.py +0 -0
- /jaclang/{utils → vendor}/sly/yacc.py +0 -0
- {jaclang-0.0.5.dist-info → jaclang-0.0.8.dist-info}/WHEEL +0 -0
- {jaclang-0.0.5.dist-info → jaclang-0.0.8.dist-info}/entry_points.txt +0 -0
- {jaclang-0.0.5.dist-info → jaclang-0.0.8.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
############################################################################
|
|
2
|
+
# Original work Copyright 2018 Palantir Technologies, Inc. #
|
|
3
|
+
# Original work licensed under the MIT License. #
|
|
4
|
+
# See ThirdPartyNotices.txt in the project root for license information. #
|
|
5
|
+
# All modifications Copyright (c) Open Law Library. All rights reserved. #
|
|
6
|
+
# #
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License") #
|
|
8
|
+
# you may not use this file except in compliance with the License. #
|
|
9
|
+
# You may obtain a copy of the License at #
|
|
10
|
+
# #
|
|
11
|
+
# http: // www.apache.org/licenses/LICENSE-2.0 #
|
|
12
|
+
# #
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software #
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS, #
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
|
|
16
|
+
# See the License for the specific language governing permissions and #
|
|
17
|
+
# limitations under the License. #
|
|
18
|
+
############################################################################
|
|
19
|
+
import traceback
|
|
20
|
+
from typing import Set
|
|
21
|
+
from typing import Type
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class JsonRpcException(Exception):
|
|
25
|
+
"""A class used as a base class for json rpc exceptions."""
|
|
26
|
+
|
|
27
|
+
def __init__(self, message=None, code=None, data=None):
|
|
28
|
+
message = message or getattr(self.__class__, "MESSAGE")
|
|
29
|
+
super().__init__(message)
|
|
30
|
+
self.message = message
|
|
31
|
+
self.code = code or getattr(self.__class__, "CODE")
|
|
32
|
+
self.data = data
|
|
33
|
+
|
|
34
|
+
def __eq__(self, other):
|
|
35
|
+
return (
|
|
36
|
+
isinstance(other, self.__class__)
|
|
37
|
+
and self.code == other.code
|
|
38
|
+
and self.message == other.message
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def __hash__(self):
|
|
42
|
+
return hash((self.code, self.message))
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def from_error(error):
|
|
46
|
+
for exc_class in _EXCEPTIONS:
|
|
47
|
+
if exc_class.supports_code(error.code):
|
|
48
|
+
return exc_class(
|
|
49
|
+
code=error.code, message=error.message, data=error.data
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
return JsonRpcException(code=error.code, message=error.message, data=error.data)
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def supports_code(cls, code):
|
|
56
|
+
# Defaults to UnknownErrorCode
|
|
57
|
+
return getattr(cls, "CODE", -32001) == code
|
|
58
|
+
|
|
59
|
+
def to_dict(self):
|
|
60
|
+
exception_dict = {
|
|
61
|
+
"code": self.code,
|
|
62
|
+
"message": self.message,
|
|
63
|
+
}
|
|
64
|
+
if self.data is not None:
|
|
65
|
+
exception_dict["data"] = str(self.data)
|
|
66
|
+
return exception_dict
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class JsonRpcInternalError(JsonRpcException):
|
|
70
|
+
CODE = -32603
|
|
71
|
+
MESSAGE = "Internal Error"
|
|
72
|
+
|
|
73
|
+
@classmethod
|
|
74
|
+
def of(cls, exc_info):
|
|
75
|
+
exc_type, exc_value, exc_tb = exc_info
|
|
76
|
+
return cls(
|
|
77
|
+
message="".join(
|
|
78
|
+
traceback.format_exception_only(exc_type, exc_value)
|
|
79
|
+
).strip(),
|
|
80
|
+
data={"traceback": traceback.format_tb(exc_tb)},
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class JsonRpcInvalidParams(JsonRpcException):
|
|
85
|
+
CODE = -32602
|
|
86
|
+
MESSAGE = "Invalid Params"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class JsonRpcInvalidRequest(JsonRpcException):
|
|
90
|
+
CODE = -32600
|
|
91
|
+
MESSAGE = "Invalid Request"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class JsonRpcMethodNotFound(JsonRpcException):
|
|
95
|
+
CODE = -32601
|
|
96
|
+
MESSAGE = "Method Not Found"
|
|
97
|
+
|
|
98
|
+
@classmethod
|
|
99
|
+
def of(cls, method):
|
|
100
|
+
return cls(message=cls.MESSAGE + ": " + method)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class JsonRpcParseError(JsonRpcException):
|
|
104
|
+
CODE = -32700
|
|
105
|
+
MESSAGE = "Parse Error"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class JsonRpcRequestCancelled(JsonRpcException):
|
|
109
|
+
CODE = -32800
|
|
110
|
+
MESSAGE = "Request Cancelled"
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class JsonRpcContentModified(JsonRpcException):
|
|
114
|
+
CODE = -32801
|
|
115
|
+
MESSAGE = "Content Modified"
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class JsonRpcServerNotInitialized(JsonRpcException):
|
|
119
|
+
CODE = -32002
|
|
120
|
+
MESSAGE = "ServerNotInitialized"
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class JsonRpcUnknownErrorCode(JsonRpcException):
|
|
124
|
+
CODE = -32001
|
|
125
|
+
MESSAGE = "UnknownErrorCode"
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class JsonRpcReservedErrorRangeStart(JsonRpcException):
|
|
129
|
+
CODE = -32099
|
|
130
|
+
MESSAGE = "jsonrpcReservedErrorRangeStart"
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class JsonRpcReservedErrorRangeEnd(JsonRpcException):
|
|
134
|
+
CODE = -32000
|
|
135
|
+
MESSAGE = "jsonrpcReservedErrorRangeEnd"
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class LspReservedErrorRangeStart(JsonRpcException):
|
|
139
|
+
CODE = -32899
|
|
140
|
+
MESSAGE = "lspReservedErrorRangeStart"
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class LspReservedErrorRangeEnd(JsonRpcException):
|
|
144
|
+
CODE = -32800
|
|
145
|
+
MESSAGE = "lspReservedErrorRangeEnd"
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class JsonRpcServerError(JsonRpcException):
|
|
149
|
+
def __init__(self, message, code, data=None):
|
|
150
|
+
if not _is_server_error_code(code):
|
|
151
|
+
raise ValueError("Error code should be in range -32099 - -32000")
|
|
152
|
+
super().__init__(message=message, code=code, data=data)
|
|
153
|
+
|
|
154
|
+
@classmethod
|
|
155
|
+
def supports_code(cls, code):
|
|
156
|
+
return _is_server_error_code(code)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _is_server_error_code(code):
|
|
160
|
+
return -32099 <= code <= -32000
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
_EXCEPTIONS: Set[Type[JsonRpcException]] = {
|
|
164
|
+
JsonRpcInternalError,
|
|
165
|
+
JsonRpcInvalidParams,
|
|
166
|
+
JsonRpcInvalidRequest,
|
|
167
|
+
JsonRpcMethodNotFound,
|
|
168
|
+
JsonRpcParseError,
|
|
169
|
+
JsonRpcRequestCancelled,
|
|
170
|
+
JsonRpcServerError,
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class PyglsError(Exception):
|
|
175
|
+
pass
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class CommandAlreadyRegisteredError(PyglsError):
|
|
179
|
+
def __init__(self, command_name):
|
|
180
|
+
self.command_name = command_name
|
|
181
|
+
|
|
182
|
+
def __repr__(self):
|
|
183
|
+
return f'Command "{self.command_name}" is already registered.'
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class FeatureAlreadyRegisteredError(PyglsError):
|
|
187
|
+
def __init__(self, feature_name):
|
|
188
|
+
self.feature_name = feature_name
|
|
189
|
+
|
|
190
|
+
def __repr__(self):
|
|
191
|
+
return f'Feature "{self.feature_name}" is already registered.'
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class FeatureRequestError(PyglsError):
|
|
195
|
+
pass
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class FeatureNotificationError(PyglsError):
|
|
199
|
+
pass
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class MethodTypeNotRegisteredError(PyglsError):
|
|
203
|
+
def __init__(self, name):
|
|
204
|
+
self.name = name
|
|
205
|
+
|
|
206
|
+
def __repr__(self):
|
|
207
|
+
return f'"{self.name}" is not added to `pygls.lsp.LSP_METHODS_MAP`.'
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class ThreadDecoratorError(PyglsError):
|
|
211
|
+
pass
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class ValidationError(PyglsError):
|
|
215
|
+
def __init__(self, errors=None):
|
|
216
|
+
self.errors = errors or []
|
|
217
|
+
|
|
218
|
+
def __repr__(self):
|
|
219
|
+
opt_errs = "\n-".join([e for e in self.errors])
|
|
220
|
+
return f"Missing options: {opt_errs}"
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
############################################################################
|
|
2
|
+
# Copyright(c) Open Law Library. All rights reserved. #
|
|
3
|
+
# See ThirdPartyNotices.txt in the project root for additional notices. #
|
|
4
|
+
# #
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License") #
|
|
6
|
+
# you may not use this file except in compliance with the License. #
|
|
7
|
+
# You may obtain a copy of the License at #
|
|
8
|
+
# #
|
|
9
|
+
# http: // www.apache.org/licenses/LICENSE-2.0 #
|
|
10
|
+
# #
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software #
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS, #
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
|
|
14
|
+
# See the License for the specific language governing permissions and #
|
|
15
|
+
# limitations under the License. #
|
|
16
|
+
############################################################################
|
|
17
|
+
import asyncio
|
|
18
|
+
import functools
|
|
19
|
+
import inspect
|
|
20
|
+
import itertools
|
|
21
|
+
import logging
|
|
22
|
+
from typing import Any, Callable, Dict, Optional, get_type_hints
|
|
23
|
+
|
|
24
|
+
from jaclang.vendor.pygls.constants import (
|
|
25
|
+
ATTR_COMMAND_TYPE,
|
|
26
|
+
ATTR_EXECUTE_IN_THREAD,
|
|
27
|
+
ATTR_FEATURE_TYPE,
|
|
28
|
+
ATTR_REGISTERED_NAME,
|
|
29
|
+
ATTR_REGISTERED_TYPE,
|
|
30
|
+
PARAM_LS,
|
|
31
|
+
)
|
|
32
|
+
from jaclang.vendor.pygls.exceptions import (
|
|
33
|
+
CommandAlreadyRegisteredError,
|
|
34
|
+
FeatureAlreadyRegisteredError,
|
|
35
|
+
ThreadDecoratorError,
|
|
36
|
+
ValidationError,
|
|
37
|
+
)
|
|
38
|
+
from jaclang.vendor.pygls.lsp import get_method_options_type, is_instance
|
|
39
|
+
|
|
40
|
+
logger = logging.getLogger(__name__)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def assign_help_attrs(f, reg_name, reg_type):
|
|
44
|
+
setattr(f, ATTR_REGISTERED_NAME, reg_name)
|
|
45
|
+
setattr(f, ATTR_REGISTERED_TYPE, reg_type)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def assign_thread_attr(f):
|
|
49
|
+
setattr(f, ATTR_EXECUTE_IN_THREAD, True)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_help_attrs(f):
|
|
53
|
+
return getattr(f, ATTR_REGISTERED_NAME, None), getattr(
|
|
54
|
+
f, ATTR_REGISTERED_TYPE, None
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def has_ls_param_or_annotation(f, annotation):
|
|
59
|
+
"""Returns true if callable has first parameter named `ls` or type of
|
|
60
|
+
annotation"""
|
|
61
|
+
try:
|
|
62
|
+
sig = inspect.signature(f)
|
|
63
|
+
first_p = next(itertools.islice(sig.parameters.values(), 0, 1))
|
|
64
|
+
return first_p.name == PARAM_LS or get_type_hints(f)[first_p.name] == annotation
|
|
65
|
+
except Exception:
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def is_thread_function(f):
|
|
70
|
+
return getattr(f, ATTR_EXECUTE_IN_THREAD, False)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def wrap_with_server(f, server):
|
|
74
|
+
"""Returns a new callable/coroutine with server as first argument."""
|
|
75
|
+
if not has_ls_param_or_annotation(f, type(server)):
|
|
76
|
+
return f
|
|
77
|
+
|
|
78
|
+
if asyncio.iscoroutinefunction(f):
|
|
79
|
+
|
|
80
|
+
async def wrapped(*args, **kwargs):
|
|
81
|
+
return await f(server, *args, **kwargs)
|
|
82
|
+
|
|
83
|
+
else:
|
|
84
|
+
wrapped = functools.partial(f, server)
|
|
85
|
+
if is_thread_function(f):
|
|
86
|
+
assign_thread_attr(wrapped)
|
|
87
|
+
|
|
88
|
+
return wrapped
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class FeatureManager:
|
|
92
|
+
"""A class for managing server features.
|
|
93
|
+
|
|
94
|
+
Attributes:
|
|
95
|
+
_builtin_features(dict): Predefined set of lsp methods
|
|
96
|
+
_feature_options(dict): Registered feature's options
|
|
97
|
+
_features(dict): Registered features
|
|
98
|
+
_commands(dict): Registered commands
|
|
99
|
+
server(LanguageServer): Reference to the language server
|
|
100
|
+
If passed, server will be passed to registered
|
|
101
|
+
features/commands with first parameter:
|
|
102
|
+
1. ls - parameter naming convention
|
|
103
|
+
2. name: LanguageServer - add typings
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
def __init__(self, server=None):
|
|
107
|
+
self._builtin_features = {}
|
|
108
|
+
self._feature_options = {}
|
|
109
|
+
self._features = {}
|
|
110
|
+
self._commands = {}
|
|
111
|
+
self.server = server
|
|
112
|
+
|
|
113
|
+
def add_builtin_feature(self, feature_name: str, func: Callable) -> None:
|
|
114
|
+
"""Registers builtin (predefined) feature."""
|
|
115
|
+
self._builtin_features[feature_name] = func
|
|
116
|
+
logger.info("Registered builtin feature %s", feature_name)
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def builtin_features(self) -> Dict:
|
|
120
|
+
"""Returns server builtin features."""
|
|
121
|
+
return self._builtin_features
|
|
122
|
+
|
|
123
|
+
def command(self, command_name: str) -> Callable:
|
|
124
|
+
"""Decorator used to register custom commands.
|
|
125
|
+
|
|
126
|
+
Example:
|
|
127
|
+
@ls.command('myCustomCommand')
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
def decorator(f):
|
|
131
|
+
# Validate
|
|
132
|
+
if command_name is None or command_name.strip() == "":
|
|
133
|
+
logger.error("Missing command name.")
|
|
134
|
+
raise ValidationError("Command name is required.")
|
|
135
|
+
|
|
136
|
+
# Check if not already registered
|
|
137
|
+
if command_name in self._commands:
|
|
138
|
+
logger.error('Command "%s" is already registered.', command_name)
|
|
139
|
+
raise CommandAlreadyRegisteredError(command_name)
|
|
140
|
+
|
|
141
|
+
assign_help_attrs(f, command_name, ATTR_COMMAND_TYPE)
|
|
142
|
+
|
|
143
|
+
wrapped = wrap_with_server(f, self.server)
|
|
144
|
+
# Assign help attributes for thread decorator
|
|
145
|
+
assign_help_attrs(wrapped, command_name, ATTR_COMMAND_TYPE)
|
|
146
|
+
|
|
147
|
+
self._commands[command_name] = wrapped
|
|
148
|
+
|
|
149
|
+
logger.info('Command "%s" is successfully registered.', command_name)
|
|
150
|
+
|
|
151
|
+
return f
|
|
152
|
+
|
|
153
|
+
return decorator
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
def commands(self) -> Dict:
|
|
157
|
+
"""Returns registered custom commands."""
|
|
158
|
+
return self._commands
|
|
159
|
+
|
|
160
|
+
def feature(
|
|
161
|
+
self,
|
|
162
|
+
feature_name: str,
|
|
163
|
+
options: Optional[Any] = None,
|
|
164
|
+
) -> Callable:
|
|
165
|
+
"""Decorator used to register LSP features.
|
|
166
|
+
|
|
167
|
+
Example:
|
|
168
|
+
@ls.feature('textDocument/completion', CompletionItems(trigger_characters=['.']))
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
def decorator(f):
|
|
172
|
+
# Validate
|
|
173
|
+
if feature_name is None or feature_name.strip() == "":
|
|
174
|
+
logger.error("Missing feature name.")
|
|
175
|
+
raise ValidationError("Feature name is required.")
|
|
176
|
+
|
|
177
|
+
# Add feature if not exists
|
|
178
|
+
if feature_name in self._features:
|
|
179
|
+
logger.error('Feature "%s" is already registered.', feature_name)
|
|
180
|
+
raise FeatureAlreadyRegisteredError(feature_name)
|
|
181
|
+
|
|
182
|
+
assign_help_attrs(f, feature_name, ATTR_FEATURE_TYPE)
|
|
183
|
+
|
|
184
|
+
wrapped = wrap_with_server(f, self.server)
|
|
185
|
+
# Assign help attributes for thread decorator
|
|
186
|
+
assign_help_attrs(wrapped, feature_name, ATTR_FEATURE_TYPE)
|
|
187
|
+
|
|
188
|
+
self._features[feature_name] = wrapped
|
|
189
|
+
|
|
190
|
+
if options:
|
|
191
|
+
options_type = get_method_options_type(feature_name)
|
|
192
|
+
if options_type and not is_instance(options, options_type):
|
|
193
|
+
raise TypeError(
|
|
194
|
+
(
|
|
195
|
+
f'Options of method "{feature_name}"'
|
|
196
|
+
f" should be instance of type {options_type}"
|
|
197
|
+
)
|
|
198
|
+
)
|
|
199
|
+
self._feature_options[feature_name] = options
|
|
200
|
+
|
|
201
|
+
logger.info('Registered "%s" with options "%s"', feature_name, options)
|
|
202
|
+
|
|
203
|
+
return f
|
|
204
|
+
|
|
205
|
+
return decorator
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def feature_options(self) -> Dict:
|
|
209
|
+
"""Returns feature options for registered features."""
|
|
210
|
+
return self._feature_options
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
def features(self) -> Dict:
|
|
214
|
+
"""Returns registered features"""
|
|
215
|
+
return self._features
|
|
216
|
+
|
|
217
|
+
def thread(self) -> Callable:
|
|
218
|
+
"""Decorator that mark function to execute it in a thread."""
|
|
219
|
+
|
|
220
|
+
def decorator(f):
|
|
221
|
+
if asyncio.iscoroutinefunction(f):
|
|
222
|
+
raise ThreadDecoratorError(
|
|
223
|
+
f'Thread decorator cannot be used with async functions "{f.__name__}"'
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
# Allow any decorator order
|
|
227
|
+
try:
|
|
228
|
+
reg_name = getattr(f, ATTR_REGISTERED_NAME)
|
|
229
|
+
reg_type = getattr(f, ATTR_REGISTERED_TYPE)
|
|
230
|
+
|
|
231
|
+
if reg_type is ATTR_FEATURE_TYPE:
|
|
232
|
+
assign_thread_attr(self.features[reg_name])
|
|
233
|
+
elif reg_type is ATTR_COMMAND_TYPE:
|
|
234
|
+
assign_thread_attr(self.commands[reg_name])
|
|
235
|
+
|
|
236
|
+
except AttributeError:
|
|
237
|
+
assign_thread_attr(f)
|
|
238
|
+
|
|
239
|
+
return f
|
|
240
|
+
|
|
241
|
+
return decorator
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
############################################################################
|
|
2
|
+
# Copyright(c) Open Law Library. All rights reserved. #
|
|
3
|
+
# See ThirdPartyNotices.txt in the project root for additional notices. #
|
|
4
|
+
# #
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License") #
|
|
6
|
+
# you may not use this file except in compliance with the License. #
|
|
7
|
+
# You may obtain a copy of the License at #
|
|
8
|
+
# #
|
|
9
|
+
# http: // www.apache.org/licenses/LICENSE-2.0 #
|
|
10
|
+
# #
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software #
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS, #
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
|
|
14
|
+
# See the License for the specific language governing permissions and #
|
|
15
|
+
# limitations under the License. #
|
|
16
|
+
############################################################################
|
|
17
|
+
from typing import Any, Callable, List, Optional, Union
|
|
18
|
+
|
|
19
|
+
from jaclang.vendor.pygls.lsprotocol.types import (
|
|
20
|
+
ALL_TYPES_MAP,
|
|
21
|
+
METHOD_TO_TYPES,
|
|
22
|
+
TEXT_DOCUMENT_DID_SAVE,
|
|
23
|
+
TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,
|
|
24
|
+
TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL_DELTA,
|
|
25
|
+
TEXT_DOCUMENT_SEMANTIC_TOKENS_RANGE,
|
|
26
|
+
WORKSPACE_DID_CREATE_FILES,
|
|
27
|
+
WORKSPACE_DID_DELETE_FILES,
|
|
28
|
+
WORKSPACE_DID_RENAME_FILES,
|
|
29
|
+
WORKSPACE_WILL_CREATE_FILES,
|
|
30
|
+
WORKSPACE_WILL_DELETE_FILES,
|
|
31
|
+
WORKSPACE_WILL_RENAME_FILES,
|
|
32
|
+
FileOperationRegistrationOptions,
|
|
33
|
+
SaveOptions,
|
|
34
|
+
SemanticTokensLegend,
|
|
35
|
+
SemanticTokensRegistrationOptions,
|
|
36
|
+
ShowDocumentResult,
|
|
37
|
+
)
|
|
38
|
+
from typeguard import check_type
|
|
39
|
+
|
|
40
|
+
from jaclang.vendor.pygls.exceptions import MethodTypeNotRegisteredError
|
|
41
|
+
|
|
42
|
+
ConfigCallbackType = Callable[[List[Any]], None]
|
|
43
|
+
ShowDocumentCallbackType = Callable[[ShowDocumentResult], None]
|
|
44
|
+
|
|
45
|
+
METHOD_TO_OPTIONS = {
|
|
46
|
+
TEXT_DOCUMENT_DID_SAVE: SaveOptions,
|
|
47
|
+
TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL: Union[
|
|
48
|
+
SemanticTokensLegend, SemanticTokensRegistrationOptions
|
|
49
|
+
],
|
|
50
|
+
TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL_DELTA: Union[
|
|
51
|
+
SemanticTokensLegend, SemanticTokensRegistrationOptions
|
|
52
|
+
],
|
|
53
|
+
TEXT_DOCUMENT_SEMANTIC_TOKENS_RANGE: Union[
|
|
54
|
+
SemanticTokensLegend, SemanticTokensRegistrationOptions
|
|
55
|
+
],
|
|
56
|
+
WORKSPACE_DID_CREATE_FILES: FileOperationRegistrationOptions,
|
|
57
|
+
WORKSPACE_DID_DELETE_FILES: FileOperationRegistrationOptions,
|
|
58
|
+
WORKSPACE_DID_RENAME_FILES: FileOperationRegistrationOptions,
|
|
59
|
+
WORKSPACE_WILL_CREATE_FILES: FileOperationRegistrationOptions,
|
|
60
|
+
WORKSPACE_WILL_DELETE_FILES: FileOperationRegistrationOptions,
|
|
61
|
+
WORKSPACE_WILL_RENAME_FILES: FileOperationRegistrationOptions,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def get_method_registration_options_type(
|
|
66
|
+
method_name, lsp_methods_map=METHOD_TO_TYPES
|
|
67
|
+
) -> Optional[Any]:
|
|
68
|
+
"""The type corresponding with a method's options when dynamically registering
|
|
69
|
+
capability for it."""
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
return lsp_methods_map[method_name][3]
|
|
73
|
+
except KeyError:
|
|
74
|
+
raise MethodTypeNotRegisteredError(method_name)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def get_method_options_type(
|
|
78
|
+
method_name, lsp_options_map=METHOD_TO_OPTIONS, lsp_methods_map=METHOD_TO_TYPES
|
|
79
|
+
) -> Optional[Any]:
|
|
80
|
+
"""Return the type corresponding with a method's ``ServerCapabilities`` fields.
|
|
81
|
+
|
|
82
|
+
In the majority of cases this simply means returning the ``<MethodName>Options``
|
|
83
|
+
type, which we can easily derive from the method's
|
|
84
|
+
``<MethodName>RegistrationOptions`` type.
|
|
85
|
+
|
|
86
|
+
However, where the options are more involved (such as semantic tokens) and
|
|
87
|
+
``pygls`` does some extra work to help derive the options for the user the type
|
|
88
|
+
has to be provided via the ``lsp_options_map``
|
|
89
|
+
|
|
90
|
+
Arguments:
|
|
91
|
+
method_name:
|
|
92
|
+
The lsp method name to retrieve the options for
|
|
93
|
+
|
|
94
|
+
lsp_options_map:
|
|
95
|
+
The map used to override the default options type finding behavior
|
|
96
|
+
|
|
97
|
+
lsp_methods_map:
|
|
98
|
+
The standard map used to look up the various method types.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
options_type = lsp_options_map.get(method_name, None)
|
|
102
|
+
if options_type is not None:
|
|
103
|
+
return options_type
|
|
104
|
+
|
|
105
|
+
registration_type = get_method_registration_options_type(
|
|
106
|
+
method_name, lsp_methods_map
|
|
107
|
+
)
|
|
108
|
+
if registration_type is None:
|
|
109
|
+
return None
|
|
110
|
+
|
|
111
|
+
type_name = registration_type.__name__.replace("Registration", "")
|
|
112
|
+
options_type = ALL_TYPES_MAP.get(type_name, None)
|
|
113
|
+
|
|
114
|
+
if options_type is None:
|
|
115
|
+
raise MethodTypeNotRegisteredError(method_name)
|
|
116
|
+
|
|
117
|
+
return options_type
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def get_method_params_type(method_name, lsp_methods_map=METHOD_TO_TYPES):
|
|
121
|
+
try:
|
|
122
|
+
return lsp_methods_map[method_name][2]
|
|
123
|
+
except KeyError:
|
|
124
|
+
raise MethodTypeNotRegisteredError(method_name)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def get_method_return_type(method_name, lsp_methods_map=METHOD_TO_TYPES):
|
|
128
|
+
try:
|
|
129
|
+
return lsp_methods_map[method_name][1]
|
|
130
|
+
except KeyError:
|
|
131
|
+
raise MethodTypeNotRegisteredError(method_name)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def is_instance(o, t):
|
|
135
|
+
try:
|
|
136
|
+
check_type(o, t)
|
|
137
|
+
return True
|
|
138
|
+
except TypeError:
|
|
139
|
+
return False
|