Compare 04c72c3 ... +2 ... fc030f1

Flags

Flags have been temporarily removed from this view while the flagging feature is refactored for better performance and user experience.

You can still use flags when viewing individual files. Flag-level thresholds will also remain on pull and merge requests in your repository provider.

More information can be found in our documentation.


@@ -5,13 +5,8 @@
Loading
5 5
`end`). Statements are grouped in a `Block` EXPR.
6 6
"""
7 7
function parse_block(ps::ParseState, ret::Vector{EXPR}=EXPR[], closers=(Tokens.END,), docable=false)
8 -
    safetytrip = 0
8 +
    prevpos = position(ps)
9 9
    while kindof(ps.nt) βˆ‰ closers # loop until an expected closer is hit
10 -
        safetytrip += 1
11 -
        if safetytrip > 10_000
12 -
            # Not needed, we take a take a token or break the loop for each branch.
13 -
            throw(CSTInfiniteLoop("Infinite loop at $ps"))
14 -
        end
15 10
        if kindof(ps.nt) ∈ term_c # error handling if an unexpected closer is hit
16 11
            if kindof(ps.nt) === Tokens.ENDMARKER
17 12
                break
@@ -32,6 +27,7 @@
Loading
32 27
            end
33 28
            push!(ret, a)
34 29
        end
30 +
        prevpos = loop_check(ps, prevpos)
35 31
    end
36 32
    return ret
37 33
end
@@ -70,15 +66,12 @@
Loading
70 66
    arg = parse_iterator(ps)
71 67
    if iscomma(ps.nt) # we've hit a comma separated list of iterators.
72 68
        arg = EXPR(Block, EXPR[arg])
73 -
        safetytrip = 0
69 +
        prevpos = position(ps)
74 70
        while iscomma(ps.nt)
75 -
            safetytrip += 1
76 -
            if safetytrip > 10_000
77 -
                throw(CSTInfiniteLoop("Infinite loop at $ps"))
78 -
            end
79 71
            accept_comma(ps, arg)
80 72
            nextarg = parse_iterator(ps)
81 73
            push!(arg, nextarg)
74 +
            prevpos = loop_check(ps, prevpos)
82 75
        end
83 76
    end
84 77
@@ -147,8 +140,8 @@
Loading
147 140
assignment (`=`) expressions to `Kw`.
148 141
"""
149 142
function parse_comma_sep(ps::ParseState, args::Vector{EXPR}, kw=true, block=false, istuple=false)
143 +
    prevpos = position(ps)
150 144
    @nocloser ps :inwhere @nocloser ps :newline @closer ps :comma while !closer(ps)
151 -
        starting_offset = ps.t.startbyte
152 145
        a = parse_expression(ps)
153 146
        if kw && _do_kw_convert(ps, a)
154 147
            a = _kw_convert(a)
@@ -159,10 +152,7 @@
Loading
159 152
        else# if kindof(ps.ws) == SemiColonWS
160 153
            break
161 154
        end
162 -
        if ps.t.startbyte <= starting_offset
163 -
            # We've not progressed over the course of a loop.
164 -
            throw(CSTInfiniteLoop("Infinite loop at $ps"))
165 -
        end
155 +
        prevpos = loop_check(ps, prevpos)
166 156
    end
167 157
    if istuple && length(args) > 2
168 158
        block = false
@@ -179,14 +169,11 @@
Loading
179 169
            a = @nocloser ps :newline @closer ps :comma @nocloser ps :inwhere parse_expression(ps)
180 170
            if block && !(length(args) == 1 && ispunctuation(args[1])) && !is_splat(last(args)) && !(istuple && iscomma(ps.nt))
181 171
                args1 = EXPR[pop!(args), a]
182 -
                safetytrip = 0
172 +
                prevpos = position(ps)
183 173
                @nocloser ps :newline @closer ps :comma while @nocloser ps :semicolon !closer(ps)
184 -
                    safetytrip += 1
185 -
                    if safetytrip > 10_000
186 -
                        throw(CSTInfiniteLoop("Infinite loop at $ps"))
187 -
                    end
188 174
                    a = parse_expression(ps)
189 175
                    push!(args1, a)
176 +
                    prevpos = loop_check(ps, prevpos)
190 177
                end
191 178
                body = EXPR(Block, args1)
192 179
                push!(args, body)
