Completed
Push — master ( 57e7bf...8a74a7 )
by P.R.
01:36
created

SDoc2Visitor.__init__()   B

Complexity

Conditions 1

Size

Total Lines 40

Duplication

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