1- using JuliaSyntax: ParseStream, @K_str , build_tree, bump_trivia, kind, parse!, peek_full_token, peek_token
1+ using JuliaSyntax: ParseError, ParseStream, @K_str , any_error, build_tree, bump_trivia, kind, last_byte , parse!, peek_full_token, peek_token
22using StringViews
33
44function include_test_file (ti_filter:: TestItemFilter , path:: String )
55 bytes = read (path)
66 stream = ParseStream (bytes)
7+ line_starts = Int32[Int32 (i) for (i, x) in enumerate (bytes) if x == 0x0a ] # :(
78 tls = task_local_storage ()
89 tls[:SOURCE_PATH ] = path # This is also done by Base.include
910 try
@@ -13,11 +14,12 @@ function include_test_file(ti_filter::TestItemFilter, path::String)
1314 k = kind (t)
1415 k == K " EndMarker" && break
1516 if k == K " @"
17+ line = searchsortedfirst (line_starts, last_byte (stream))
1618 tf = peek_full_token (stream, 2 )
1719 v = @inbounds @view (bytes[tf. first_byte: tf. last_byte])
18- if v == b " testitem" ; _eval_from_stream (stream, path, ti_filter, bytes)
19- elseif v == b " testsetup" ; _eval_from_stream (stream, path)
20- elseif v == b " test_rel" ; _eval_from_stream (stream, path, ti_filter)
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)
2123 else
2224 error (" Test files must only include `@testitem` and `@testsetup` calls, got an `@$(StringView (v)) ` at $(path) " ) # TODO
2325 end
@@ -35,17 +37,17 @@ _contains(s::AbstractString, pattern::Regex) = occursin(pattern, s)
3537_contains (s:: AbstractString , pattern:: AbstractString ) = s == pattern
3638
3739# unconditionally eval
38- function _eval_from_stream (stream, path)
40+ function _eval_from_stream (stream, path, line )
3941 parse! (stream; rule= :statement )
40- ast = build_tree (Expr, stream; filename= path)
42+ ast = build_tree (Expr, stream; filename= path, first_line = line )
4143 Core. eval (Main, ast)
4244 return nothing
4345end
4446
4547# test_rel -> apply ti_filter on the parsed ast
46- function _eval_from_stream (stream, path, ti_filter:: TestItemFilter )
48+ function _eval_from_stream (stream, path, line, ti_filter:: TestItemFilter )
4749 parse! (stream; rule= :statement )
48- ast = build_tree (Expr, stream; filename= path)
50+ ast = build_tree (Expr, stream; filename= path, first_line = line )
4951 any_error (stream) && throw (ParseError (stream, filename= path))
5052 filtered = __filter_rai (ti_filter, ast):: Union{Nothing, Expr}
5153 filtered === nothing || Core. eval (Main, filtered:: Expr )
5456
5557# like above, but tries to avoid parsing the ast if it sees from the name identifier token
5658# it won't pass the filter
57- function _eval_from_stream (stream, path, ti_filter:: TestItemFilter , bytes)
59+ function _eval_from_stream (stream, path, line, ti_filter:: TestItemFilter , bytes)
5860 if ti_filter. name isa Nothing
5961 parse! (stream; rule= :statement )
60- ast = build_tree (Expr, stream; filename= path)
62+ ast = build_tree (Expr, stream; filename= path, first_line = line )
6163 any_error (stream) && throw (ParseError (stream, filename= path))
6264 filtered = __filter_ti (ti_filter, ast):: Union{Nothing, Expr}
6365 filtered === nothing || Core. eval (Main, filtered:: Expr )
@@ -68,7 +70,7 @@ function _eval_from_stream(stream, path, ti_filter::TestItemFilter, bytes)
6870 name = @inbounds StringView (@view (bytes[name_t. first_byte: name_t. last_byte]))
6971 parse! (stream; rule= :statement )
7072 if _contains (name, ti_filter. name)
71- ast = build_tree (Expr, stream; filename= path)
73+ ast = build_tree (Expr, stream; filename= path, first_line = line )
7274 any_error (stream) && throw (ParseError (stream, filename= path))
7375 filtered = __filter_ti (ti_filter, ast):: Union{Nothing, Expr}
7476 filtered === nothing || Core. eval (Main, filtered:: Expr )
0 commit comments