Skip to content

Commit eef17f7

Browse files
committed
Also try to early filter-out test_rels
1 parent 1d10d67 commit eef17f7

File tree

1 file changed

+46
-30
lines changed

1 file changed

+46
-30
lines changed

src/include_test_file.jl

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using JuliaSyntax: ParseError, ParseStream, @K_str, any_error, build_tree, bump_trivia, kind, last_byte, parse!, peek_full_token, peek_token
1+
using JuliaSyntax: JuliaSyntax, ParseError, ParseStream, @K_str
2+
using JuliaSyntax: any_error, build_tree, first_byte, kind, parse!, peek_full_token, peek_token
23
using StringViews
34

45
function include_test_file(ti_filter::TestItemFilter, path::String)
@@ -8,23 +9,23 @@ function include_test_file(ti_filter::TestItemFilter, path::String)
89
tls = task_local_storage()
910
tls[:SOURCE_PATH] = path # This is also done by Base.include
1011
try
11-
while true
12-
bump_trivia(stream, skip_newlines=true)
12+
@inbounds while true
13+
JuliaSyntax.bump_trivia(stream, skip_newlines=true)
1314
t = peek_token(stream, 1)
1415
k = kind(t)
1516
k == K"EndMarker" && break
17+
line = _source_line_index(line_starts, first_byte(stream))
1618
if k == K"@"
17-
line = searchsortedfirst(line_starts, last_byte(stream))
1819
tf = peek_full_token(stream, 2)
19-
v = @inbounds @view(bytes[tf.first_byte:tf.last_byte])
20-
if v == b"testitem" ; _eval_from_stream(stream, path, line, ti_filter, bytes)
21-
elseif v == b"testsetup"; _eval_from_stream(stream, path, line)
22-
elseif v == b"test_rel" ; _eval_from_stream(stream, path, line, ti_filter)
20+
v = @view(bytes[tf.first_byte:tf.last_byte])
21+
if v == b"testitem" ; _eval_test_item_stream(stream, path, line, ti_filter, bytes)
22+
elseif v == b"testsetup"; _eval_test_setup_stream(stream, path, line)
23+
elseif v == b"test_rel" ; _eval_test_rel_stream(stream, path, line, ti_filter, bytes)
2324
else
24-
error("Test files must only include `@testitem` and `@testsetup` calls, got an `@$(StringView(v))` at $(path)") # TODO
25+
error("Test files must only include `@testitem` and `@testsetup` calls, got an `@$(StringView(v))` at $(path):$(line)") # TODO
2526
end
2627
else
27-
error("Test files must only include `@testitem` and `@testsetup` calls, got a $t at $(path)") # TODO
28+
error("Test files must only include `@testitem` and `@testsetup` calls, got a $t at $(path):$(line)") # TODO
2829
end
2930
empty!(stream) # TODO: SourceFile created on a reset stream always start line number at 1
3031
end
@@ -33,20 +34,37 @@ function include_test_file(ti_filter::TestItemFilter, path::String)
3334
end
3435
end
3536

36-
_contains(s::AbstractString, pattern::Regex) = occursin(pattern, s)
37-
_contains(s::AbstractString, pattern::AbstractString) = s == pattern
37+
@inline function _source_line_index(line_starts, bytes_pos)
38+
lineidx = searchsortedfirst(line_starts, bytes_pos)
39+
return (lineidx < lastindex(line_starts)) ? lineidx : lineidx-1
40+
end
3841

3942
# unconditionally eval
40-
function _eval_from_stream(stream, path, line)
43+
function _eval_test_setup_stream(stream, path, line)
4144
parse!(stream; rule=:statement)
4245
ast = build_tree(Expr, stream; filename=path, first_line=line)
4346
Core.eval(Main, ast)
4447
return nothing
4548
end
4649

4750
# test_rel -> apply ti_filter on the parsed ast
48-
function _eval_from_stream(stream, path, line, ti_filter::TestItemFilter)
51+
function _eval_test_rel_stream(stream, path, line, ti_filter::TestItemFilter, bytes)
4952
parse!(stream; rule=:statement)
53+
if !(ti_filter.name isa Nothing)
54+
@inbounds for (i, token) in enumerate(stream.tokens)
55+
if kind(token) == K"Identifier"
56+
fbyte = JuliaSyntax.token_first_byte(stream, i)
57+
lbyte = JuliaSyntax.token_last_byte(stream, i)
58+
if @view(bytes[fbyte:lbyte]) == b"name"
59+
fbyte = JuliaSyntax.token_first_byte(stream, i + 3)
60+
lbyte = JuliaSyntax.token_last_byte(stream, i + 3)
61+
name = StringView(@view(bytes[fbyte:lbyte]))
62+
_contains(name, ti_filter.name) && break
63+
return nothing
64+
end
65+
end
66+
end
67+
end
5068
ast = build_tree(Expr, stream; filename=path, first_line=line)
5169
any_error(stream) && throw(ParseError(stream, filename=path))
5270
filtered = __filter_rai(ti_filter, ast)::Union{Nothing, Expr}
@@ -56,24 +74,22 @@ end
5674

5775
# like above, but tries to avoid parsing the ast if it sees from the name identifier token
5876
# it won't pass the filter
59-
function _eval_from_stream(stream, path, line, ti_filter::TestItemFilter, bytes)
60-
if ti_filter.name isa Nothing
77+
function _eval_test_item_stream(stream, path, line, ti_filter::TestItemFilter, bytes)
78+
if !(ti_filter.name isa Nothing)
79+
name_t = peek_full_token(stream, 4) # 3 was '\"'
80+
name = @inbounds StringView(@view(bytes[name_t.first_byte:name_t.last_byte]))
81+
parse!(stream; rule=:statement)
82+
_contains(name, ti_filter.name) || return nothing
83+
else
6184
parse!(stream; rule=:statement)
62-
ast = build_tree(Expr, stream; filename=path, first_line=line)
63-
any_error(stream) && throw(ParseError(stream, filename=path))
64-
filtered = __filter_ti(ti_filter, ast)::Union{Nothing, Expr}
65-
filtered === nothing || Core.eval(Main, filtered::Expr)
66-
return nothing
6785
end
6886

69-
name_t = peek_full_token(stream, 4) # 3 was '\"'
70-
name = @inbounds StringView(@view(bytes[name_t.first_byte:name_t.last_byte]))
71-
parse!(stream; rule=:statement)
72-
if _contains(name, ti_filter.name)
73-
ast = build_tree(Expr, stream; filename=path, first_line=line)
74-
any_error(stream) && throw(ParseError(stream, filename=path))
75-
filtered = __filter_ti(ti_filter, ast)::Union{Nothing, Expr}
76-
filtered === nothing || Core.eval(Main, filtered::Expr)
77-
end
87+
ast = build_tree(Expr, stream; filename=path, first_line=line)
88+
any_error(stream) && throw(ParseError(stream, filename=path))
89+
filtered = __filter_ti(ti_filter, ast)::Union{Nothing, Expr}
90+
filtered === nothing || Core.eval(Main, filtered::Expr)
7891
return nothing
7992
end
93+
94+
@inline _contains(s::AbstractString, pattern::Regex) = occursin(pattern, s)
95+
@inline _contains(s::AbstractString, pattern::AbstractString) = s == pattern

0 commit comments

Comments
 (0)