@@ -206,12 +193,8 @@
Loading
206 193
"""
207 194
function parse_parameters(ps::ParseState, args::Vector{EXPR}, args1::Vector{EXPR}=EXPR[]; usekw=true)
208 195
    isfirst = isempty(args1)
209 -
    safetytrip = 0
196 +
    prevpos = position(ps)
210 197
    @nocloser ps :inwhere @nocloser ps :newline  @closer ps :comma while !isfirst || (@nocloser ps :semicolon !closer(ps))
211 -
        safetytrip += 1
212 -
        if safetytrip > 10_000
213 -
            throw(CSTInfiniteLoop("Infinite loop at $ps"))
214 -
        end
215 198
        if isfirst
216 199
            a = parse_expression(ps)
217 200
        else
@@ -232,6 +215,11 @@
Loading
232 215
        if kindof(ps.ws) == SemiColonWS
233 216
            parse_parameters(ps, args1; usekw=usekw)
234 217
        end
218 +
        if isfirst
219 +
            prevpos = loop_check(ps, prevpos)
220 +
        else
221 +
            prevpos = position(ps)
222 +
        end
235 223
        isfirst = true
236 224
    end
237 225
    if !isempty(args1)
@@ -256,15 +244,12 @@
Loading
256 244
257 245
    # Handle cases with @ at start of dotted expressions
258 246
    if kindof(ps.nt) === Tokens.DOT && isemptyws(ps.ws)
259 -
        safetytrip = 0
247 +
        prevpos = position(ps)
260 248
        while kindof(ps.nt) === Tokens.DOT
261 -
            safetytrip += 1
262 -
            if safetytrip > 10_000
263 -
                throw(CSTInfiniteLoop("Infinite loop at $ps"))
264 -
            end
265 249
            op = mOPERATOR(next(ps))
266 250
            nextarg = mIDENTIFIER(next(ps))
267 251
            mname = mBinaryOpCall(mname, op, EXPR(Quotenode, EXPR[nextarg]))
252 +
            prevpos = loop_check(ps, prevpos)
268 253
        end
269 254
    end
270 255
@@ -275,12 +260,8 @@
Loading
275 260
    else
276 261
        args = EXPR[mname]
277 262
        insquare = ps.closer.insquare
278 -
        safetytrip = 0
263 +
        prevpos = position(ps)
279 264
        @default ps while !closer(ps)
280 -
            safetytrip += 1
281 -
            if safetytrip > 10_000
282 -
                throw(CSTInfiniteLoop("Infinite loop at $ps"))
283 -
            end
284 265
            if insquare
285 266
                a = @closer ps :insquare @closer ps :inmacro @closer ps :ws @closer ps :wsop parse_expression(ps)
286 267
            else
@@ -290,6 +271,7 @@
Loading
290 271
            if insquare && kindof(ps.nt) === Tokens.FOR
291 272
                break
292 273
            end
274 +
            prevpos = loop_check(ps, prevpos)
293 275
        end
294 276
        return EXPR(MacroCall, args)
295 277
    end
@@ -325,12 +307,8 @@
Loading
325 307
function parse_dot_mod(ps::ParseState, is_colon=false)
326 308
    args = EXPR[]
327 309
328 -
    safetytrip = 0
310 +
    prevpos = position(ps)
329 311
    while kindof(ps.nt) === Tokens.DOT || kindof(ps.nt) === Tokens.DDOT || kindof(ps.nt) === Tokens.DDDOT
330 -
        safetytrip += 1
331 -
        if safetytrip > 10_000
332 -
            throw(CSTInfiniteLoop("Infinite loop at $ps"))
333 -
        end
334 312
        d = mOPERATOR(next(ps))
335 313
        trailing_ws = d.fullspan - d.span
336 314
        if is_dot(d)
@@ -343,6 +321,7 @@
Loading
343 321
            push!(args, mOPERATOR(1, 1, Tokens.DOT, false))
344 322
            push!(args, mOPERATOR(1 + trailing_ws, 1, Tokens.DOT, false))
345 323
        end
324 +
        prevpos = loop_check(ps, prevpos)
346 325
    end
347 326
348 327
    # import/export ..
@@ -353,12 +332,8 @@
Loading
353 332
    #     end
354 333
    # end
355 334
356 -
    safetytrip = 0
335 +
    prevpos = position(ps)
357 336
    while true
358 -
        safetytrip += 1
359 -
        if safetytrip > 10_000
360 -
            throw(CSTInfiniteLoop("Infinite loop at $ps"))
361 -
        end
362 337
        if kindof(ps.nt) === Tokens.AT_SIGN
363 338
            at = mPUNCTUATION(next(ps))
364 339
            a = INSTANCE(next(ps))
@@ -388,6 +363,7 @@
Loading
388 363
        else
389 364
            break
390 365
        end
366 +
        prevpos = loop_check(ps, prevpos)
391 367
    end
392 368
    args
393 369
end

@@ -49,13 +49,10 @@
Loading
49 49
50 50
function ParseState(str::Union{IO,String}, loc::Int)
51 51
    ps = ParseState(str)
52 -
    prev_pos = -1  # TODO: remove
52 +
    prevpos = position(ps)
53 53
    while ps.nt.startbyte < loc
54 -
        if prev_pos == ps.nt.startbyte  # TODO: remove
55 -
            throw(CSTInfiniteLoop("Inifite loop at $ps"))  # TODO: remove
56 -
        end  # TODO: remove
57 -
        prev_pos = ps.nt.startbyte # TODO: remove
58 54
        next(ps)
55 +
        prevpos = loop_check(ps, prevpos)
59 56
    end
60 57
    return ps
61 58
end
@@ -97,6 +94,7 @@
Loading
97 94
    next(next(ps))
98 95
end
99 96
97 +
Base.position(ps::ParseState) = ps.nt.startbyte
100 98
101 99
"""
102 100
    lex_ws_comment(l::Lexer, c)

@@ -164,27 +164,21 @@
Loading
164 164
165 165
        arg = parse_dot_mod(ps, true)
166 166
        append!(ret, arg)
167 -
        safetytrip = 0
167 +
        prevpos = position(ps)
168 168
        while iscomma(ps.nt)
169 -
            safetytrip += 1
170 -
            if safetytrip > 10_000
171 -
                throw(CSTInfiniteLoop("Infinite loop at $ps"))
172 -
            end
173 169
            accept_comma(ps, ret)
174 170
            arg = parse_dot_mod(ps, true)
175 171
            append!(ret, arg)
172 +
            prevpos = loop_check(ps, prevpos)
176 173
        end
177 174
    else
178 175
        ret = EXPR(kwt, vcat(kw, arg))
179 -
        safetytrip = 0
176 +
        prevpos = position(ps)
180 177
        while iscomma(ps.nt)
181 -
            safetytrip += 1
182 -
            if safetytrip > 10_000
183 -
                throw(CSTInfiniteLoop("Infinite loop at $ps"))
184 -
            end
185 178
            accept_comma(ps, ret)
186 179
            arg = parse_dot_mod(ps)
187 180
            append!(ret, arg)
181 +
            prevpos = loop_check(ps, prevpos)
188 182
        end
189 183
    end
190 184
@@ -195,15 +189,12 @@
Loading
195 189
    args = EXPR[mKEYWORD(ps)]
196 190
    append!(args, parse_dot_mod(ps))
197 191
198 -
    safetytrip = 0
192 +
    prevpos = position(ps)
199 193
    while iscomma(ps.nt)
200 -
        safetytrip += 1
201 -
        if safetytrip > 10_000
202 -
            throw(CSTInfiniteLoop("Infinite loop at $ps"))
203 -
        end
204 194
        push!(args, mPUNCTUATION(next(ps)))
205 195
        arg = parse_dot_mod(ps)[1]
206 196
        push!(args, arg)
197 +
        prevpos = loop_check(ps, prevpos)
207 198
    end
208 199
209 200
    return EXPR(Export, args)
@@ -225,13 +216,10 @@
Loading
225 216
        if convertsigtotuple(sig)
226 217
            sig = EXPR(TupleH, sig.args)
227 218
        end
228 -
        safetytrip = 0
219 +
        prevpos = position(ps)
229 220
        while kindof(ps.nt) === Tokens.WHERE && kindof(ps.ws) != Tokens.NEWLINE_WS
230 -
            safetytrip += 1
231 -
            if safetytrip > 10_000
232 -
                throw(CSTInfiniteLoop("Infinite loop at $ps"))
233 -
            end
234 221
            sig = @closer ps :inwhere @closer ps :ws parse_operator_where(ps, sig, INSTANCE(next(ps)), false)
222 +
            prevpos = loop_check(ps, prevpos)
235 223
        end
236 224
        return sig
237 225
    elseif head === Let
@@ -241,35 +229,29 @@
Loading
241 229
            arg = @closer ps :comma @closer ps :ws  parse_expression(ps)
242 230
            if iscomma(ps.nt) || !(is_wrapped_assignment(arg) || isidentifier(arg))
243 231
                arg = EXPR(Block, EXPR[arg])
244 -
                safetytrip = 0
232 +
                prevpos = position(ps)
245 233
                while iscomma(ps.nt)
246 -
                    safetytrip += 1
247 -
                    if safetytrip > 10_000
248 -
                        throw(CSTInfiniteLoop("Infinite loop at $ps"))
249 -
                    end
250 234
                    accept_comma(ps, arg)
251 235
                    startbyte = ps.nt.startbyte
252 236
                    nextarg = @closer ps :comma @closer ps :ws parse_expression(ps)
253 237
                    push!(arg, nextarg)
