@@ -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

@@ -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)

@@ -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

@@ -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,28 +229,21 @@
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
@@ -270,6 +251,7 @@
Loading
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

@@ -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

@@ -215,12 +215,8 @@
Loading
215 215
            push!(top, mLITERAL(ps.nt.startbyte, ps.nt.startbyte, "", Tokens.NOTHING))
216 216
        end
217 217
218 -
        safetytrip = 0
218 +
        prevpos = position(ps)
219 219
        while kindof(ps.nt) !== Tokens.ENDMARKER
220 -
            safetytrip += 1
221 -
            if safetytrip > 10_000
222 -
                throw(CSTInfiniteLoop("Infinite loop at $ps"))
223 -
            end
224 220
            curr_line = ps.nt.startpos[1]
225 221
            ret = parse_doc(ps)
226 222
            if _continue_doc_parse(ps, ret)
@@ -237,6 +233,7 @@
Loading
237 233
                push!(top, ret)
238 234
            end
239 235
            last_line = curr_line
236 +
            prevpos = loop_check(ps, prevpos)
240 237
        end
241 238
    else
242 239
        if kindof(ps.nt) === Tokens.WHITESPACE || kindof(ps.nt) === Tokens.COMMENT
@@ -252,14 +249,12 @@
Loading
252 249
            if kindof(ps.ws) == SemiColonWS
253 250
                top = EXPR(TopLevel, EXPR[top])
254 251
                safetytrip = 0
252 +
                prevpos = position(ps)
255 253
                while kindof(ps.ws) == SemiColonWS && ps.nt.startpos[1] == last_line && kindof(ps.nt) != Tokens.ENDMARKER
256 -
                    safetytrip += 1
257 -
                    if safetytrip > 10_000
258 -
                        throw(CSTInfiniteLoop("Infinite loop at $ps"))
259 -
                    end
260 254
                    ret = parse_doc(ps)
261 255
                    push!(top, ret)
262 256
                    last_line = ps.nt.startpos[1]
257 +
                    prevpos = loop_check(ps, prevpos)
263 258
                end
264 259
            end
265 260
        else

@@ -112,14 +112,11 @@
Loading
112 112
            ps.closer.inref = false
113 113
            ret = EXPR(Vcat, args)
114 114
            push!(ret, first_arg)
115 -
            safetytrip = 0
115 +
            prevpos = position(ps)
116 116
            while kindof(ps.nt) !== Tokens.RSQUARE && kindof(ps.nt) !== Tokens.ENDMARKER
117 -
                safetytrip += 1
118 -
                if safetytrip > 10_000
119 -
                    throw(CSTInfiniteLoop("Infinite loop at $ps"))
120 -
                end
121 117
                a = @closesquare ps  parse_expression(ps)
122 118
                push!(ret, a)
119 +
                prevpos = loop_check(ps, prevpos)
123 120
            end
124 121
            accept_rsquare(ps, ret)
125 122
            update_span!(ret)
@@ -127,14 +124,11 @@
Loading
127 124
        elseif kindof(ps.ws) == WS || kindof(ps.ws) == SemiColonWS
128 125
            ps.closer.inref = false
129 126
            first_row = EXPR(Hcat, EXPR[first_arg])
130 -
            safetytrip = 0
127 +
            prevpos = position(ps)
131 128
            while kindof(ps.nt) !== Tokens.RSQUARE && kindof(ps.ws) !== NewLineWS && kindof(ps.ws) !== SemiColonWS && kindof(ps.nt) !== Tokens.ENDMARKER
132 -
                safetytrip += 1
133 -
                if safetytrip > 10_000
134 -
                    throw(CSTInfiniteLoop("Infinite loop at $ps"))
135 -
                end
136 129
                a = @closesquare ps @closer ps :ws @closer ps :wsop parse_expression(ps)
137 130
                push!(first_row, a)
131 +
                prevpos = loop_check(ps, prevpos)
138 132
            end
139 133
            if kindof(ps.nt) === Tokens.RSQUARE && kindof(ps.ws) != SemiColonWS
140 134
                if length(first_row.args) == 1
@@ -151,28 +145,22 @@
Loading
151 145
                    first_row = EXPR(Row, first_row.args)
152 146
                end
153 147
                ret = EXPR(Vcat, EXPR[args[1], first_row])
154 -
                safetytrip = 0
148 +
                prevpos = position(ps)
155 149
                while kindof(ps.nt) !== Tokens.RSQUARE && kindof(ps.nt) !== Tokens.ENDMARKER
156 -
                    safetytrip += 1
157 -
                    if safetytrip > 10_000
158 -
                        throw(CSTInfiniteLoop("Infinite loop at $ps"))
159 -
                    end
160 150
                    first_arg = @closesquare ps @closer ps :ws @closer ps :wsop parse_expression(ps)
161 151
                    push!(ret, EXPR(Row, EXPR[first_arg]))
162 -
                    safetytrip1 = 0
152 +
                    prevpos1 = position(ps)
