Skip to content

Commit fabeb92

Browse files
pekkaklarckyanne
authored andcommitted
Lexer for new parser. robotframework#3076
1 parent 6ecc066 commit fabeb92

File tree

9 files changed

+1503
-8
lines changed

9 files changed

+1503
-8
lines changed

atest/robot/core/empty_tc_and_uk.robot

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ Resource atest_resource.robot
77
Test Case Without Name
88
Check Test Case ${EMPTY}
99

10-
User Keyword Without Name
11-
Check Test Case ${TESTNAME}
12-
1310
Empty Test Case
1411
Check Test Case ${TESTNAME}
1512

atest/testdata/core/empty_testcase_and_uk.robot

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,6 @@ Documentation NO RIDE because it removes empty [Return]
55
[Documentation] FAIL Test case name cannot be empty.
66
Fail Should not be executed
77

8-
User Keyword Without Name
9-
[Documentation] FAIL Keyword name cannot be empty.
10-
\ argh
11-
Fail Should not be executed
12-
138
Empty Test Case
149
[Documentation] FAIL Test case contains no keywords.
1510
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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 __future__ import print_function # TODO: Remove once "main" is removed
17+
18+
from .context import TestCaseFileContext
19+
from .lexers import TestCaseFileLexer
20+
from .splitter import Splitter
21+
from .tokens import EOS, Token
22+
23+
24+
class RobotFrameworkLexer(object):
25+
26+
def __init__(self, data_only=False, lexer=None):
27+
self.lexer = lexer or TestCaseFileLexer()
28+
self.statements = []
29+
self._data_only = data_only
30+
31+
def input(self, content):
32+
for statement in Splitter().split(content, data_only=self._data_only):
33+
if not statement:
34+
continue
35+
self.statements.append(statement)
36+
if self._data_only:
37+
data = statement[:]
38+
else:
39+
data = [t for t in statement if t.type == t.DATA]
40+
self.lexer.input(data)
41+
42+
def get_tokens(self):
43+
self.lexer.lex(TestCaseFileContext())
44+
if self._data_only:
45+
# TODO: Should whole statement be ignored if there's ERROR?
46+
ignore = {Token.IGNORE, Token.COMMENT_HEADER, Token.COMMENT,
47+
Token.ERROR, Token.OLD_FOR_INDENT}
48+
else:
49+
ignore = {Token.IGNORE}
50+
for statement in self._handle_old_for(self.statements):
51+
name_token = last_token = None
52+
for token in statement:
53+
if token.type in ignore:
54+
continue
55+
if name_token:
56+
yield EOS.from_token(name_token)
57+
name_token = None
58+
if token.type == Token.NAME:
59+
name_token = token
60+
last_token = token
61+
yield token
62+
if last_token:
63+
yield EOS.from_token(last_token)
64+
65+
def _handle_old_for(self, statements):
66+
end_statement = [Token(Token.END)]
67+
old_for = False
68+
for statement in statements:
69+
marker = self._get_first_data_token(statement)
70+
if marker:
71+
if marker.type == Token.OLD_FOR_INDENT:
72+
old_for = True
73+
elif old_for:
74+
if marker.type != Token.END:
75+
yield end_statement
76+
old_for = False
77+
yield statement
78+
if old_for:
79+
yield end_statement
80+
81+
def _get_first_data_token(self, statement):
82+
for token in statement:
83+
if token.type not in Token.NON_DATA_TOKENS:
84+
return token
85+
return None
86+
87+
88+
# TODO: Remove when integrated...
89+
if __name__ == '__main__':
90+
import sys
91+
if len(sys.argv) == 2:
92+
data_only = False
93+
formatter = str
94+
end = ''
95+
ignore = ()
96+
else:
97+
data_only = True
98+
formatter = repr
99+
end = '\n'
100+
ignore = (Token.EOS,)
101+
lxr = RobotFrameworkLexer(data_only=data_only)
102+
with open(sys.argv[1]) as f:
103+
lxr.input(f.read())
104+
for token in lxr.get_tokens():
105+
if token.type not in ignore:
106+
print(formatter(token), end=end)

src/robot/parsing/lexer/context.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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 .settings import KeywordSettings, TestCaseFileSettings, TestCaseSettings
17+
18+
19+
class LexingContext(object):
20+
21+
def __init__(self, settings=None):
22+
self.settings = settings
23+
24+
def tokenize_setting(self, statement):
25+
return self.settings.tokenize(statement)
26+
27+
def test_case_context(self):
28+
return TestCaseContext(TestCaseSettings(self.settings))
29+
30+
def keyword_context(self):
31+
return KeywordContext(KeywordSettings())
32+
33+
34+
class TestCaseFileContext(LexingContext):
35+
36+
def __init__(self, settings=None):
37+
LexingContext.__init__(self, settings or TestCaseFileSettings())
38+
39+
40+
class TestCaseContext(LexingContext):
41+
42+
@property
43+
def template_set(self):
44+
return self.settings.template_set
45+
46+
47+
class KeywordContext(LexingContext):
48+
settings_class = KeywordSettings
49+
50+
@property
51+
def template_set(self):
52+
return False

0 commit comments

Comments
 (0)