Completed
Pull Request — master (#45)
by Oleg
02:04
created

SDoc2Visitor   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 196
Duplicated Lines 0 %

Test Coverage

Coverage 91.94%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 20
c 1
b 0
f 0
dl 0
loc 196
ccs 57
cts 62
cp 0.9194
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A set_output() 0 7 1
A visitCmd_sdoc2() 0 13 2
A visitCmd_end() 0 9 1
A visitCmd_begin() 0 9 1
A __init__() 0 55 1
A stream() 0 8 2
A visitText() 0 7 1
A visitCmd_position() 0 19 2
A get_position() 0 17 2
C _get_options() 0 28 7
1
"""
2
SDoc
3
4
Copyright 2016 Set Based IT Consultancy
5
6
Licence MIT
7
"""
8
# ----------------------------------------------------------------------------------------------------------------------
9 1
import re
10
11 1
from sdoc import sdoc2
12 1
from sdoc.antlr.sdoc2ParserVisitor import sdoc2ParserVisitor
13 1
from sdoc.sdoc.SDocVisitor import SDocVisitor
14 1
from sdoc.sdoc2.Position import Position
15
16
17 1
class SDoc2Visitor(sdoc2ParserVisitor, SDocVisitor):
18
    """
19
    Visitor for SDoc level 2.
20
    """
21
22
    # ------------------------------------------------------------------------------------------------------------------
23 1
    def __init__(self, sdoc1_path, io):
24
        """
25
        Object constructor.
26
27
        :param str sdoc1_path: The the path to the original SDoc1 document.
28
        :param cleo.styles.output_style.OutputStyle io: The IO object.
29
        """
30 1
        SDocVisitor.__init__(self, io)
31
32 1
        self._io = io
33
        """
34
        Styled output formatter.
35
36
        :type: sdoc.style.SdocStyle.SdocStyle
37
        """
38
39 1
        self._output = None
40
        """
41
        Object for streaming the generated output. This object MUST implement the write method.
42
        """
43
44 1
        self._sdoc1_file_name = sdoc1_path
45
        """
46
        The original file name at SDoc1 level.
47
48
        :type: str
49
        """
50
51 1
        self._sdoc1_line = 0
52
        """
53
        The offset of for computing the current line at SDoc1 level.
54
55
        :type: int
56
        """
57
58 1
        self._sdoc1_column = 0
59
        """
60
        The offset of for computing the current column at SDoc1 level.
61
62
        :type: int
63
        """
64
65 1
        self._sdoc2_line = 0
66
        """
67
        The line position of the last position command.
68
69
        :type: int
70
        """
71
72 1
        self._sdoc2_column = 0
73 1
        """
74
        The last column position of the last position command.
75
76
        :type: int
77
        """
78
79
    # ------------------------------------------------------------------------------------------------------------------
80 1
    @staticmethod
81
    def _get_options(ctx):
82
        """
83
        Returns the option of an command.
84
85
        :param ParserRuleContext ctx: The parse tree with the options.
86
87
        :rtype: dict[str,str]
88
        """
89 1
        options = {}
90 1
        i = 0
91 1
        while True:
92 1
            name_token = ctx.OPT_ARG_NAME(i)
93 1
            value_token = ctx.OPT_ARG_VALUE(i)
94 1
            if not name_token:
95 1
                break
96
97 1
            option_name = name_token.getText()
98 1
            option_value = value_token.getText()
99
            # Trim leading and trailing (double)quotes from string. (Is there a way to do this in ANTLR?)
100 1
            if (option_value[0] == '"' and option_value[-1] == '"') or \
101
                    (option_value[0] == "'" and option_value[-1] == "'"):
102 1
                option_value = option_value[1:-1]
103
104 1
            options[option_name] = option_value
105 1
            i += 1
106
107 1
        return options
108
109
    # ------------------------------------------------------------------------------------------------------------------
110 1
    def get_position(self, token):
111
        """
112
        Returns the position of the token in the original SDoc1 source file.
113
114
        :param token:
115
116
        :rtype: sdoc.sdoc2.Position.Position
117
        """
118 1
        line_number = token.line
119 1
        column = token.column
120
121 1
        if self._sdoc2_line == line_number:
122 1
            column = self._sdoc1_column + (column - self._sdoc2_column)
123
124 1
        line_number = self._sdoc1_line + (line_number - self._sdoc2_line)
125
126 1
        return Position(self._sdoc1_file_name, line_number, column, -1, -1)
127
128
    # ------------------------------------------------------------------------------------------------------------------
129 1
    def set_output(self, output):
130
        """
131
        Sets the object for streaming the generated output.
132
133
        :param output: This object MUST implement the write method.
134
        """
135
        self._output = output
136
137
    # ------------------------------------------------------------------------------------------------------------------
138 1
    def stream(self, snippet):
139
        """
140
        Puts an output snippet on the output stream.
141
142
        :param str snippet: The snippet to be appended to the output stream of this parser.
143
        """
144
        if snippet is not None:
145
            self._output.write(snippet)
146
147
    # ------------------------------------------------------------------------------------------------------------------
148 1
    def visitCmd_begin(self, ctx):
149
        """
150
        Visit a parse tree produced by a begin command.
151
152
        :param sdoc.antlr.sdoc2Parser.sdoc2Parser.Cmd_beginContext ctx: The parse tree.
153
        """
154 1
        command = ctx.BLOCK_ARG_ARG().getText()
155
156 1
        sdoc2.node_store.append_block_node(command, self._get_options(ctx), self.get_position(ctx.start))
157
158
    # ------------------------------------------------------------------------------------------------------------------
159 1
    def visitCmd_end(self, ctx):
160
        """
161
        Visit a parse tree produced by an end command.
162
163
        :param sdoc.antlr.sdoc2Parser.sdoc2Parser.Cmd_endContext ctx: The parse tree.
164
        """
165 1
        command = ctx.BLOCK_ARG_ARG().getText().rstrip()
166
167 1
        sdoc2.node_store.end_block_node(command)
168
169
    # ------------------------------------------------------------------------------------------------------------------
170 1
    def visitCmd_position(self, ctx):
171
        """
172
        Visit a parse tree produced by a position command.
173
174
        :param sdoc.antlr.sdoc2Parser.sdoc2Parser.Cmd_positionContext ctx: The parse tree.
175
        """
176 1
        argument = ctx.INLINE_ARG_ARG()
177 1
        parts = re.match(r'(.+):([0-9]+)\.([0-9]+)', str(argument))
178 1
        if not parts:
179
            self._error('{0!s} is not a valid position'.format(argument))
180
            return
181
182 1
        self._sdoc1_file_name = parts.group(1)
183 1
        self._sdoc1_line = int(parts.group(2))
184 1
        self._sdoc1_column = int(parts.group(3))
185
186 1
        token = ctx.stop
187 1
        self._sdoc2_line = token.line
188 1
        self._sdoc2_column = token.column + len(token.text)
189
190
    # ------------------------------------------------------------------------------------------------------------------
191 1
    def visitCmd_sdoc2(self, ctx):
192
        """
193
        Visit a parse tree produced by a inline command.
194
195
        :param sdoc.antlr.sdoc2Parser.sdoc2Parser.Cmd_sdoc2Context ctx: The parse tree.
196
        """
197 1
        command = ctx.SDOC2_COMMAND().getText()
198 1
        argument = ctx.INLINE_ARG_ARG()
199
200 1
        sdoc2.node_store.append_inline_node(command[1:],
201
                                            self._get_options(ctx),
202
                                            argument.getText() if argument else '',
203
                                            self.get_position(ctx.start))
204
205
    # ------------------------------------------------------------------------------------------------------------------
206 1
    def visitText(self, ctx):
207
        """
208
        Visit a parse tree produced by TEXT.
209
210
        :param sdoc.antlr.sdoc2Parser.sdoc2Parser.TextContext ctx: The parse tree.
211
        """
212 1
        sdoc2.node_store.append_inline_node('TEXT', {}, ctx.TEXT().getText(), self.get_position(ctx.start))
213
214
# ----------------------------------------------------------------------------------------------------------------------
215