163 153
                    while kindof(ps.nt) !== Tokens.RSQUARE && kindof(ps.ws) !== NewLineWS && kindof(ps.ws) !== SemiColonWS && kindof(ps.nt) !== Tokens.ENDMARKER
164 -
                        safetytrip1 += 1
165 -
                        if safetytrip1 > 10_000
166 -
                            throw(CSTInfiniteLoop("Infinite loop at $ps"))
167 -
                        end
168 154
                        a = @closesquare ps @closer ps :ws @closer ps :wsop parse_expression(ps)
169 155
                        push!(last(ret.args), a)
156 +
                        prevpos1 = loop_check(ps, prevpos1)
170 157
                    end
171 158
                    # if only one entry dont use :row
172 159
                    if length(last(ret.args).args) == 1
173 160
                        ret.args[end] = setparent!(ret.args[end].args[1], ret)
174 161
                    end
175 162
                    update_span!(ret)
163 +
                    prevpos = loop_check(ps, prevpos)
176 164
                end
177 165
                accept_rsquare(ps, ret)
178 166
                update_span!(ret)
@@ -269,28 +257,22 @@
Loading
269 257
        elseif kindof(ps.ws) == NewLineWS
270 258
            ret = EXPR(BracesCat, args)
271 259
            push!(ret, first_arg)
272 -
            safetytrip = 0
260 +
            prevpos = position(ps)
273 261
            while kindof(ps.nt) != Tokens.RBRACE && kindof(ps.nt) !== Tokens.ENDMARKER
274 -
                safetytrip += 1
275 -
                if safetytrip > 10_000
276 -
                    throw(CSTInfiniteLoop("Infinite loop at $ps"))
277 -
                end
278 262
                a = @closebrace ps  parse_expression(ps)
279 263
                push!(ret, a)
264 +
                prevpos = loop_check(ps, prevpos)
280 265
            end
281 266
            accept_rsquare(ps, ret)
282 267
            update_span!(ret)
283 268
            return ret
284 269
        elseif kindof(ps.ws) == WS || kindof(ps.ws) == SemiColonWS
285 270
            first_row = EXPR(Row, EXPR[first_arg])
286 -
            safetytrip = 0
271 +
            prevpos = position(ps)
287 272
            while kindof(ps.nt) !== Tokens.RBRACE && kindof(ps.ws) !== NewLineWS && kindof(ps.ws) !== SemiColonWS && kindof(ps.nt) !== Tokens.ENDMARKER
288 -
                safetytrip += 1
289 -
                if safetytrip > 10_000
290 -
                    throw(CSTInfiniteLoop("Infinite loop at $ps"))
291 -
                end
292 273
                a = @closebrace ps @closer ps :ws @closer ps :wsop parse_expression(ps)
293 274
                push!(first_row, a)
275 +
                prevpos = loop_check(ps, prevpos)
294 276
            end
295 277
            if kindof(ps.nt) === Tokens.RBRACE && kindof(ps.ws) != SemiColonWS
296 278
                if length(first_row.args) == 1
@@ -306,31 +288,24 @@
Loading
306 288
                    first_row = EXPR(Row, first_row.args)
307 289
                end
308 290
                ret = EXPR(BracesCat, EXPR[args[1], first_row])
309 -
                safetytrip = 0
291 +
                prevpos = position(ps)
310 292
                while kindof(ps.nt) != Tokens.RBRACE
311 -
                    safetytrip += 1
312 -
                    if safetytrip > 10_000
313 -
                        throw(CSTInfiniteLoop("Infinite loop at $ps"))
314 -
                    end
315 293
                    if kindof(ps.nt) === Tokens.ENDMARKER
316 294
                        break
317 295
                    end
318 296
                    first_arg = @closebrace ps @closer ps :ws @closer ps :wsop parse_expression(ps)
319 297
                    push!(ret, EXPR(Row, EXPR[first_arg]))
320 -
                    safetytrip1 = 0
321 298
                    while kindof(ps.nt) !== Tokens.RBRACE && kindof(ps.ws) !== NewLineWS && kindof(ps.ws) !== SemiColonWS && kindof(ps.nt) !== Tokens.ENDMARKER
322 -
                        safetytrip1 += 1
323 -
                        if safetytrip1 > 10_000
324 -
                            throw(CSTInfiniteLoop("Infinite loop at $ps"))
325 -
                        end
326 299
                        a = @closebrace ps @closer ps :ws @closer ps :wsop parse_expression(ps)
327 300
                        push!(last(ret.args), a)
301 +
                        prevpos = loop_check(ps, prevpos)
328 302
                    end
329 303
                    # if only one entry dont use :row
330 304
                    if length(last(ret.args).args) == 1
331 305
                        ret.args[end] = setparent!(ret.args[end].args[1], ret)
332 306
                    end
333 307
                    update_span!(ret)
308 +
                    prevpos = loop_check(ps, prevpos)
334 309
                end
335 310
                accept_rbrace(ps, ret)
336 311
                update_span!(ret)
Files Coverage
src 86.01%
Project Totals (14 files) 86.01%
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests
codecov-umbrella
Build #291969644 -
unittests

No yaml found.

Create your codecov.yml to customize your Codecov experience

Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading