Completed
Pull Request — master (#40)
by Oleg
01:53
created

SDoc2Visitor   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 193
Duplicated Lines 0 %

Importance

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