~corey.bryant/ubuntu/wily/python-pyscss/thedac

« back to all changes in this revision

Viewing changes to scss/src/grammar/yappsrt.py

  • Committer: Package Import Robot
  • Author(s): Thomas Goirand
  • Date: 2014-06-26 12:10:36 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20140626121036-3dv13zn5zptk9fpx
Tags: 1.2.0.post3-1
* Team upload.
* New upstream release (Closes: #738776).
* Added a debian/gbp.conf.
* Added missing ${python:Depends}
* Added Python 3 support.
* Removed duplicate debhelper build-depends.
* Cannonical VCS URLs.
* Standards-Version: is now 3.9.5.
* Added a watch file.
* override dh helpers which the package doesn't use.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Yapps 3.0 Runtime (by Kronuz)
2
 
#
3
 
# This module is needed to run generated parsers.
4
 
 
5
 
import re
6
 
 
7
 
try:
8
 
    from _scss import Scanner, NoMoreTokens
9
 
except ImportError:
10
 
    Scanner = None
11
 
 
12
 
################################################################################
13
 
# Parser
14
 
 
15
 
if not Scanner:
16
 
    class NoMoreTokens(Exception):
17
 
        """
18
 
        Another exception object, for when we run out of tokens
19
 
        """
20
 
        pass
21
 
 
22
 
    class Scanner(object):
23
 
        def __init__(self, patterns, ignore, input=None):
24
 
            """
25
 
            Patterns is [(terminal,regex)...]
26
 
            Ignore is [terminal,...];
27
 
            Input is a string
28
 
            """
29
 
            self.reset(input)
30
 
            self.ignore = ignore
31
 
            # The stored patterns are a pair (compiled regex,source
32
 
            # regex).  If the patterns variable passed in to the
33
 
            # constructor is None, we assume that the class already has a
34
 
            # proper .patterns list constructed
35
 
            if patterns is not None:
36
 
                self.patterns = []
37
 
                for k, r in patterns:
38
 
                    self.patterns.append((k, re.compile(r)))
39
 
 
40
 
        def reset(self, input):
41
 
            self.tokens = []
42
 
            self.restrictions = []
43
 
            self.input = input
44
 
            self.pos = 0
45
 
 
46
 
        def __repr__(self):
47
 
            """
48
 
            Print the last 10 tokens that have been scanned in
49
 
            """
50
 
            output = ''
51
 
            for t in self.tokens[-10:]:
52
 
                output = "%s\n  (@%s)  %s  =  %s" % (output, t[0], t[2], repr(t[3]))
53
 
            return output
54
 
 
55
 
        def _scan(self, restrict):
56
 
            """
57
 
            Should scan another token and add it to the list, self.tokens,
58
 
            and add the restriction to self.restrictions
59
 
            """
60
 
            # Keep looking for a token, ignoring any in self.ignore
61
 
            token = None
62
 
            while True:
63
 
                best_pat = None
64
 
                # Search the patterns for a match, with earlier
65
 
                # tokens in the list having preference
66
 
                best_pat_len = 0
67
 
                for p, regexp in self.patterns:
68
 
                    # First check to see if we're restricting to this token
69
 
                    if restrict and p not in restrict and p not in self.ignore:
70
 
                        continue
71
 
                    m = regexp.match(self.input, self.pos)
72
 
                    if m:
73
 
                        # We got a match
74
 
                        best_pat = p
75
 
                        best_pat_len = len(m.group(0))
76
 
                        break
77
 
 
78
 
                # If we didn't find anything, raise an error
79
 
                if best_pat is None:
80
 
                    msg = "Bad Token"
81
 
                    if restrict:
82
 
                        msg = "Trying to find one of " + ", ".join(restrict)
83
 
                    raise SyntaxError("SyntaxError[@ char %s: %s]" % (repr(self.pos), msg))
84
 
 
85
 
                # If we found something that isn't to be ignored, return it
86
 
                if best_pat in self.ignore:
87
 
                    # This token should be ignored...
88
 
                    self.pos += best_pat_len
89
 
                else:
90
 
                    end_pos = self.pos + best_pat_len
91
 
                    # Create a token with this data
92
 
                    token = (
93
 
                        self.pos,
94
 
                        end_pos,
95
 
                        best_pat,
96
 
                        self.input[self.pos:end_pos]
97
 
                    )
98
 
                    break
99
 
            if token is not None:
100
 
                self.pos = token[1]
101
 
                # Only add this token if it's not in the list
102
 
                # (to prevent looping)
103
 
                if not self.tokens or token != self.tokens[-1]:
104
 
                    self.tokens.append(token)
105
 
                    self.restrictions.append(restrict)
106
 
                    return 1
107
 
            return 0
108
 
 
109
 
        def token(self, i, restrict=None):
110
 
            """
111
 
            Get the i'th token, and if i is one past the end, then scan
112
 
            for another token; restrict is a list of tokens that
113
 
            are allowed, or 0 for any token.
114
 
            """
115
 
            tokens_len = len(self.tokens)
116
 
            if i == tokens_len:  # We are at the end, get the next...
117
 
                tokens_len += self._scan(restrict)
118
 
            if i < tokens_len:
119
 
                if restrict and self.restrictions[i] and restrict > self.restrictions[i]:
120
 
                    raise NotImplementedError("Unimplemented: restriction set changed")
121
 
                return self.tokens[i]
122
 
            raise NoMoreTokens
123
 
 
124
 
        def rewind(self, i):
125
 
            tokens_len = len(self.tokens)
126
 
            if i <= tokens_len:
127
 
                token = self.tokens[i]
128
 
                self.tokens = self.tokens[:i]
129
 
                self.restrictions = self.restrictions[:i]
130
 
                self.pos = token[0]
131
 
 
132
 
 
133
 
class CachedScanner(Scanner):
134
 
    """
135
 
    Same as Scanner, but keeps cached tokens for any given input
136
 
    """
137
 
    _cache_ = {}
138
 
    _goals_ = ['END']
139
 
 
140
 
    @classmethod
141
 
    def cleanup(cls):
142
 
        cls._cache_ = {}
143
 
 
144
 
    def __init__(self, patterns, ignore, input=None):
145
 
        try:
146
 
            self._tokens = self._cache_[input]
147
 
        except KeyError:
148
 
            self._tokens = None
149
 
            self.__tokens = {}
150
 
            self.__input = input
151
 
            super(CachedScanner, self).__init__(patterns, ignore, input)
152
 
 
153
 
    def reset(self, input):
154
 
        try:
155
 
            self._tokens = self._cache_[input]
156
 
        except KeyError:
157
 
            self._tokens = None
158
 
            self.__tokens = {}
159
 
            self.__input = input
160
 
            super(CachedScanner, self).reset(input)
161
 
 
162
 
    def __repr__(self):
163
 
        if self._tokens is None:
164
 
            return super(CachedScanner, self).__repr__()
165
 
        output = ''
166
 
        for t in self._tokens[-10:]:
167
 
            output = "%s\n  (@%s)  %s  =  %s" % (output, t[0], t[2], repr(t[3]))
168
 
        return output
169
 
 
170
 
    def token(self, i, restrict=None):
171
 
        if self._tokens is None:
172
 
            token = super(CachedScanner, self).token(i, restrict)
173
 
            self.__tokens[i] = token
174
 
            if token[2] in self._goals_:  # goal tokens
175
 
                self._cache_[self.__input] = self._tokens = self.__tokens
176
 
            return token
177
 
        else:
178
 
            token = self._tokens.get(i)
179
 
            if token is None:
180
 
                raise NoMoreTokens
181
 
            return token
182
 
 
183
 
    def rewind(self, i):
184
 
        if self._tokens is None:
185
 
            super(CachedScanner, self).rewind(i)
186
 
 
187
 
 
188
 
class Parser(object):
189
 
    def __init__(self, scanner):
190
 
        self._scanner = scanner
191
 
        self._pos = 0
192
 
 
193
 
    def reset(self, input):
194
 
        self._scanner.reset(input)
195
 
        self._pos = 0
196
 
 
197
 
    def _peek(self, types):
198
 
        """
199
 
        Returns the token type for lookahead; if there are any args
200
 
        then the list of args is the set of token types to allow
201
 
        """
202
 
        tok = self._scanner.token(self._pos, types)
203
 
        return tok[2]
204
 
 
205
 
    def _scan(self, type):
206
 
        """
207
 
        Returns the matched text, and moves to the next token
208
 
        """
209
 
        tok = self._scanner.token(self._pos, set([type]))
210
 
        if tok[2] != type:
211
 
            raise SyntaxError("SyntaxError[@ char %s: %s]" % (repr(tok[0]), "Trying to find " + type))
212
 
        self._pos += 1
213
 
        return tok[3]
214
 
 
215
 
    def _rewind(self, n=1):
216
 
        self._pos -= min(n, self._pos)
217
 
        self._scanner.rewind(self._pos)
218
 
 
219
 
 
220
 
################################################################################
221
 
 
222
 
 
223
 
def print_error(input, err, scanner):
224
 
    """This is a really dumb long function to print error messages nicely."""
225
 
    p = err.pos
226
 
    # Figure out the line number
227
 
    line = input[:p].count('\n')
228
 
    print err.msg + " on line " + repr(line + 1) + ":"
229
 
    # Now try printing part of the line
230
 
    text = input[max(p - 80, 0):
231
 
        p + 80]
232
 
    p = p - max(p - 80, 0)
233
 
 
234
 
    # Strip to the left
235
 
    i = text[:p].rfind('\n')
236
 
    j = text[:p].rfind('\r')
237
 
    if i < 0 or (0 <= j < i):
238
 
        i = j
239
 
    if 0 <= i < p:
240
 
        p = p - i - 1
241
 
        text = text[i + 1:]
242
 
 
243
 
    # Strip to the right
244
 
    i = text.find('\n', p)
245
 
    j = text.find('\r', p)
246
 
    if i < 0 or (0 <= j < i):
247
 
        i = j
248
 
    if i >= 0:
249
 
        text = text[:i]
250
 
 
251
 
    # Now shorten the text
252
 
    while len(text) > 70 and p > 60:
253
 
        # Cut off 10 chars
254
 
        text = "..." + text[10:]
255
 
        p = p - 7
256
 
 
257
 
    # Now print the string, along with an indicator
258
 
    print '> ', text
259
 
    print '> ', ' ' * p + '^'
260
 
    print 'List of nearby tokens:', scanner
261
 
 
262
 
 
263
 
def wrap_error_reporter(parser, rule, *args):
264
 
    try:
265
 
        return getattr(parser, rule)(*args)
266
 
    except SyntaxError, s:
267
 
        input = parser._scanner.input
268
 
        try:
269
 
            print_error(input, s, parser._scanner)
270
 
            raise
271
 
        except ImportError:
272
 
            print "Syntax Error %s on line %d" % (s.msg, input[:s.pos].count('\n') + 1)
273
 
    except NoMoreTokens:
274
 
        print "Could not complete parsing; stopped around here:"
275
 
        print parser._scanner