238 +
                    prevpos = loop_check(ps, prevpos)
254 239
                end
255 240
            end
256 241
            return arg
257 242
        end
258 243
    elseif head === Do
259 244
        sig = EXPR(TupleH, EXPR[])
260 -
        safetytrip = 0
245 +
        prevpos = position(ps)
261 246
        @closer ps :comma @closer ps :block while !closer(ps)
262 -
            safetytrip += 1
263 -
            if safetytrip > 10_000
264 -
                throw(CSTInfiniteLoop("Infinite loop at $ps"))
265 -
            end
266 247
            @closer ps :ws a = parse_expression(ps)
267 248
            push!(sig, a)
268 249
            if kindof(ps.nt) === Tokens.COMMA
269 250
                accept_comma(ps, sig)
270 251
            elseif @closer ps :ws closer(ps)
271 252
                break
272 253
            end
254 +
            prevpos = loop_check(ps, prevpos)
273 255
        end
274 256
        return sig
275 257
    elseif head === ModuleH || head === BareModule

@@ -712,3 +712,11 @@
Loading
712 712
arguments?
713 713
"""
714 714
can_become_chain(x::EXPR, op::EXPR) = isbinarycall(x) && (is_star(op) || is_plus(op)) && kindof(op) == kindof(x.args[2]) && !x.args[2].dot && x.args[2].span > 0
715 +
716 +
function loop_check(ps, prevpos)
717 +
    if position(ps) <= prevpos
718 +
        throw(CSTInfiniteLoop("Infinite loop at $ps"))
719 +
    else
720 +
        position(ps)
721 +
    end
722 +
end

@@ -37,20 +37,12 @@
Loading
37 37
            (isempty(str) || (lcp !== nothing && isempty(lcp))) && return
38 38
            (last && str[end] == '\n') && return (lcp = "")
39 39
            idxstart, idxend = 2, 1
40 -
            safetytrip = 0
40 +
            prevpos = idxend
41 41
            while nextind(str, idxend) - 1 < sizeof(str) && (lcp === nothing || !isempty(lcp))
42 -
                safetytrip += 1
43 -
                if safetytrip > 10_000
44 -
                    throw(CSTInfiniteLoop("Infinite loop."))
45 -
                end
46 42
                idxend = skip_to_nl(str, idxend)
47 43
                idxstart = nextind(str, idxend)
48 -
                safetytrip1 = 0
44 +
                prevpos1 = idxend
49 45
                while nextind(str, idxend) - 1 < sizeof(str)
50 -
                    safetytrip1 += 1
51 -
                    if safetytrip1 > 10_000
52 -
                        throw(CSTInfiniteLoop("Infinite loop."))
53 -
                    end
54 46
                    c = str[nextind(str, idxend)]
55 47
                    if c == ' ' || c == '\t'
56 48
                        idxend += 1
@@ -63,6 +55,16 @@
Loading
63 55
                        lcp = lcp === nothing ? prefix : longest_common_prefix(lcp, prefix)
64 56
                        break
65 57
                    end
58 +
                    if idxend <= prevpos1
59 +
                        throw(CSTInfiniteLoop("Infinite loop in adjust_lcp"))
60 +
                    else
61 +
                        prevpos1 = idxend
62 +
                    end
63 +
                end
64 +
                if idxend < prevpos
65 +
                    throw(CSTInfiniteLoop("Infinite loop in adjust_lcp"))
66 +
                else
67 +
                    prevpos = idxend
66 68
                end
67 69
            end
68 70
            if idxstart != nextind(str, idxend)
@@ -100,11 +102,8 @@
Loading
100 102
        seek(input, startbytes)
101 103
        b = IOBuffer()
102 104
        safetytrip = 0
105 +
        prevpos = position(input)
103 106
        while !eof(input)
104 -
            safetytrip += 1
105 -
            if safetytrip > length(str2) # This is iterating over characters, not parsed expressions - 10,000 was in inappropriate limit.
106 -
                throw(CSTInfiniteLoop("Infinite loop parsing: \"$str2\""))
107 -
            end
108 107
            c = read(input, Char)
109 108
            if c == '\\'
110 109
                write(b, c)
@@ -160,6 +159,7 @@
Loading
160 159
            else
161 160
                write(b, c)
162 161
            end
162 +
            prevpos = loop_check(input, prevpos)
163 163
        end
164 164
165 165
        # handle last String section

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Everything is accounted for!

No changes detected that need to be reviewed.
What changes does Codecov check for?
Lines, not adjusted in diff, that have changed coverage data.
Files that introduced coverage data that had none before.
Files that have missing coverage data that once were tracked.
Files Coverage
src +1.64% 86.01%
Project Totals (14 files) 86.01%
Loading