Robot Framework Integrated Development Environment (RIDE)
splitter.py
Go to the documentation of this file.
1 # Copyright 2008-2015 Nokia Networks
2 # Copyright 2016- Robot Framework Foundation
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 from robotide.lib.robot.utils import is_string, py2to3
17 
18 
20 
21  def __init__(self, string, identifiers='$@%&*'):
22  self.identifieridentifier = None
23  self.basebase = None
24  self.itemsitems = []
25  self.startstart = -1
26  self.endend = -1
27  self._identifiers_identifiers = identifiers
28  self._may_have_internal_variables_may_have_internal_variables = False
29  if not is_string(string):
30  self._max_end_max_end = -1
31  return
32  self._max_end_max_end = len(string)
33  if self._split_split(string):
34  self._finalize_finalize()
35 
36  def get_replaced_variable(self, replacer):
37  if self._may_have_internal_variables_may_have_internal_variables:
38  base = replacer.replace_string(self.basebase)
39  else:
40  base = self.basebase
41  # This omits possible variable items.
42  return '%s{%s}' % (self.identifieridentifier, base)
43 
44  def is_variable(self):
45  return bool(self.identifieridentifier and self.basebase and
46  self.startstart == 0 and self.endend == self._max_end_max_end)
47 
48  def is_list_variable(self):
49  return bool(self.identifieridentifier == '@' and self.basebase and
50  self.startstart == 0 and self.endend == self._max_end_max_end and
51  not self.itemsitems)
52 
53  def is_dict_variable(self):
54  return bool(self.identifieridentifier == '&' and self.basebase and
55  self.startstart == 0 and self.endend == self._max_end_max_end and
56  not self.itemsitems)
57 
58  def _finalize(self):
59  self.identifieridentifier = self._variable_chars_variable_chars[0]
60  self.basebase = ''.join(self._variable_chars_variable_chars[2:-1])
61  self.endend = self.startstart + len(self._variable_chars_variable_chars)
62  if self.itemsitems:
63  self.endend += len(''.join(self.itemsitems)) + 2 * len(self.itemsitems)
64 
65  def _split(self, string):
66  start_index, max_index = self._find_variable_find_variable(string)
67  if start_index == -1:
68  return False
69  self.startstart = start_index
70  self._open_curly_open_curly = 1
71  self._state_state = self._variable_state_variable_state
72  self._variable_chars_variable_chars = [string[start_index], '{']
73  self._item_chars_item_chars = []
74  self._string_string = string
75  start_index += 2
76  for index, char in enumerate(string[start_index:], start=start_index):
77  try:
78  self._state_state(char, index)
79  except StopIteration:
80  break
81  if index == max_index and not self._scanning_item_scanning_item():
82  break
83  return True
84 
85  def _scanning_item(self):
86  return self._state_state in (self._waiting_item_state_waiting_item_state, self._item_state_item_state)
87 
88  def _find_variable(self, string):
89  max_end_index = string.rfind('}')
90  if max_end_index == -1:
91  return -1, -1
92  if self._is_escaped_is_escaped(string, max_end_index):
93  return self._find_variable_find_variable(string[:max_end_index])
94  start_index = self._find_start_index_find_start_index(string, 1, max_end_index)
95  if start_index == -1:
96  return -1, -1
97  return start_index, max_end_index
98 
99  def _find_start_index(self, string, start, end):
100  while True:
101  index = string.find('{', start, end) - 1
102  if index < 0:
103  return -1
104  if self._start_index_is_ok_start_index_is_ok(string, index):
105  return index
106  start = index + 2
107 
108  def _start_index_is_ok(self, string, index):
109  return (string[index] in self._identifiers_identifiers
110  and not self._is_escaped_is_escaped(string, index))
111 
112  def _is_escaped(self, string, index):
113  escaped = False
114  while index > 0 and string[index-1] == '\\':
115  index -= 1
116  escaped = not escaped
117  return escaped
118 
119  def _variable_state(self, char, index):
120  self._variable_chars_variable_chars.append(char)
121  if char == '}' and not self._is_escaped_is_escaped(self._string_string, index):
122  self._open_curly_open_curly -= 1
123  if self._open_curly_open_curly == 0:
124  if not self._can_have_item_can_have_item():
125  raise StopIteration
126  self._state_state = self._waiting_item_state_waiting_item_state
127  elif char in self._identifiers_identifiers:
128  self._state_state = self._internal_variable_start_state_internal_variable_start_state
129 
130  def _can_have_item(self):
131  return self._variable_chars_variable_chars[0] in '$@&'
132 
133  def _internal_variable_start_state(self, char, index):
134  self._state_state = self._variable_state_variable_state
135  if char == '{':
136  self._variable_chars_variable_chars.append(char)
137  self._open_curly_open_curly += 1
138  self._may_have_internal_variables_may_have_internal_variables = True
139  else:
140  self._variable_state_variable_state(char, index)
141 
142  def _waiting_item_state(self, char, index):
143  if char != '[':
144  raise StopIteration
145  self._state_state = self._item_state_item_state
146 
147  def _item_state(self, char, index):
148  if char != ']':
149  self._item_chars_item_chars.append(char)
150  return
151  self.itemsitems.append(''.join(self._item_chars_item_chars))
152  self._item_chars_item_chars = []
153  # Don't support nested item access with olf @ and & syntax.
154  # In RF 3.2 old syntax is to be deprecated and in RF 3.3 it
155  # will be reassigned to mean using variable in list/dict context.
156  if self._variable_chars_variable_chars[0] in '@&':
157  raise StopIteration
158  self._state_state = self._waiting_item_state_waiting_item_state
159 
160 
161 @py2to3
163 
164  def __init__(self, string, identifiers='$@%&*'):
165  self._string_string = string
166  self._identifiers_identifiers = identifiers
167 
168  def __iter__(self):
169  string = self._string_string
170  while True:
171  var = VariableSplitter(string, self._identifiers_identifiers)
172  if var.identifier is None:
173  break
174  before = string[:var.start]
175  variable = '%s{%s}' % (var.identifier, var.base)
176  string = string[var.end:]
177  yield before, variable, string
178 
179  def __len__(self):
180  return sum(1 for _ in self)
181 
182  def __nonzero__(self):
183  try:
184  next(iter(self))
185  except StopIteration:
186  return False
187  else:
188  return True
def __init__(self, string, identifiers='$@%&*')
Definition: splitter.py:164
def _find_start_index(self, string, start, end)
Definition: splitter.py:99
def __init__(self, string, identifiers='$@%&*')
Definition: splitter.py:21