robotcode-robot 1.1.0__py3-none-any.whl → 1.3.0__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.
@@ -1,7 +1,7 @@
1
1
  import ast
2
2
  import functools
3
- import itertools
4
3
  import os
4
+ import re
5
5
  import token as python_token
6
6
  from collections import defaultdict
7
7
  from concurrent.futures import CancelledError
@@ -47,6 +47,7 @@ from robotcode.core.utils.logging import LoggingDescriptor
47
47
 
48
48
  from ..utils import get_robot_version
49
49
  from ..utils.ast import (
50
+ get_first_variable_token,
50
51
  is_not_variable_token,
51
52
  range_from_node,
52
53
  range_from_node_or_token,
@@ -54,13 +55,19 @@ from ..utils.ast import (
54
55
  strip_variable_token,
55
56
  tokenize_variables,
56
57
  )
57
- from ..utils.variables import contains_variable, is_scalar_assign, is_variable, search_variable, split_from_equals
58
+ from ..utils.variables import (
59
+ InvalidVariableError,
60
+ VariableMatcher,
61
+ contains_variable,
62
+ search_variable,
63
+ split_from_equals,
64
+ )
58
65
  from ..utils.visitor import Visitor
59
66
  from .entities import (
60
67
  ArgumentDefinition,
68
+ EmbeddedArgumentDefinition,
61
69
  EnvironmentVariableDefinition,
62
70
  GlobalVariableDefinition,
63
- InvalidVariableError,
64
71
  LibraryEntry,
65
72
  LocalVariableDefinition,
66
73
  TagDefinition,
@@ -68,7 +75,6 @@ from .entities import (
68
75
  TestVariableDefinition,
69
76
  VariableDefinition,
70
77
  VariableDefinitionType,
71
- VariableMatcher,
72
78
  VariableNotFoundDefinition,
73
79
  )
74
80
  from .errors import DIAGNOSTICS_SOURCE_NAME, Error
@@ -186,19 +192,19 @@ class NamespaceAnalyzer(Visitor):
186
192
  if name_token is None:
187
193
  return
188
194
 
189
- name = name_token.value
190
-
191
- if name is not None:
192
- match = search_variable(name, ignore_errors=True)
193
- if not match.is_assign(allow_assign_mark=True):
195
+ if name_token.value is not None:
196
+ matcher = search_variable(
197
+ name_token.value[:-1].rstrip() if name_token.value.endswith("=") else name_token.value,
198
+ parse_type=True,
199
+ ignore_errors=True,
200
+ )
201
+ if not matcher.is_assign(allow_assign_mark=True, allow_nested=True) or matcher.name is None:
194
202
  return
195
203
 
196
- if name.endswith("="):
197
- name = name[:-1].rstrip()
204
+ name = matcher.name
205
+
206
+ stripped_name_token = strip_variable_token(name_token, matcher=matcher, parse_type=True)
198
207
 
199
- stripped_name_token = strip_variable_token(
200
- Token(name_token.type, name, name_token.lineno, name_token.col_offset, name_token.error)
201
- )
202
208
  r = range_from_token(stripped_name_token)
203
209
 
204
210
  existing_var = self._find_variable(name)
@@ -216,14 +222,15 @@ class NamespaceAnalyzer(Visitor):
216
222
  var_def = VariableDefinition(
217
223
  name=name,
218
224
  name_token=stripped_name_token,
219
- line_no=node.lineno,
220
- col_offset=node.col_offset,
221
- end_line_no=node.lineno,
222
- end_col_offset=node.end_col_offset,
225
+ line_no=stripped_name_token.lineno,
226
+ col_offset=stripped_name_token.col_offset,
227
+ end_line_no=stripped_name_token.lineno,
228
+ end_col_offset=stripped_name_token.end_col_offset,
223
229
  source=self._namespace.source,
224
230
  has_value=has_value,
225
231
  resolvable=True,
226
232
  value=value,
233
+ value_type=matcher.type,
227
234
  )
228
235
 
229
236
  add_to_references = True
@@ -317,26 +324,25 @@ class NamespaceAnalyzer(Visitor):
317
324
 
318
325
  if get_robot_version() >= (7, 0):
319
326
 
320
- def visit_Var(self, node: Statement) -> None: # noqa: N802
327
+ def visit_Var(self, node: Var) -> None: # noqa: N802
321
328
  self._analyze_statement_variables(node)
322
329
 
323
- variable = node.get_token(Token.VARIABLE)
324
- if variable is None:
330
+ name_token = node.get_token(Token.VARIABLE)
331
+ if name_token is None:
325
332
  return
326
333
 
327
334
  try:
328
- var_name = variable.value
329
- if var_name.endswith("="):
330
- var_name = var_name[:-1].rstrip()
331
-
332
- if not is_variable(var_name):
335
+ matcher = search_variable(
336
+ name_token.value[:-1].rstrip() if name_token.value.endswith("=") else name_token.value,
337
+ parse_type=True,
338
+ ignore_errors=True,
339
+ )
340
+ if not matcher.is_assign(allow_assign_mark=True) or matcher.name is None:
333
341
  return
334
342
 
335
- stripped_variable = strip_variable_token(
336
- Token(variable.type, var_name, variable.lineno, variable.col_offset, variable.error)
337
- )
343
+ stripped_name_token = strip_variable_token(name_token, matcher=matcher, parse_type=True)
338
344
 
339
- scope = cast(Var, node).scope
345
+ scope = node.scope
340
346
  if scope:
341
347
  scope = scope.upper()
342
348
 
@@ -350,13 +356,14 @@ class NamespaceAnalyzer(Visitor):
350
356
  var_type = LocalVariableDefinition
351
357
 
352
358
  var = var_type(
353
- name=var_name,
354
- name_token=strip_variable_token(stripped_variable),
355
- line_no=stripped_variable.lineno,
356
- col_offset=stripped_variable.col_offset,
357
- end_line_no=stripped_variable.lineno,
358
- end_col_offset=stripped_variable.end_col_offset,
359
+ name=matcher.name,
360
+ name_token=strip_variable_token(stripped_name_token),
361
+ line_no=stripped_name_token.lineno,
362
+ col_offset=stripped_name_token.col_offset,
363
+ end_line_no=stripped_name_token.lineno,
364
+ end_col_offset=stripped_name_token.end_col_offset,
359
365
  source=self._namespace.source,
366
+ value_type=matcher.type,
360
367
  )
361
368
 
362
369
  if var.matcher not in self._variables:
@@ -366,7 +373,7 @@ class NamespaceAnalyzer(Visitor):
366
373
  existing_var = self._variables[var.matcher]
367
374
 
368
375
  location = Location(
369
- self._namespace.document_uri, range_from_token(strip_variable_token(stripped_variable))
376
+ self._namespace.document_uri, range_from_token(strip_variable_token(stripped_name_token))
370
377
  )
371
378
  self._variable_references[existing_var].add(location)
372
379
  if existing_var in self._overridden_variables:
@@ -413,7 +420,7 @@ class NamespaceAnalyzer(Visitor):
413
420
  self, token: Token, severity: DiagnosticSeverity = DiagnosticSeverity.ERROR
414
421
  ) -> None:
415
422
  for var_token, var in self._iter_expression_variables_from_token(token):
416
- self._handle_find_variable_result(token, var_token, var, severity)
423
+ self._handle_find_variable_result(var_token, var, severity)
417
424
 
418
425
  def _append_error_from_node(
419
426
  self,
@@ -479,11 +486,10 @@ class NamespaceAnalyzer(Visitor):
479
486
 
480
487
  def _analyze_token_variables(self, token: Token, severity: DiagnosticSeverity = DiagnosticSeverity.ERROR) -> None:
481
488
  for var_token, var in self._iter_variables_from_token(token):
482
- self._handle_find_variable_result(token, var_token, var, severity)
489
+ self._handle_find_variable_result(var_token, var, severity)
483
490
 
484
491
  def _handle_find_variable_result(
485
492
  self,
486
- token: Token,
487
493
  var_token: Token,
488
494
  var: VariableDefinition,
489
495
  severity: DiagnosticSeverity = DiagnosticSeverity.ERROR,
@@ -664,6 +670,9 @@ class NamespaceAnalyzer(Visitor):
664
670
  else:
665
671
  self._keyword_references[result].add(Location(self._namespace.document_uri, kw_range))
666
672
 
673
+ if result.is_embedded:
674
+ self._analyze_token_variables(keyword_token)
675
+
667
676
  if result.errors:
668
677
  self._append_diagnostics(
669
678
  range=kw_range,
@@ -1016,7 +1025,6 @@ class NamespaceAnalyzer(Visitor):
1016
1025
  )
1017
1026
  return
1018
1027
 
1019
- self._analyze_token_variables(keyword_token)
1020
1028
  self._analyze_statement_variables(node)
1021
1029
 
1022
1030
  self._analyze_keyword_call(
@@ -1129,6 +1137,8 @@ class NamespaceAnalyzer(Visitor):
1129
1137
  self._current_testcase_or_keyword_name = None
1130
1138
  self._current_keyword_doc = None
1131
1139
 
1140
+ EMBEDDED_ARGUMENTS_MATCHER = re.compile("([^:]+): ([^:]+)(:(.*))?")
1141
+
1132
1142
  def visit_KeywordName(self, node: KeywordName) -> None: # noqa: N802
1133
1143
  name_token = node.get_token(Token.KEYWORD_NAME)
1134
1144
 
@@ -1138,14 +1148,28 @@ class NamespaceAnalyzer(Visitor):
1138
1148
  tokenize_variables(name_token, identifiers="$", ignore_errors=True),
1139
1149
  ):
1140
1150
  if variable_token.value:
1141
- match = search_variable(variable_token.value, "$", ignore_errors=True)
1142
- if match.base is None:
1151
+ matcher = search_variable(variable_token.value, "$", ignore_errors=True)
1152
+ if matcher.base is None:
1143
1153
  continue
1144
- name = match.base.split(":", 1)[0]
1145
- full_name = f"{match.identifier}{{{name}}}"
1154
+ if ":" not in matcher.base:
1155
+ name = matcher.base
1156
+ pattern = None
1157
+ type = None
1158
+ elif get_robot_version() >= (7, 3):
1159
+ re_match = self.EMBEDDED_ARGUMENTS_MATCHER.fullmatch(matcher.base)
1160
+ if re_match:
1161
+ name, type, _, pattern = re_match.groups()
1162
+ else:
1163
+ name, pattern = matcher.base.split(":", 1)
1164
+ type = None
1165
+ else:
1166
+ name, pattern = matcher.base.split(":", 1)
1167
+ type = None
1168
+
1169
+ full_name = f"{matcher.identifier}{{{name}}}"
1146
1170
  var_token = strip_variable_token(variable_token)
1147
1171
  var_token.value = name
1148
- arg_def = ArgumentDefinition(
1172
+ arg_def = EmbeddedArgumentDefinition(
1149
1173
  name=full_name,
1150
1174
  name_token=var_token,
1151
1175
  line_no=variable_token.lineno,
@@ -1154,32 +1178,19 @@ class NamespaceAnalyzer(Visitor):
1154
1178
  end_col_offset=variable_token.end_col_offset,
1155
1179
  source=self._namespace.source,
1156
1180
  keyword_doc=self._current_keyword_doc,
1181
+ value_type=type,
1182
+ pattern=pattern,
1157
1183
  )
1158
1184
 
1159
1185
  self._variables[arg_def.matcher] = arg_def
1160
1186
  self._variable_references[arg_def] = set()
1161
1187
 
1162
- def _get_variable_token(self, token: Token) -> Optional[Token]:
1163
- return next(
1164
- (
1165
- v
1166
- for v in itertools.dropwhile(
1167
- lambda t: t.type in Token.NON_DATA_TOKENS,
1168
- tokenize_variables(token, ignore_errors=True, extra_types={Token.VARIABLE}),
1169
- )
1170
- if v.type == Token.VARIABLE
1171
- ),
1172
- None,
1173
- )
1174
-
1175
1188
  def _visit_Arguments(self, node: Statement) -> None: # noqa: N802
1176
1189
  args: Dict[VariableMatcher, VariableDefinition] = {}
1177
1190
 
1178
- arguments = node.get_tokens(Token.ARGUMENT)
1179
-
1180
- for argument_token in arguments:
1191
+ for argument_token in node.get_tokens(Token.ARGUMENT):
1181
1192
  try:
1182
- argument = self._get_variable_token(argument_token)
1193
+ argument = get_first_variable_token(argument_token)
1183
1194
 
1184
1195
  if argument is not None and argument.value != "@{}":
1185
1196
  if len(argument_token.value) > len(argument.value):
@@ -1193,18 +1204,23 @@ class NamespaceAnalyzer(Visitor):
1193
1204
  )
1194
1205
  )
1195
1206
 
1196
- matcher = VariableMatcher(argument.value)
1207
+ matcher = VariableMatcher(argument.value, parse_type=True, ignore_errors=True)
1208
+ if not matcher.is_variable() or matcher.name is None:
1209
+ continue
1210
+
1211
+ stripped_argument_token = strip_variable_token(argument, parse_type=True, matcher=matcher)
1197
1212
 
1198
1213
  if matcher not in args:
1199
1214
  arg_def = ArgumentDefinition(
1200
- name=argument.value,
1201
- name_token=strip_variable_token(argument),
1202
- line_no=argument.lineno,
1203
- col_offset=argument.col_offset,
1204
- end_line_no=argument.lineno,
1205
- end_col_offset=argument.end_col_offset,
1215
+ name=matcher.name,
1216
+ name_token=stripped_argument_token,
1217
+ line_no=stripped_argument_token.lineno,
1218
+ col_offset=stripped_argument_token.col_offset,
1219
+ end_line_no=stripped_argument_token.lineno,
1220
+ end_col_offset=stripped_argument_token.end_col_offset,
1206
1221
  source=self._namespace.source,
1207
1222
  keyword_doc=self._current_keyword_doc,
1223
+ value_type=matcher.type,
1208
1224
  )
1209
1225
 
1210
1226
  args[matcher] = arg_def
@@ -1214,22 +1230,57 @@ class NamespaceAnalyzer(Visitor):
1214
1230
  self._variable_references[arg_def] = set()
1215
1231
  else:
1216
1232
  self._variable_references[args[matcher]].add(
1217
- Location(
1218
- self._namespace.document_uri,
1219
- range_from_token(strip_variable_token(argument)),
1220
- )
1233
+ Location(self._namespace.document_uri, range_from_token(stripped_argument_token))
1221
1234
  )
1222
1235
 
1223
1236
  except (VariableError, InvalidVariableError):
1224
1237
  pass
1225
1238
 
1226
1239
  def _analyze_assign_statement(self, node: Statement) -> None:
1240
+ token_with_assign_mark: Optional[Token] = None
1227
1241
  for assign_token in node.get_tokens(Token.ASSIGN):
1228
- variable_token = self._get_variable_token(assign_token)
1229
-
1230
1242
  try:
1231
- if variable_token is not None:
1232
- matcher = VariableMatcher(variable_token.value)
1243
+ if token_with_assign_mark is not None:
1244
+ r = range_from_token(token_with_assign_mark)
1245
+ r.start.character = r.end.character - 1
1246
+ self._append_diagnostics(
1247
+ range=r,
1248
+ message="Assign mark '=' can be used only with the last variable.",
1249
+ severity=DiagnosticSeverity.ERROR,
1250
+ code=Error.ASSIGN_MARK_ALLOWED_ONLY_ON_LAST_VAR,
1251
+ )
1252
+
1253
+ if assign_token.value.endswith("="):
1254
+ token_with_assign_mark = assign_token
1255
+
1256
+ matcher = search_variable(
1257
+ assign_token.value[:-1].rstrip() if assign_token.value.endswith("=") else assign_token.value,
1258
+ parse_type=True,
1259
+ ignore_errors=True,
1260
+ )
1261
+
1262
+ if not matcher.is_assign(allow_assign_mark=True) or matcher.name is None:
1263
+ return
1264
+
1265
+ stripped_name_token = strip_variable_token(assign_token, matcher=matcher, parse_type=True)
1266
+
1267
+ if matcher.items:
1268
+ existing_var = self._find_variable(matcher.name)
1269
+ if existing_var is None:
1270
+ self._handle_find_variable_result(
1271
+ stripped_name_token,
1272
+ VariableNotFoundDefinition(
1273
+ stripped_name_token.lineno,
1274
+ stripped_name_token.col_offset,
1275
+ stripped_name_token.lineno,
1276
+ stripped_name_token.end_col_offset,
1277
+ self._namespace.source,
1278
+ matcher.name,
1279
+ stripped_name_token,
1280
+ ),
1281
+ )
1282
+ return
1283
+ else:
1233
1284
  existing_var = next(
1234
1285
  (
1235
1286
  v
@@ -1239,26 +1290,28 @@ class NamespaceAnalyzer(Visitor):
1239
1290
  ),
1240
1291
  None,
1241
1292
  )
1242
- if existing_var is None:
1243
- var_def = LocalVariableDefinition(
1244
- name=variable_token.value,
1245
- name_token=strip_variable_token(variable_token),
1246
- line_no=variable_token.lineno,
1247
- col_offset=variable_token.col_offset,
1248
- end_line_no=variable_token.lineno,
1249
- end_col_offset=variable_token.end_col_offset,
1250
- source=self._namespace.source,
1251
- )
1252
- self._variables[matcher] = var_def
1253
- self._variable_references[var_def] = set()
1254
- self._local_variable_assignments[var_def].add(var_def.range)
1255
- else:
1256
- self._variable_references[existing_var].add(
1257
- Location(
1258
- self._namespace.document_uri,
1259
- range_from_token(strip_variable_token(variable_token)),
1260
- )
1293
+
1294
+ if existing_var is None:
1295
+ var_def = LocalVariableDefinition(
1296
+ name=matcher.name,
1297
+ name_token=stripped_name_token,
1298
+ line_no=stripped_name_token.lineno,
1299
+ col_offset=stripped_name_token.col_offset,
1300
+ end_line_no=stripped_name_token.lineno,
1301
+ end_col_offset=stripped_name_token.end_col_offset,
1302
+ source=self._namespace.source,
1303
+ value_type=matcher.type,
1304
+ )
1305
+ self._variables[matcher] = var_def
1306
+ self._variable_references[var_def] = set()
1307
+ self._local_variable_assignments[var_def].add(var_def.range)
1308
+ else:
1309
+ self._variable_references[existing_var].add(
1310
+ Location(
1311
+ self._namespace.document_uri,
1312
+ range_from_token(stripped_name_token),
1261
1313
  )
1314
+ )
1262
1315
 
1263
1316
  except (VariableError, InvalidVariableError):
1264
1317
  pass
@@ -1271,24 +1324,27 @@ class NamespaceAnalyzer(Visitor):
1271
1324
  def visit_ForHeader(self, node: Statement) -> None: # noqa: N802
1272
1325
  self._analyze_statement_variables(node)
1273
1326
 
1274
- variables = node.get_tokens(Token.VARIABLE)
1275
- for variable in variables:
1276
- variable_token = self._get_variable_token(variable)
1277
- if variable_token is not None and is_variable(variable_token.value):
1278
- existing_var = self._find_variable(variable_token.value)
1327
+ for variable_token in node.get_tokens(Token.VARIABLE):
1328
+ matcher = search_variable(variable_token.value, ignore_errors=True, parse_type=True)
1329
+
1330
+ if matcher.name is not None and matcher.is_scalar_assign():
1331
+ existing_var = self._find_variable(matcher.name)
1332
+
1333
+ stripped_variable_token = strip_variable_token(variable_token, parse_type=True, matcher=matcher)
1279
1334
 
1280
1335
  if existing_var is None or existing_var.type not in [
1281
1336
  VariableDefinitionType.ARGUMENT,
1282
1337
  VariableDefinitionType.LOCAL_VARIABLE,
1283
1338
  ]:
1284
1339
  var_def = LocalVariableDefinition(
1285
- name=variable_token.value,
1286
- name_token=strip_variable_token(variable_token),
1287
- line_no=variable_token.lineno,
1288
- col_offset=variable_token.col_offset,
1289
- end_line_no=variable_token.lineno,
1290
- end_col_offset=variable_token.end_col_offset,
1340
+ name=matcher.name,
1341
+ name_token=stripped_variable_token,
1342
+ line_no=stripped_variable_token.lineno,
1343
+ col_offset=stripped_variable_token.col_offset,
1344
+ end_line_no=stripped_variable_token.lineno,
1345
+ end_col_offset=stripped_variable_token.end_col_offset,
1291
1346
  source=self._namespace.source,
1347
+ value_type=matcher.type,
1292
1348
  )
1293
1349
  self._variables[var_def.matcher] = var_def
1294
1350
  self._variable_references[var_def] = set()
@@ -1300,7 +1356,7 @@ class NamespaceAnalyzer(Visitor):
1300
1356
  self._variable_references[existing_var].add(
1301
1357
  Location(
1302
1358
  self._namespace.document_uri,
1303
- range_from_token(strip_variable_token(variable_token)),
1359
+ range_from_token(stripped_variable_token),
1304
1360
  )
1305
1361
  )
1306
1362
 
@@ -1310,31 +1366,33 @@ class NamespaceAnalyzer(Visitor):
1310
1366
 
1311
1367
  variable_token = node.get_token(Token.VARIABLE)
1312
1368
 
1313
- if variable_token is not None and is_scalar_assign(variable_token.value):
1369
+ if variable_token is not None:
1314
1370
  try:
1315
- if variable_token is not None:
1316
- matcher = VariableMatcher(variable_token.value)
1317
- if (
1318
- next(
1319
- (
1320
- k
1321
- for k, v in self._variables.items()
1322
- if k == matcher
1323
- and v.type in [VariableDefinitionType.ARGUMENT, VariableDefinitionType.LOCAL_VARIABLE]
1324
- ),
1325
- None,
1326
- )
1327
- is None
1328
- ):
1329
- self._variables[matcher] = LocalVariableDefinition(
1330
- name=variable_token.value,
1331
- name_token=strip_variable_token(variable_token),
1332
- line_no=variable_token.lineno,
1333
- col_offset=variable_token.col_offset,
1334
- end_line_no=variable_token.lineno,
1335
- end_col_offset=variable_token.end_col_offset,
1336
- source=self._namespace.source,
1337
- )
1371
+ matcher = search_variable(variable_token.value, ignore_errors=True)
1372
+ if not matcher.is_scalar_assign():
1373
+ return
1374
+
1375
+ if (
1376
+ next(
1377
+ (
1378
+ k
1379
+ for k, v in self._variables.items()
1380
+ if k == matcher
1381
+ and v.type in [VariableDefinitionType.ARGUMENT, VariableDefinitionType.LOCAL_VARIABLE]
1382
+ ),
1383
+ None,
1384
+ )
1385
+ is None
1386
+ ):
1387
+ self._variables[matcher] = LocalVariableDefinition(
1388
+ name=variable_token.value,
1389
+ name_token=strip_variable_token(variable_token),
1390
+ line_no=variable_token.lineno,
1391
+ col_offset=variable_token.col_offset,
1392
+ end_line_no=variable_token.lineno,
1393
+ end_col_offset=variable_token.end_col_offset,
1394
+ source=self._namespace.source,
1395
+ )
1338
1396
 
1339
1397
  except (VariableError, InvalidVariableError):
1340
1398
  pass
@@ -1747,9 +1805,9 @@ class NamespaceAnalyzer(Visitor):
1747
1805
  and var_token.value[1:2] == "{"
1748
1806
  and var_token.value[-1:] == "}"
1749
1807
  ):
1750
- match = ModelHelper.match_extended.match(name[2:-1])
1751
- if match is not None:
1752
- base_name, _ = match.groups()
1808
+ extended_match = ModelHelper.MATCH_EXTENDED.match(name[2:-1])
1809
+ if extended_match is not None:
1810
+ base_name, _ = extended_match.groups()
1753
1811
  name = f"{name[0]}{{{base_name.strip()}}}"
1754
1812
  var = self._find_variable(name)
1755
1813
  sub_sub_token = Token(
@@ -1,17 +1,14 @@
1
- from typing import Optional
1
+ import functools
2
2
 
3
3
  import robot.version
4
4
  from robotcode.core.utils.version import Version, create_version_from_str
5
5
 
6
- _robot_version: Optional[Version] = None
7
-
8
6
 
7
+ @functools.lru_cache(maxsize=1)
9
8
  def get_robot_version() -> Version:
10
- global _robot_version
11
- if _robot_version is None:
12
- _robot_version = create_version_from_str(robot.version.get_version())
13
- return _robot_version
9
+ return create_version_from_str(robot.version.get_version())
14
10
 
15
11
 
12
+ @functools.lru_cache(maxsize=1)
16
13
  def get_robot_version_str() -> str:
17
14
  return str(robot.version.get_version())
@@ -11,6 +11,7 @@ from robot.parsing.lexer.tokens import Token
11
11
  from robot.parsing.model.statements import EmptyLine, Statement
12
12
  from robotcode.core.lsp.types import Position, Range
13
13
 
14
+ from ..utils.variables import VariableMatcher, search_variable
14
15
  from . import get_robot_version
15
16
  from .visitor import Visitor
16
17
 
@@ -325,34 +326,35 @@ def iter_over_keyword_names_and_owners(
325
326
  yield ".".join(tokens[:i]), ".".join(tokens[i:])
326
327
 
327
328
 
328
- def strip_variable_token(token: Token) -> Token:
329
- if (
330
- token.type == Token.VARIABLE
331
- and token.value[:1] in "$@&%"
332
- and token.value[1:2] == "{"
333
- and token.value[-1:] == "}"
334
- ):
335
- value = token.value[2:-1]
336
-
337
- stripped_value = value.lstrip()
338
- stripped_offset = len(value) - len(stripped_value)
339
- return Token(
340
- token.type,
341
- stripped_value.rstrip(),
342
- token.lineno,
343
- token.col_offset + 2 + stripped_offset,
344
- )
329
+ def strip_variable_token(
330
+ token: Token, identifiers: str = "$@&%*", parse_type: bool = False, matcher: Optional[VariableMatcher] = None
331
+ ) -> Token:
332
+ if token.type in [Token.VARIABLE, Token.ASSIGN]:
333
+ if matcher is None:
334
+ matcher = search_variable(token.value, identifiers, parse_type=parse_type, ignore_errors=True)
335
+
336
+ if matcher.is_variable():
337
+ value = matcher.base
338
+
339
+ stripped_value = value.lstrip()
340
+ stripped_offset = len(value) - len(stripped_value)
341
+ return Token(
342
+ token.type,
343
+ matcher.base.strip(),
344
+ token.lineno,
345
+ token.col_offset + 2 + stripped_offset,
346
+ )
345
347
 
346
348
  return token
347
349
 
348
350
 
349
- def get_variable_token(token: Token) -> Optional[Token]:
351
+ def get_first_variable_token(token: Token, extra_types: Optional[Set[str]] = None) -> Optional[Token]:
350
352
  return next(
351
353
  (
352
354
  v
353
355
  for v in itertools.dropwhile(
354
356
  lambda t: t.type in Token.NON_DATA_TOKENS,
355
- tokenize_variables(token, ignore_errors=True),
357
+ tokenize_variables(token, ignore_errors=True, extra_types=extra_types),
356
358
  )
357
359
  if v.type == Token.VARIABLE
358
360
  ),