diff --git a/base/client.jl b/base/client.jl index 223670eebe7ea..63425d9acbdaa 100644 --- a/base/client.jl +++ b/base/client.jl @@ -207,12 +207,12 @@ function syntax_deprecation_warnings(f::Function, warn::Bool) end function parse_input_line(s::String; filename::String="none") - # (expr, pos) = parse(s, 1) + # (expr, pos) = Meta.parse(s, 1) # (ex, pos) = ccall(:jl_parse_string, Any, # (Ptr{UInt8},Csize_t,Int32,Int32), # s, sizeof(s), pos-1, 1) # if ex!==() - # throw(ParseError("extra input after end of expression")) + # throw(Meta.ParseError("extra input after end of expression")) # end # expr ex = ccall(:jl_parse_input_line, Any, (Ptr{UInt8}, Csize_t, Ptr{UInt8}, Csize_t), diff --git a/base/deprecated.jl b/base/deprecated.jl index ee81e772f9360..0f25fdf9c42e3 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -2073,6 +2073,11 @@ end # issue #24167 @deprecate EnvHash EnvDict +# issue #24349 +@deprecate parse(str::AbstractString; kwargs...) Meta.parse(str; kwargs...) +@deprecate parse(str::AbstractString, pos::Int, ; kwargs...) Meta.parse(str, pos; kwargs...) +@deprecate_binding ParseError Meta.ParseError + # #24258 # Physical units define an equivalence class: there is no such thing as a step of "1" (is # it one day or one second or one nanosecond?). So require the user to specify the step diff --git a/base/docs/utils.jl b/base/docs/utils.jl index f8739ca27cbf9..5daaa068a7893 100644 --- a/base/docs/utils.jl +++ b/base/docs/utils.jl @@ -103,7 +103,7 @@ function helpmode(io::IO, line::AbstractString) Symbol(line) else x = Base.syntax_deprecation_warnings(false) do - parse(line, raise = false) + Meta.parse(line, raise = false) end # Retrieving docs for macros requires us to make a distinction between the text # `@macroname` and `@macroname()`. These both parse the same, but are used by diff --git a/base/markdown/Julia/interp.jl b/base/markdown/Julia/interp.jl index a1d0a4d7e3722..ca78f3a41a17a 100644 --- a/base/markdown/Julia/interp.jl +++ b/base/markdown/Julia/interp.jl @@ -1,8 +1,8 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -function Base.parse(stream::IO; greedy::Bool = true, raise::Bool = true) +function _parse(stream::IO; greedy::Bool = true, raise::Bool = true) pos = position(stream) - ex, Δ = Base.parse(read(stream, String), 1, greedy = greedy, raise = raise) + ex, Δ = Meta.parse(read(stream, String), 1, greedy = greedy, raise = raise) seek(stream, pos + Δ - 1) return ex end @@ -11,7 +11,7 @@ function interpinner(stream::IO, greedy = false) startswith(stream, '$') || return (eof(stream) || Char(peek(stream)) in whitespace) && return try - return Base.parse(stream::IOBuffer, greedy = greedy) + return _parse(stream::IOBuffer, greedy = greedy) catch e return end diff --git a/base/meta.jl b/base/meta.jl index 0a50234c03a18..49b731f024744 100644 --- a/base/meta.jl +++ b/base/meta.jl @@ -79,4 +79,89 @@ macro lower(mod, code) return :(lower($(esc(mod)), $(QuoteNode(code)))) end + +## interface to parser ## + +""" + ParseError(msg) + +The expression passed to the `parse` function could not be interpreted as a valid Julia +expression. +""" +struct ParseError <: Exception + msg::AbstractString +end + +""" + parse(str, start; greedy=true, raise=true) + +Parse the expression string and return an expression (which could later be passed to eval +for execution). `start` is the index of the first character to start parsing. If `greedy` is +`true` (default), `parse` will try to consume as much input as it can; otherwise, it will +stop as soon as it has parsed a valid expression. Incomplete but otherwise syntactically +valid expressions will return `Expr(:incomplete, "(error message)")`. If `raise` is `true` +(default), syntax errors other than incomplete expressions will raise an error. If `raise` +is `false`, `parse` will return an expression that will raise an error upon evaluation. + +```jldoctest +julia> Meta.parse("x = 3, y = 5", 7) +(:(y = 5), 13) + +julia> Meta.parse("x = 3, y = 5", 5) +(:((3, y) = 5), 13) +``` +""" +function parse(str::AbstractString, pos::Int; greedy::Bool=true, raise::Bool=true) + # pos is one based byte offset. + # returns (expr, end_pos). expr is () in case of parse error. + bstr = String(str) + ex, pos = ccall(:jl_parse_string, Any, + (Ptr{UInt8}, Csize_t, Int32, Int32), + bstr, sizeof(bstr), pos-1, greedy ? 1 : 0) + if raise && isa(ex,Expr) && ex.head === :error + throw(ParseError(ex.args[1])) + end + if ex === () + raise && throw(ParseError("end of input")) + ex = Expr(:error, "end of input") + end + return ex, pos+1 # C is zero-based, Julia is 1-based +end + +""" + parse(str; raise=true) + +Parse the expression string greedily, returning a single expression. An error is thrown if +there are additional characters after the first expression. If `raise` is `true` (default), +syntax errors will raise an error; otherwise, `parse` will return an expression that will +raise an error upon evaluation. + +```jldoctest +julia> Meta.parse("x = 3") +:(x = 3) + +julia> Meta.parse("x = ") +:($(Expr(:incomplete, "incomplete: premature end of input"))) + +julia> Meta.parse("1.0.2") +ERROR: ParseError("invalid numeric constant \\\"1.0.\\\"") +Stacktrace: +[...] + +julia> Meta.parse("1.0.2"; raise = false) +:($(Expr(:error, "invalid numeric constant \"1.0.\""))) +``` +""" +function parse(str::AbstractString; raise::Bool=true) + ex, pos = parse(str, 1, greedy=true, raise=raise) + if isa(ex,Expr) && ex.head === :error + return ex + end + if !done(str, pos) + raise && throw(ParseError("extra token after end of expression")) + return Expr(:error, "extra token after end of expression") + end + return ex +end + end # module diff --git a/base/parse.jl b/base/parse.jl index d9de42393bfeb..d4fbff975321d 100644 --- a/base/parse.jl +++ b/base/parse.jl @@ -236,86 +236,3 @@ function parse(::Type{T}, s::AbstractString) where T<:AbstractFloat return unsafe_get(result) end -## interface to parser ## - -""" - ParseError(msg) - -The expression passed to the `parse` function could not be interpreted as a valid Julia -expression. -""" -struct ParseError <: Exception - msg::AbstractString -end - -""" - parse(str, start; greedy=true, raise=true) - -Parse the expression string and return an expression (which could later be passed to eval -for execution). `start` is the index of the first character to start parsing. If `greedy` is -`true` (default), `parse` will try to consume as much input as it can; otherwise, it will -stop as soon as it has parsed a valid expression. Incomplete but otherwise syntactically -valid expressions will return `Expr(:incomplete, "(error message)")`. If `raise` is `true` -(default), syntax errors other than incomplete expressions will raise an error. If `raise` -is `false`, `parse` will return an expression that will raise an error upon evaluation. - -```jldoctest -julia> parse("x = 3, y = 5", 7) -(:(y = 5), 13) - -julia> parse("x = 3, y = 5", 5) -(:((3, y) = 5), 13) -``` -""" -function parse(str::AbstractString, pos::Int; greedy::Bool=true, raise::Bool=true) - # pos is one based byte offset. - # returns (expr, end_pos). expr is () in case of parse error. - bstr = String(str) - ex, pos = ccall(:jl_parse_string, Any, - (Ptr{UInt8}, Csize_t, Int32, Int32), - bstr, sizeof(bstr), pos-1, greedy ? 1 : 0) - if raise && isa(ex,Expr) && ex.head === :error - throw(ParseError(ex.args[1])) - end - if ex === () - raise && throw(ParseError("end of input")) - ex = Expr(:error, "end of input") - end - return ex, pos+1 # C is zero-based, Julia is 1-based -end - -""" - parse(str; raise=true) - -Parse the expression string greedily, returning a single expression. An error is thrown if -there are additional characters after the first expression. If `raise` is `true` (default), -syntax errors will raise an error; otherwise, `parse` will return an expression that will -raise an error upon evaluation. - -```jldoctest -julia> parse("x = 3") -:(x = 3) - -julia> parse("x = ") -:($(Expr(:incomplete, "incomplete: premature end of input"))) - -julia> parse("1.0.2") -ERROR: ParseError("invalid numeric constant \\\"1.0.\\\"") -Stacktrace: -[...] - -julia> parse("1.0.2"; raise = false) -:($(Expr(:error, "invalid numeric constant \"1.0.\""))) -``` -""" -function parse(str::AbstractString; raise::Bool=true) - ex, pos = parse(str, 1, greedy=true, raise=raise) - if isa(ex,Expr) && ex.head === :error - return ex - end - if !done(str, pos) - raise && throw(ParseError("extra token after end of expression")) - return Expr(:error, "extra token after end of expression") - end - return ex -end diff --git a/base/repl/REPL.jl b/base/repl/REPL.jl index b14a8a9c1427a..72203878b1696 100644 --- a/base/repl/REPL.jl +++ b/base/repl/REPL.jl @@ -895,7 +895,7 @@ function setup_interface( end end ast, pos = Base.syntax_deprecation_warnings(false) do - Base.parse(input, oldpos, raise=false) + Meta.parse(input, oldpos, raise=false) end if (isa(ast, Expr) && (ast.head == :error || ast.head == :continue || ast.head == :incomplete)) || (done(input, pos) && !endswith(input, '\n')) diff --git a/base/repl/REPLCompletions.jl b/base/repl/REPLCompletions.jl index d757da88ed82c..5523ab544ca3d 100644 --- a/base/repl/REPLCompletions.jl +++ b/base/repl/REPLCompletions.jl @@ -45,7 +45,7 @@ function complete_symbol(sym, ffunc) lookup_name, name = rsplit(sym, ".", limit=2) ex = Base.syntax_deprecation_warnings(false) do - parse(lookup_name, raise=false) + Meta.parse(lookup_name, raise=false) end b, found = get_value(ex, context_module) @@ -479,7 +479,7 @@ function completions(string, pos) # First parse everything up to the current position partial = string[1:pos] inc_tag = Base.syntax_deprecation_warnings(false) do - Base.incomplete_tag(parse(partial, raise=false)) + Base.incomplete_tag(Meta.parse(partial, raise=false)) end # if completing a key in a Dict @@ -527,7 +527,7 @@ function completions(string, pos) if inc_tag == :other && should_method_complete(partial) frange, method_name_end = find_start_brace(partial) ex = Base.syntax_deprecation_warnings(false) do - parse(partial[frange] * ")", raise=false) + Meta.parse(partial[frange] * ")", raise=false) end if isa(ex, Expr) && ex.head==:call return complete_methods(ex), start(frange):method_name_end, false diff --git a/base/shell.jl b/base/shell.jl index 32b0845db6e7e..b8923ced43d04 100644 --- a/base/shell.jl +++ b/base/shell.jl @@ -75,7 +75,7 @@ function shell_parse(str::AbstractString, interpolate::Bool=true; error("space not allowed right after \$") end stpos = j - ex, j = parse(s,j,greedy=false) + ex, j = Meta.parse(s,j,greedy=false) last_parse = stpos:j update_arg(ex); i = j else diff --git a/base/show.jl b/base/show.jl index aeb5d3bc73c01..1f6fd407b3a9f 100644 --- a/base/show.jl +++ b/base/show.jl @@ -509,8 +509,8 @@ show(io::IO, s::Symbol) = show_unquoted_quote_expr(io, s, 0, 0) # show_unquoted(io, ex) does the heavy lifting # # AST printing should follow two rules: -# 1. parse(string(ex)) == ex -# 2. eval(parse(repr(ex))) == ex +# 1. Meta.parse(string(ex)) == ex +# 2. eval(Meta.parse(repr(ex))) == ex # # Rule 1 means that printing an expression should generate Julia code which # could be reparsed to obtain the original expression. This code should be @@ -521,8 +521,8 @@ show(io::IO, s::Symbol) = show_unquoted_quote_expr(io, s, 0, 0) # original expression. # # This is consistent with many other show methods, i.e.: -# show(Set([1,2,3])) # ==> "Set{Int64}([2,3,1])" -# eval(parse("Set{Int64}([2,3,1])”) # ==> An actual set +# show(Set([1,2,3])) # ==> "Set{Int64}([2,3,1])" +# eval(Meta.parse("Set{Int64}([2,3,1])”) # ==> An actual set # While this isn’t true of ALL show methods, it is of all ASTs. const ExprNode = Union{Expr, QuoteNode, Slot, LineNumberNode, diff --git a/doc/src/manual/metaprogramming.md b/doc/src/manual/metaprogramming.md index a7b4e414949e6..fc16eed1b7010 100644 --- a/doc/src/manual/metaprogramming.md +++ b/doc/src/manual/metaprogramming.md @@ -26,7 +26,7 @@ The next step is to [parse](https://en.wikipedia.org/wiki/Parsing#Computer_langu into an object called an expression, represented by the Julia type `Expr`: ```jldoctest prog -julia> ex1 = parse(prog) +julia> ex1 = Meta.parse(prog) :(1 + 1) julia> typeof(ex1) @@ -86,7 +86,7 @@ Expr `Expr` objects may also be nested: ```jldoctest ex3 -julia> ex3 = parse("(4 + 4) / 2") +julia> ex3 = Meta.parse("(4 + 4) / 2") :((4 + 4) / 2) ``` @@ -160,12 +160,12 @@ Expr (to view the structure of this expression, try `ex.head` and `ex.args`, or use [`dump`](@ref) as above or [`Meta.@dump`](@ref)) -Note that equivalent expressions may be constructed using [`parse`](@ref) or the direct `Expr` +Note that equivalent expressions may be constructed using [`Meta.parse`](@ref) or the direct `Expr` form: ```jldoctest -julia> :(a + b*c + 1) == - parse("a + b*c + 1") == +julia> :(a + b*c + 1) == + Meta.parse("a + b*c + 1") == Expr(:call, :+, :a, Expr(:call, :*, :b, :c), 1) true ``` @@ -314,7 +314,7 @@ equivalent of `eval(eval(:x))`. The usual representation of a `quote` form in an AST is an `Expr` with head `:quote`: ```jldoctest interp1 -julia> dump(parse(":(1+2)")) +julia> dump(Meta.parse(":(1+2)")) Expr head: Symbol quote args: Array{Any}((1,)) @@ -335,7 +335,7 @@ as an object of type `QuoteNode`. The parser yields `QuoteNode`s for simple quoted items like symbols: ```jldoctest interp1 -julia> dump(parse(":x")) +julia> dump(Meta.parse(":x")) QuoteNode value: Symbol x ``` diff --git a/doc/src/stdlib/base.md b/doc/src/stdlib/base.md index 96642c37c88ff..c65875e8be06b 100644 --- a/doc/src/stdlib/base.md +++ b/doc/src/stdlib/base.md @@ -211,8 +211,6 @@ Base.@gensym Base.@goto Base.@label Base.@polly -Base.parse(::AbstractString, ::Int) -Base.parse(::AbstractString) ``` ## Nullables @@ -343,6 +341,8 @@ Base.gc Base.gc_enable Meta.lower Meta.@lower +Meta.parse(::AbstractString, ::Int) +Meta.parse(::AbstractString) Base.macroexpand Base.@macroexpand Base.@macroexpand1 diff --git a/test/choosetests.jl b/test/choosetests.jl index 77f1407b9ec11..cfb0a3d08a6f0 100644 --- a/test/choosetests.jl +++ b/test/choosetests.jl @@ -49,7 +49,7 @@ function choosetests(choices = []) "checked", "bitset", "floatfuncs", "compile", "distributed", "inline", "boundscheck", "error", "ambiguous", "cartesian", "asmvariant", "osutils", "channels", "iostream", "specificity", "codegen", "codevalidation", - "reinterpretarray" + "reinterpretarray", "syntax" ] if isdir(joinpath(JULIA_HOME, Base.DOCDIR, "examples")) diff --git a/test/docs.jl b/test/docs.jl index bf78c055d71fd..60ac4a5349e2b 100644 --- a/test/docs.jl +++ b/test/docs.jl @@ -924,15 +924,15 @@ let x = Binding(curmod, :bindingdoesnotexist) end let x = Binding(Main, :+) - @test parse(string(x)) == :(Base.:+) + @test Meta.parse(string(x)) == :(Base.:+) end -let x = Binding(Base, :parse) - @test parse(string(x)) == :(Base.parse) +let x = Binding(Meta, :parse) + @test Meta.parse(string(x)) == :(Base.Meta.parse) end let x = Binding(Main, :⊕) - @test parse(string(x)) == :(⊕) + @test Meta.parse(string(x)) == :(⊕) end doc_util_path = Symbol(joinpath("docs", "utils.jl")) diff --git a/test/namedtuple.jl b/test/namedtuple.jl index 42423da7a96b4..4c0076f3e7b85 100644 --- a/test/namedtuple.jl +++ b/test/namedtuple.jl @@ -108,14 +108,14 @@ end # syntax errors -@test Meta.lower(Main, parse("(a=1, 0)")) == Expr(:error, "invalid named tuple element \"0\"") -@test Meta.lower(Main, parse("(a=1, f(x))")) == Expr(:error, "invalid named tuple element \"f(x)\"") -@test Meta.lower(Main, parse("(a=1,a=2)")) == Expr(:error, "field name \"a\" repeated in named tuple") -@test Meta.lower(Main, parse("(a=1,b=0,a=2)")) == Expr(:error, "field name \"a\" repeated in named tuple") -@test Meta.lower(Main, parse("(c=1,a=1,b=0,a=2)")) == Expr(:error, "field name \"a\" repeated in named tuple") - -@test parse("(;)") == quote end -@test Meta.lower(Main, parse("(1,;2)")) == Expr(:error, "unexpected semicolon in tuple") +@test Meta.lower(Main, Meta.parse("(a=1, 0)")) == Expr(:error, "invalid named tuple element \"0\"") +@test Meta.lower(Main, Meta.parse("(a=1, f(x))")) == Expr(:error, "invalid named tuple element \"f(x)\"") +@test Meta.lower(Main, Meta.parse("(a=1,a=2)")) == Expr(:error, "field name \"a\" repeated in named tuple") +@test Meta.lower(Main, Meta.parse("(a=1,b=0,a=2)")) == Expr(:error, "field name \"a\" repeated in named tuple") +@test Meta.lower(Main, Meta.parse("(c=1,a=1,b=0,a=2)")) == Expr(:error, "field name \"a\" repeated in named tuple") + +@test Meta.parse("(;)") == quote end +@test Meta.lower(Main, Meta.parse("(1,;2)")) == Expr(:error, "unexpected semicolon in tuple") # splatting diff --git a/test/numbers.jl b/test/numbers.jl index 10223931edf56..b610076b17fa5 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -1816,7 +1816,7 @@ end @test isa(0b00000000000000000000000000000000000000000000000000000000000000000,UInt128) @test isa(0b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,UInt128) # remove BigInt unsigned integer literals #11105 - @test_throws ParseError parse("0b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") + @test_throws Meta.ParseError Meta.parse("0b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") @test isa(0b11111111,UInt8) @test isa(0b111111111,UInt16) @test isa(0b1111111111111111,UInt16) @@ -1827,7 +1827,7 @@ end @test isa(0b11111111111111111111111111111111111111111111111111111111111111111,UInt128) @test isa(0b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111,UInt128) # remove BigInt unsigned integer literals #11105 - @test_throws ParseError parse("0b111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") + @test_throws Meta.ParseError Meta.parse("0b111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") end @testset "octal literals" begin @test 0o10 == 0x8 @@ -1845,7 +1845,7 @@ end @test isa(0o0000000000000000000000,UInt128) @test isa(0o000000000000000000000000000000000000000000,UInt128) # remove BigInt unsigned integer literals #11105 - @test_throws ParseError parse("0o0000000000000000000000000000000000000000000") + @test_throws Meta.ParseError Meta.parse("0o0000000000000000000000000000000000000000000") @test isa(0o11,UInt8) @test isa(0o111,UInt8) @test isa(0o11111,UInt16) @@ -1857,7 +1857,7 @@ end @test isa(0o111111111111111111111111111111111111111111,UInt128) @test isa(0o1111111111111111111111111111111111111111111,UInt128) # remove BigInt unsigned integer literals #11105 - @test_throws ParseError parse("0o11111111111111111111111111111111111111111111") + @test_throws Meta.ParseError Meta.parse("0o11111111111111111111111111111111111111111111") end @testset "hexadecimal literals" begin @test isa(0x00,UInt8) @@ -1870,7 +1870,7 @@ end @test isa(0x00000000000000000,UInt128) @test isa(0x00000000000000000000000000000000,UInt128) # remove BigInt unsigned integer literals #11105 - @test_throws ParseError parse("0x000000000000000000000000000000000") + @test_throws Meta.ParseError Meta.parse("0x000000000000000000000000000000000") @test isa(0x11,UInt8) @test isa(0x111,UInt16) @@ -1882,7 +1882,7 @@ end @test isa(0x11111111111111111,UInt128) @test isa(0x11111111111111111111111111111111,UInt128) # remove BigInt unsigned integer literals #11105 - @test_throws ParseError parse("0x111111111111111111111111111111111") + @test_throws Meta.ParseError Meta.parse("0x111111111111111111111111111111111") end @testset "minus sign and unsigned literals" begin # "-" is not part of unsigned literals @@ -1902,7 +1902,7 @@ end @test isa(-0x00000000000000000,UInt128) @test isa(-0x00000000000000000000000000000000,UInt128) # remove BigInt unsigned integer literals #11105 - @test_throws ParseError parse("-0x000000000000000000000000000000000") + @test_throws Meta.ParseError Meta.parse("-0x000000000000000000000000000000000") end @testset "Float32 literals" begin @test isa(1f0,Float32) diff --git a/test/parse.jl b/test/parse.jl index b2bc7d0d020e5..e338020bf0f72 100644 --- a/test/parse.jl +++ b/test/parse.jl @@ -1,176 +1,5 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -# tests for parser and syntax lowering - -function parseall(str) - pos = start(str) - exs = [] - while !done(str, pos) - ex, pos = parse(str, pos) - push!(exs, ex) - end - if length(exs) == 0 - throw(ParseError("end of input")) - elseif length(exs) == 1 - return exs[1] - else - return Expr(:block, exs...) - end -end - -# issue #9684 -let - undot(op) = Symbol(string(op)[2:end]) - for (ex1, ex2) in [("5 .≠ x", "5 .!= x"), - ("5 .≥ x", "5 .>= x"), - ("5 .≤ x", "5 .<= x")] - ex1 = parse(ex1); ex2 = parse(ex2) - @test ex1.head === :call && (ex1.head === ex2.head) - @test ex1.args[2] === 5 && ex2.args[2] === 5 - @test eval(Main, undot(ex1.args[1])) === eval(Main, undot(ex2.args[1])) - @test ex1.args[3] === :x && (ex1.args[3] === ex2.args[3]) - end -end - -# issue #9704 -let a = :a - @test :(try - catch $a - end) == :(try - catch a - end) - @test :(module $a end) == :(module a - end) -end - -# string literals -macro test999_str(args...); args; end -@test test999"a"b == ("a","b") -@test test999"""a"""b == ("a","b") -@test test999" - a - b" == (" - a - b",) -@test test999""" - a - b""" == ("a\nb",) - -# issue #5997 -@test_throws ParseError parse(": x") -@test_throws ParseError parse("d[: 2]") - -# issue #6770 -@test_throws ParseError parse("x.3") - -# issue #8763 -@test_throws ParseError parse("sqrt(16)2") -@test_throws ParseError parse("x' y") -@test_throws ParseError parse("x 'y") -@test parse("x'y") == Expr(:call, :*, Expr(Symbol("'"), :x), :y) - -# issue #8301 -@test_throws ParseError parse("&*s") - -# issue #10677 -@test_throws ParseError parse("/1") -@test_throws ParseError parse("/pi") -@test parse("- = 2") == Expr(:(=), :(-), 2) -@test parse("/ = 2") == Expr(:(=), :(/), 2) -@test_throws ParseError parse("< : 2") -@test_throws ParseError parse("+ : 2") -@test_throws ParseError parse("< :2") -@test parse("+ :2") == Expr(:call, :(+), QuoteNode(2)) - -# issue #10900 -@test_throws ParseError parse("+=") -@test_throws ParseError parse(".") -@test_throws ParseError parse("...") - -# issue #10901 -@test parse("/([1], 1)[1]") == :(([1] / 1)[1]) - -# issue #10997 -@test parse(":(x.\$f[i])") == Expr(:quote, - Expr(:ref, - Expr(Symbol("."), :x, - QuoteNode(Expr(:$, :f))), - :i)) - -# issue #10994 -@test parse("1 + #= \0 =# 2") == :(1 + 2) - -# issue #10910 -@test parse(":(using A)") == Expr(:quote, Expr(:using, :A)) -@test parse(":(using A.b, B)") == Expr(:quote, - Expr(:toplevel, - Expr(:using, :A, :b), - Expr(:using, :B))) -@test parse(":(using A: b, c.d)") == Expr(:quote, - Expr(:toplevel, - Expr(:using, :A, :b), - Expr(:using, :A, :c, :d))) - -@test parse(":(import A)") == Expr(:quote, Expr(:import, :A)) -@test parse(":(import A.b, B)") == Expr(:quote, - Expr(:toplevel, - Expr(:import, :A, :b), - Expr(:import, :B))) -@test parse(":(import A: b, c.d)") == Expr(:quote, - Expr(:toplevel, - Expr(:import, :A, :b), - Expr(:import, :A, :c, :d))) - -# issue #11332 -@test parse("export \$(Symbol(\"A\"))") == :(export $(Expr(:$, :(Symbol("A"))))) -@test parse("export \$A") == :(export $(Expr(:$, :A))) -@test parse("using \$a.\$b") == Expr(:using, Expr(:$, :a), Expr(:$, :b)) -@test parse("using \$a.\$b, \$c") == Expr(:toplevel, Expr(:using, Expr(:$, :a), - Expr(:$, :b)), - Expr(:using, Expr(:$, :c))) -@test parse("using \$a: \$b, \$c.\$d") == - Expr(:toplevel, Expr(:using, Expr(:$, :a), Expr(:$, :b)), - Expr(:using, Expr(:$, :a), Expr(:$, :c), Expr(:$, :d))) - -# fix pr #11338 and test for #11497 -@test parseall("using \$\na") == Expr(:block, Expr(:using, :$), :a) -@test parseall("using \$,\na") == Expr(:toplevel, Expr(:using, :$), - Expr(:using, :a)) -@test parseall("using &\na") == Expr(:block, Expr(:using, :&), :a) - -@test parseall("a = &\nb") == Expr(:block, Expr(:(=), :a, :&), :b) -@test parseall("a = \$\nb") == Expr(:block, Expr(:(=), :a, :$), :b) -@test parseall(":(a = &\nb)") == Expr(:quote, Expr(:(=), :a, Expr(:&, :b))) -@test parseall(":(a = \$\nb)") == Expr(:quote, Expr(:(=), :a, Expr(:$, :b))) - -# issue 11970 -@test parseall(""" - macro f(args...) end; @f "macro argument" -""") == Expr(:toplevel, - Expr(:macro, Expr(:call, :f, Expr(:..., :args)), Expr(:block, LineNumberNode(1, :none))), - Expr(:macrocall, Symbol("@f"), LineNumberNode(1, :none), "macro argument")) - -# blocks vs. tuples -@test parse("()") == Expr(:tuple) -@test parse("(;)") == Expr(:block) -@test parse("(;;;;)") == Expr(:block) -@test_throws ParseError parse("(,)") -@test_throws ParseError parse("(;,)") -@test_throws ParseError parse("(,;)") -@test parse("(x;)") == Expr(:block, :x) -@test parse("(;x)") == Expr(:tuple, Expr(:parameters, :x)) -@test parse("(;x,)") == Expr(:tuple, Expr(:parameters, :x)) -@test parse("(x,)") == Expr(:tuple, :x) -@test parse("(x,;)") == Expr(:tuple, :x) -@test parse("(x;y)") == Expr(:block, :x, :y) -@test parse("(x=1;y=2)") == Expr(:block, Expr(:(=), :x, 1), Expr(:(=), :y, 2)) -@test parse("(x,;y)") == Expr(:tuple, Expr(:parameters, :y), :x) -@test parse("(x,;y=1)") == Expr(:tuple, Expr(:parameters, Expr(:kw, :y, 1)), :x) -@test parse("(x,a;y=1)") == Expr(:tuple, Expr(:parameters, Expr(:kw, :y, 1)), :x, :a) -@test parse("(x,a;y=1,z=2)") == Expr(:tuple, Expr(:parameters, Expr(:kw,:y,1), Expr(:kw,:z,2)), :x, :a) -@test parse("(a=1, b=2)") == Expr(:tuple, Expr(:(=), :a, 1), Expr(:(=), :b, 2)) -@test_throws ParseError parse("(1 2)") # issue #15248 - # integer parsing @test parse(Int32,"0",36) === Int32(0) @test parse(Int32,"1",36) === Int32(1) @@ -340,18 +169,6 @@ parsehex(s) = parse(Int,s,16) @test_throws ArgumentError parse(Int,"2x") @test_throws ArgumentError parse(Int,"-") -# parsing numbers with _ and . -@test parse("1_2.3_4") == 12.34 -@test_throws ParseError parse("1._") -@test_throws ParseError parse("1._5") -@test_throws ParseError parse("1e.3") -@test_throws ParseError parse("1e3.") -@test parse("2e_1") == Expr(:call, :*, 2, :e_1) -# issue #17705 -@test parse("2e3_") == Expr(:call, :*, 2e3, :_) -@test parse("2e-3_") == Expr(:call, :*, 2e-3, :_) -@test parse("2e3_\"x\"") == Expr(:call, :*, 2e3, Expr(:macrocall, Symbol("@__str"), LineNumberNode(1, :none), "x")) - # multibyte spaces @test parse(Int, "3\u2003\u202F") == 3 @test_throws ArgumentError parse(Int, "3\u2003\u202F,") @@ -382,270 +199,7 @@ for T in (UInt8,UInt16,UInt32,UInt64,UInt128) @test_throws OverflowError parse(T,string(big(typemax(T))+1)) end -@test parse("1 == 2|>3") == Expr(:call, :(==), 1, Expr(:call, :(|>), 2, 3)) - -# issue #24153 -@test parse("a|>b|>c|>d") == parse("((a|>b)|>c)|>d") -@test parse("a<|b<|c<|d") == parse("a<|(b<|(c<|d))") - -# issue #12501 and pr #12502 -parse(""" - baremodule A - "a" in b - end - """) -parse(""" - baremodule A - "a" - end - """) - -# issue #12626 -@test parse("a .÷ 1") == Expr(:call, :.÷, :a, 1) -@test parse("a .÷= 1") == Expr(:.÷=, :a, 1) - -# issue #12771 -@test -(3)^2 == -9 - -# issue #13302 -let p = parse("try - a - catch - b, c = t - end") - @test isa(p,Expr) && p.head === :try - @test p.args[2] === false - @test p.args[3].args[end] == parse("b,c = t") -end - -# pr #13078 -@test parse("a in b in c") == Expr(:comparison, :a, :in, :b, :in, :c) -@test parse("a||b→c&&d") == Expr(:call, :→, - Expr(Symbol("||"), :a, :b), - Expr(Symbol("&&"), :c, :d)) - -# issue #11988 -- normalize \r and \r\n in literal strings to \n -@test "foo\nbar" == parse("\"\"\"\r\nfoo\r\nbar\"\"\"") == - parse("\"\"\"\nfoo\nbar\"\"\"") == parse("\"\"\"\rfoo\rbar\"\"\"") == - parse("\"foo\r\nbar\"") == parse("\"foo\rbar\"") == parse("\"foo\nbar\"") -@test '\r' == first("\r") == first("\r\n") # still allow explicit \r - -# issue #14561 - generating 0-method generic function def -let fname = :f - @test :(function $fname end) == Expr(:function, :f) -end - -# issue #14977 -@test parse("x = 1", 1) == (:(x = 1), 6) -@test parse("x = 1", 6) == (nothing, 6) -@test_throws BoundsError parse("x = 1", 0) -@test_throws BoundsError parse("x = 1", -1) -@test_throws BoundsError parse("x = 1", 7) - -# issue #14683 -@test_throws ParseError parse("'\\A\"'") -@test parse("'\"'") == parse("'\\\"'") == '"' == "\""[1] == '\42' - -@test_throws ParseError parse("f(2x for x=1:10, y") - -# issue #15223 -call0(f) = f() -call1(f,x) = f(x) -call2(f,x,y) = f(x,y) -@test (call0() do; 42 end) == 42 -@test (call1(42) do x; x+1 end) == 43 -@test (call2(42,1) do x,y; x+y+1 end) == 44 - -# definitions using comparison syntax -let a⊂b = reduce(&, x ∈ b for x in a) && length(b)>length(a) - @test [1,2] ⊂ [1,2,3,4] - @test !([1,2] ⊂ [1,3,4]) - @test !([1,2] ⊂ [1,2]) -end - -# issue #9503 -@test parse("x<:y") == Expr(:(<:), :x, :y) -@test parse("x>:y") == Expr(:(>:), :x, :y) -@test parse("x<:y<:z").head === :comparison -@test parse("x>:y<:z").head === :comparison - -# reason PR #19765, <- operator, was reverted -@test -2<-1 # DO NOT ADD SPACES - -# issue #11169 -uncalled(x) = @test false -fret() = uncalled(return true) -@test fret() - -# issue #9617 -let p = 15 - @test 2p+1 == 31 # not a hex float literal -end - # issue #15597 -function test_parseerror(str, msg) - try - parse(str) - @test false - catch e - @test isa(e,ParseError) && e.msg == msg - end -end -test_parseerror("0x", "invalid numeric constant \"0x\"") -test_parseerror("0b", "invalid numeric constant \"0b\"") -test_parseerror("0o", "invalid numeric constant \"0o\"") -test_parseerror("0x0.1", "hex float literal must contain \"p\" or \"P\"") -test_parseerror("0x1.0p", "invalid numeric constant \"0x1.0\"") - -# issue #15798 -@test Meta.lower(Main, Base.parse_input_line(""" - try = "No" - """)) == Expr(:error, "unexpected \"=\"") - -# issue #19861 make sure macro-expansion happens in the newest world for top-level expression -@test eval(Base.parse_input_line(""" - macro X19861() - return 23341 - end - @X19861 - """)::Expr) == 23341 - -# test parse_input_line for a streaming IO input -let b = IOBuffer(""" - let x = x - x - end - f() - """) - @test Base.parse_input_line(b) == Expr(:let, Expr(:(=), :x, :x), Expr(:block, LineNumberNode(2, :none), :x)) - @test Base.parse_input_line(b) == Expr(:call, :f) - @test Base.parse_input_line(b) === nothing -end - -# issue #15763 -test_parseerror("if\nfalse\nend", "missing condition in \"if\" at none:1") -test_parseerror("if false\nelseif\nend", "missing condition in \"elseif\" at none:2") - -# issue #15828 -@test Meta.lower(Main, parse("x...")) == Expr(:error, "\"...\" expression outside call") - -# issue #15830 -@test Meta.lower(Main, parse("foo(y = (global x)) = y")) == Expr(:error, "misplaced \"global\" declaration") - -# issue #15844 -function f15844(x) - x -end - -g15844 = let - local function f15844(x::Int32) - 2x - end -end - -function add_method_to_glob_fn!() - global function f15844(x::Int64) - 3x - end -end - -add_method_to_glob_fn!() -@test g15844 !== f15844 -@test g15844(Int32(1)) == 2 -@test f15844(Int32(1)) == 1 -@test f15844(Int64(1)) == 3 - -# issue #15661 -@test_throws ParseError parse("function catch() end") -@test_throws ParseError parse("function end() end") -@test_throws ParseError parse("function finally() end") - -# PR #16170 -@test Meta.lower(Main, parse("true(x) = x")) == Expr(:error, "invalid function name \"true\"") -@test Meta.lower(Main, parse("false(x) = x")) == Expr(:error, "invalid function name \"false\"") - -# issue #16355 -@test Meta.lower(Main, :(f(d:Int...) = nothing)) == Expr(:error, "\"d:Int\" is not a valid function argument name") - -# issue #16517 -@test (try error(); catch; 0; end) === 0 -@test (try error(); catch; false; end) === false # false and true are Bool literals, not variables -@test (try error(); catch; true; end) === true -f16517() = try error(); catch; 0; end -@test f16517() === 0 - -# issue #16671 -@test parse("1.") === 1.0 - -isline(x) = isa(x, LineNumberNode) - -# issue #16672 -@test count(isline, parse("begin end").args) == 1 -@test count(isline, parse("begin; end").args) == 1 -@test count(isline, parse("begin; x+2; end").args) == 1 -@test count(isline, parse("begin; x+2; y+1; end").args) == 2 - -# issue #16736 -let - local lineoffset0 = @__LINE__() + 1 - local lineoffset1 = @__LINE__() - local lineoffset2 = @__LINE__() - 1 - @test lineoffset0 == lineoffset1 == lineoffset2 -end - -# issue #16686 -@test parse("try x - catch; test() - y - end") == Expr(:try, - Expr(:block, - LineNumberNode(1, :none), - :x), - false, - Expr(:block, - LineNumberNode(2, :none), - Expr(:call, :test), - LineNumberNode(3, :none), - :y)) - -# test that pre 0.5 deprecated syntax is a parse error -@test_throws ParseError parse("Int [1,2,3]") -@test_throws ParseError parse("Int [x for x in 1:10]") -@test_throws ParseError parse("foo (x) = x") -@test_throws ParseError parse("foo {T<:Int}(x::T) = x") - -@test_throws ParseError parse("Foo .bar") - -@test_throws ParseError parse("import x .y") -@test_throws ParseError parse("using x .y") - -@test_throws ParseError parse("--x") -@test_throws ParseError parse("stagedfunction foo(x); end") - -@test parse("A=>B") == Expr(:call, :(=>), :A, :B) - -@test parse("{1,2,3}") == Expr(:braces, 1, 2, 3) -@test parse("{1 2 3 4}") == Expr(:bracescat, Expr(:row, 1, 2, 3, 4)) -@test parse("{1 2; 3 4}") == Expr(:bracescat, Expr(:row, 1, 2), Expr(:row, 3, 4)) -@test parse("{x for x in 1:10}") == Expr(:braces, :(x for x in 1:10)) -@test parse("{x=>y for (x,y) in zip([1,2,3],[4,5,6])}") == Expr(:braces, :(x=>y for (x,y) in zip([1,2,3],[4,5,6]))) -@test parse("{:a=>1, :b=>2}") == Expr(:braces, Expr(:call, :(=>), QuoteNode(:a), 1), - Expr(:call, :(=>), QuoteNode(:b), 2)) - -@test parse("[a,b;c]") == Expr(:vect, Expr(:parameters, :c), :a, :b) -@test parse("[a,;c]") == Expr(:vect, Expr(:parameters, :c), :a) -@test parse("a[b,c;d]") == Expr(:ref, :a, Expr(:parameters, :d), :b, :c) -@test parse("a[b,;d]") == Expr(:ref, :a, Expr(:parameters, :d), :b) -@test_throws ParseError parse("[a,;,b]") -@test parse("{a,b;c}") == Expr(:braces, Expr(:parameters, :c), :a, :b) -@test parse("{a,;c}") == Expr(:braces, Expr(:parameters, :c), :a) -@test parse("a{b,c;d}") == Expr(:curly, :a, Expr(:parameters, :d), :b, :c) -@test parse("a{b,;d}") == Expr(:curly, :a, Expr(:parameters, :d), :b) - -# this now is parsed as getindex(Pair{Any,Any}, ...) -@test_throws MethodError eval(parse("(Any=>Any)[]")) -@test_throws MethodError eval(parse("(Any=>Any)[:a=>1,:b=>2]")) - # make sure base can be any Integer for T in (Int, BigInt) let n = parse(T, "123", Int8(10)) @@ -654,23 +208,6 @@ for T in (Int, BigInt) end end -# issue #16720 -let err = try - include_string(@__MODULE__, "module A - - function broken() - - x[1] = some_func( - - end - - end") - catch e - e - end - @test err.line == 7 -end - # issue #17065 @test parse(Int, "2") === 2 @test parse(Bool, "true") === true @@ -692,693 +229,3 @@ end @test tryparse(Float32, "1.23") === Nullable(1.23f0) @test tryparse(Float16, "1.23") === Nullable(Float16(1.23)) -# PR #17393 -for op in (:.==, :.&, :.|, :.≤) - @test parse("a $op b") == Expr(:call, op, :a, :b) -end -for op in (:.=, :.+=) - @test parse("a $op b") == Expr(op, :a, :b) -end - -# issue #17489 -let m_error, error_out, filename = Base.source_path() - m_error = try @eval method_c6(a::(:A)) = 1; catch e; e; end - error_out = sprint(showerror, m_error) - @test startswith(error_out, "ArgumentError: invalid type for argument a in method definition for method_c6 at $filename:") - - m_error = try @eval method_c6(::(:A)) = 2; catch e; e; end - error_out = sprint(showerror, m_error) - @test startswith(error_out, "ArgumentError: invalid type for argument number 1 in method definition for method_c6 at $filename:") - - m_error = try @eval method_c6(A; B) = 3; catch e; e; end - error_out = sprint(showerror, m_error) - @test error_out == "syntax: keyword argument \"B\" needs a default value" - - # issue #20614 - m_error = try @eval foo(types::NTuple{N}, values::Vararg{Any,N}, c) where {N} = nothing; catch e; e; end - error_out = sprint(showerror, m_error) - @test startswith(error_out, "ArgumentError: Vararg on non-final argument") -end - -# issue #7272 -@test Meta.lower(Main, parse("let - global x = 2 - local x = 1 - end")) == Expr(:error, "variable \"x\" declared both local and global") - -@test Meta.lower(Main, parse("let - local x = 2 - local x = 1 - end")) == Expr(:error, "local \"x\" declared twice") - -@test Meta.lower(Main, parse("let x - local x = 1 - end")) == Expr(:error, "local \"x\" declared twice") - -@test Meta.lower(Main, parse("let x = 2 - local x = 1 - end")) == Expr(:error, "local \"x\" declared twice") - -# issue #23673 -@test :(let $([:(x=1),:(y=2)]...); x+y end) == :(let x = 1, y = 2; x+y end) - -# make sure front end can correctly print values to error messages -let ex = Meta.lower(Main, parse("\"a\"=1")) - @test ex == Expr(:error, "invalid assignment location \"\"a\"\"") -end - -# make sure that incomplete tags are detected correctly -# (i.e. error messages in src/julia-parser.scm must be matched correctly -# by the code in base/client.jl) -for (str, tag) in Dict("" => :none, "\"" => :string, "#=" => :comment, "'" => :char, - "`" => :cmd, "begin;" => :block, "quote;" => :block, - "let;" => :block, "for i=1;" => :block, "function f();" => :block, - "f() do x;" => :block, "module X;" => :block, "mutable struct X;" => :block, - "struct X;" => :block, "(" => :other, "[" => :other, - "begin" => :other, "quote" => :other, - "let" => :other, "for" => :other, "function" => :other, - "f() do" => :other, "module" => :other, "mutable struct" => :other, - "struct" => :other) - @test Base.incomplete_tag(parse(str, raise=false)) == tag -end - -# meta nodes for optional positional arguments -@test Meta.lower(Main, :(@inline f(p::Int=2) = 3)).args[2].args[3].inlineable - -# issue #16096 -module M16096 -macro iter() - return quote - @inline function foo16096(sub) - it = 1 - end - end -end -end -let ex = Meta.lower(M16096, :(@iter)) - @test isa(ex, Expr) && ex.head === :thunk -end -let ex = Meta.lower(Main, :($M16096.@iter)) - @test isa(ex, Expr) && ex.head === :thunk -end -let thismodule = @__MODULE__, - ex = Meta.lower(thismodule, :(@M16096.iter)) - @test isa(ex, Expr) && ex.head === :thunk - @test !isdefined(M16096, :foo16096) - local_foo16096 = eval(@__MODULE__, ex) - @test local_foo16096(2.0) == 1 - @test !@isdefined foo16096 - @test !@isdefined it - @test !isdefined(M16096, :foo16096) - @test !isdefined(M16096, :it) - @test typeof(local_foo16096).name.module === thismodule - @test typeof(local_foo16096).name.mt.module === thismodule - @test getfield(thismodule, typeof(local_foo16096).name.mt.name) === local_foo16096 - @test getfield(thismodule, typeof(local_foo16096).name.name) === typeof(local_foo16096) - @test !isdefined(M16096, typeof(local_foo16096).name.mt.name) - @test !isdefined(M16096, typeof(local_foo16096).name.name) -end - -macro f16096() - quote - g16096($(esc(:x))) = 2x - end -end -let g = @f16096 - @test g(3) == 6 -end -macro f16096_2() - quote - g16096_2(; $(esc(:x))=2) = 2x - end -end -let g = @f16096_2 - @test g() == 4 -end - -# issue #15838 -module A15838 - macro f() end - const x = :a -end -module B15838 - import ..A15838.@f - macro f(x); return :x; end - const x = :b -end -@test A15838.@f() === nothing -@test A15838.@f(1) === :b -let ex = :(A15838.@f(1, 2)), __source__ = LineNumberNode(@__LINE__, Symbol(@__FILE__)) - nometh = try - macroexpand(@__MODULE__, ex) - false - catch ex - ex - end::LoadError - @test nometh.file === string(__source__.file) - @test nometh.line === __source__.line - e = nometh.error::MethodError - @test e.f === getfield(A15838, Symbol("@f")) - @test e.args === (__source__, @__MODULE__, 1, 2) -end - -# issue 10046 -for op in ["+", "-", "\$", "|", ".+", ".-", "*", ".*"] - @test_throws ParseError parse("$op in [+, -]") -end - -# issue #17701 -@test Meta.lower(Main, :(i==3 && i+=1)) == Expr(:error, "invalid assignment location \"==(i, 3) && i\"") - -# issue #18667 -@test Meta.lower(Main, :(true = 1)) == Expr(:error, "invalid assignment location \"true\"") -@test Meta.lower(Main, :(false = 1)) == Expr(:error, "invalid assignment location \"false\"") - -# PR #15592 -let str = "[1] [2]" - @test_throws ParseError parse(str) -end - -# issue 15896 and PR 15913 -@test_throws ErrorException eval(:(macro test15896(d; y=0) end)) - -# Issue #16578 (Lowering) mismatch between push_loc and pop_loc -module TestMeta_16578 -using Test -function get_expr_list(ex::CodeInfo) - return ex.code::Array{Any,1} -end -function get_expr_list(ex::Expr) - if ex.head == :thunk - return get_expr_list(ex.args[1]) - else - return ex.args - end -end - -function count_meta_loc(exprs) - push_count = 0 - pop_count = 0 - for expr in exprs - Meta.isexpr(expr, :meta) || continue - expr = expr::Expr - if expr.args[1] === :push_loc - push_count += 1 - elseif expr.args[1] === :pop_loc - pop_count += 1 - end - @test push_count >= pop_count - end - @test push_count == pop_count - return push_count -end - -function is_return_ssavalue(ex::Expr) - ex.head === :return && isa(ex.args[1], SSAValue) -end - -function is_pop_loc(ex::Expr) - ex.head === :meta && ex.args[1] === :pop_loc -end - -# Macros -macro m1() - quote - sin(1) - end -end -macro m2() - quote - 1 - end -end -include_string(@__MODULE__, """ -macro m3() - quote - @m1 - end -end -macro m4() - quote - @m2 - end -end -""", "another_file.jl") -m1_exprs = get_expr_list(Meta.lower(@__MODULE__, :(@m1))) -m2_exprs = get_expr_list(Meta.lower(@__MODULE__, :(@m2))) -m3_exprs = get_expr_list(Meta.lower(@__MODULE__, :(@m3))) -m4_exprs = get_expr_list(Meta.lower(@__MODULE__, :(@m4))) - -# Check the expanded expresion has expected number of matching push/pop -# and the return is handled correctly -@test count_meta_loc(m1_exprs) == 1 -@test is_return_ssavalue(m1_exprs[end]) -@test is_pop_loc(m1_exprs[end - 1]) - -@test count_meta_loc(m2_exprs) == 1 -@test m2_exprs[end] == :(return 1) -@test is_pop_loc(m2_exprs[end - 1]) - -@test count_meta_loc(m3_exprs) == 2 -@test is_return_ssavalue(m3_exprs[end]) -@test is_pop_loc(m3_exprs[end - 1]) - -@test count_meta_loc(m4_exprs) == 2 -@test m4_exprs[end] == :(return 1) -@test is_pop_loc(m4_exprs[end - 1]) - -function f1(a) - b = a + 100 - b -end - -@generated function f2(a) - quote - b = a + 100 - b - end -end - -f1_exprs = get_expr_list(@code_typed(f1(1))[1]) -f2_exprs = get_expr_list(@code_typed(f2(1))[1]) - -@test Meta.isexpr(f1_exprs[end], :return) -@test is_pop_loc(f2_exprs[end]) -@test Meta.isexpr(f2_exprs[end - 1], :return) - -if Base.JLOptions().code_coverage != 0 && Base.JLOptions().can_inline != 0 - @test count_meta_loc(f1_exprs) == 1 - @test count_meta_loc(f2_exprs) == 2 -else - @test count_meta_loc(f1_exprs) == 0 - @test count_meta_loc(f2_exprs) == 1 -end - -# Check that string and command literals are parsed to the appropriate macros -@test :(x"s") == :(@x_str "s") -@test :(x"s"flag) == :(@x_str "s" "flag") -@test :(x"s\"`\x\$\\") == :(@x_str "s\"`\\x\\\$\\\\") -@test :(x`s`) == :(@x_cmd "s") -@test :(x`s`flag) == :(@x_cmd "s" "flag") -@test :(x`s\`"\x\$\\`) == :(@x_cmd "s`\"\\x\\\$\\\\") - -# Check multiline command literals -@test :(@cmd "multiline\ncommand\n") == :``` -multiline -command -``` - -macro julia_cmd(s) - Meta.quot(parse(s)) -end -@test julia``` -if test + test == test - println(test) -end -```.head == :if - -end - -# issue 18756 -module Mod18756 -mutable struct Type -end -end -@test method_exists(Mod18756.Type, ()) - -# issue 18002 -@test parse("Foo{T} = Bar{T}") == Expr(:(=), Expr(:curly, :Foo, :T), Expr(:curly, :Bar, :T)) - -# don't insert push_loc for filename `none` at the top level -let ex = Meta.lower(Main, parse(""" -begin - x = 1 -end""")) - @test !any(x->(x == Expr(:meta, :push_loc, :none)), ex.args) -end - -# Check qualified string macros -Base.r"regex" == r"regex" - -module QualifiedStringMacro -module SubModule -macro x_str(x) - 1 -end -macro y_cmd(x) - 2 -end -end -end - -@test QualifiedStringMacro.SubModule.x"" === 1 -@test QualifiedStringMacro.SubModule.y`` === 2 - -let ..(x,y) = x + y - @test 3 .. 4 === 7 -end - -# issue #7669 -@test parse("@a(b=1, c=2)") == Expr(:macrocall, Symbol("@a"), LineNumberNode(1, :none), :(b=1), :(c=2)) - -# issue #19685 -let f = function (x; kw...) - return (x, kw) - end, - g = function (x; a = 2) - return (x, a) - end - @test f(1) == (1, Any[]) - @test g(1) == (1, 2) -end - -# normalization of Unicode symbols (#19464) -let ε=1, μ=2, x=3, î=4 - # issue #5434 (mu vs micro): - @test parse("\u00b5") === parse("\u03bc") - @test µ == μ == 2 - # NFC normalization of identifiers: - @test parse("\u0069\u0302") === parse("\u00ee") - @test î == 4 - # latin vs greek ε (#14751) - @test parse("\u025B") === parse("\u03B5") - @test ɛ == ε == 1 -end - -# issue #8925 -let - global const (c8925, d8925) = (3, 4) -end -@test c8925 == 3 && isconst(@__MODULE__, :c8925) -@test d8925 == 4 && isconst(@__MODULE__, :d8925) - -# issue #18754: parse ccall as a regular function -@test parse("ccall([1], 2)[3]") == Expr(:ref, Expr(:call, :ccall, Expr(:vect, 1), 2), 3) -@test parse("ccall(a).member") == Expr(:., Expr(:call, :ccall, :a), QuoteNode(:member)) - -# Check that the body of a `where`-qualified short form function definition gets -# a :block for its body -short_where_call = :(f(x::T) where T = T) -@test short_where_call.args[2].head == :block - -# `where` with multi-line anonymous functions -let f = function (x::T) where T - T - end - @test f(:x) === Symbol -end - -let f = function (x::T, y::S) where T<:S where S - (T,S) - end - @test f(0,1) === (Int,Int) -end - -# issue #20541 -@test parse("[a .!b]") == Expr(:hcat, :a, Expr(:call, :(.!), :b)) - -@test Meta.lower(Main, :(a{1} = b)) == Expr(:error, "invalid type parameter name \"1\"") -@test Meta.lower(Main, :(a{2<:Any} = b)) == Expr(:error, "invalid type parameter name \"2\"") - -# issue #20653 -@test_throws UndefVarError Base.call(::Int) = 1 -module Test20653 -using Test -struct A -end -call(::A) = 1 -const a = A() -@test_throws MethodError a() -@test call(a) === 1 -end - -# issue #20729 -macro m20729() - ex = Expr(:head) - resize!(ex.args, 1) - return ex -end - -@test_throws ErrorException eval(@__MODULE__, :(@m20729)) -@test Meta.lower(@__MODULE__, :(@m20729)) == Expr(:error, "undefined reference in AST") - -macro err20000() - return Expr(:error, "oops!") -end - -@test Meta.lower(@__MODULE__, :(@err20000)) == Expr(:error, "oops!") - -# issue #20000 -@test parse("@m(a; b=c)") == Expr(:macrocall, Symbol("@m"), LineNumberNode(1, :none), - Expr(:parameters, Expr(:kw, :b, :c)), :a) - -# issue #21054 -macro make_f21054(T) - quote - $(esc(:f21054))(X::Type{<:$T}) = 1 - end -end -@eval @make_f21054 $Array -@test isa(f21054, Function) -g21054(>:) = >:2 -@test g21054(-) == -2 - -# issue #21168 -@test Meta.lower(Main, :(a.[1])) == Expr(:error, "invalid syntax a.[1]") -@test Meta.lower(Main, :(a.{1})) == Expr(:error, "invalid syntax a.{1}") - -# Issue #21225 -let abstr = parse("abstract type X end") - @test parse("abstract type X; end") == abstr - @test parse(string("abstract type X", ";"^5, " end")) == abstr - @test parse("abstract type X\nend") == abstr - @test parse(string("abstract type X", "\n"^5, "end")) == abstr -end -let prim = parse("primitive type X 8 end") - @test parse("primitive type X 8; end") == prim - @test parse(string("primitive type X 8", ";"^5, " end")) == prim - @test parse("primitive type X 8\nend") == prim - @test parse(string("primitive type X 8", "\n"^5, "end")) == prim -end - -# issue #21155 -@test filter(!isline, - parse("module B - using ..x, - ..y - end").args[3].args)[1] == - Expr(:toplevel, - Expr(:using, Symbol("."), Symbol("."), :x), - Expr(:using, Symbol("."), Symbol("."), :y)) - -@test filter(!isline, - parse("module A - using .B, - .C - end").args[3].args)[1] == - Expr(:toplevel, - Expr(:using, Symbol("."), :B), - Expr(:using, Symbol("."), :C)) - -# issue #21440 -@test parse("+(x::T,y::T) where {T} = 0") == parse("(+)(x::T,y::T) where {T} = 0") -@test parse("a::b::c") == Expr(:(::), Expr(:(::), :a, :b), :c) - -# issue #21545 -f21545(::Type{<: AbstractArray{T,N} where N}) where T = T -@test f21545(Array{Int8}) === Int8 -@test parse("<:{T} where T") == Expr(:where, Expr(:curly, :(<:), :T), :T) -@test parse("<:(T) where T") == Expr(:where, Expr(:(<:), :T), :T) -@test parse("<:{T}(T) where T") == Expr(:where, Expr(:call, Expr(:curly, :(<:), :T), :T), :T) - -# issue #21586 -macro m21586(x) - Expr(:kw, esc(x), 42) -end - -f21586(; @m21586(a), @m21586(b)) = a + b -@test f21586(a=10) == 52 - -# issue #21604 -@test_nowarn @eval module Test21604 - const Foo = Any - struct X - x::Foo - end -end -@test Test21604.X(1.0) === Test21604.X(1.0) - -# issue #20575 -@test_throws ParseError parse("\"a\"x") -@test_throws ParseError parse("\"a\"begin end") - -# comment 298107224 on pull #21607 -module Test21607 - using Test - const Any = Integer - - # check that X <: Core.Any, not Integer - mutable struct X; end - @test supertype(X) === Core.Any - - # check that return type is Integer - f()::Any = 1.0 - @test f() === 1 - - # check that constructor accepts Any - struct Y - x - end - @test Y(1.0) !== Y(1) - - # check that function default argument type is Any - g(x) = x - @test g(1.0) === 1.0 - - # check that asserted variable type is Integer - @test let - x::Any = 1.0 - x - end === 1 - - # check that unasserted variable type is not Integer - @test let - x = 1.0 - x - end === 1.0 -end - -# issue #16937 -@test Meta.lower(Main, :(f(2, a=1, w=3, c=3, w=4, b=2))) == - Expr(:error, "keyword argument \"w\" repeated in call to \"f\"") - -let f(x) = - g(x) = 1 - @test functionloc(f(1))[2] > functionloc(f)[2] -end - -# let-bound functions with `where` and static parameters -@test let f()::Int = 2.0 - f() -end === 2 -@test let (f(x::T)::Tuple{Int,Any}) where {T} = (3.0, T) - f("") -end === (3, String) - -# operator suffixes -@test parse("3 +̂ 4") == Expr(:call, :+̂, 3, 4) -@test parse("3 +̂′ 4") == Expr(:call, :+̂′, 3, 4) -@test parse("3 +⁽¹⁾ 4") == Expr(:call, :+⁽¹⁾, 3, 4) -@test parse("3 +₍₀₎ 4") == Expr(:call, :+₍₀₎, 3, 4) -for bad in ('=', '$', ':', "||", "&&", "->", "<:") - @test_throws ParseError parse("3 $(bad)⁽¹⁾ 4") -end -@test Base.operator_precedence(:+̂) == Base.operator_precedence(:+) - -# issue #19351 -# adding return type decl should not affect parse of function body -@test :(t(abc) = 3).args[2] == :(t(abc)::Int = 3).args[2] - -# issue #7314 -@test parse("local x, y = 1, 2") == Expr(:local, Expr(:(=), - Expr(:tuple, :x, :y), - Expr(:tuple, 1, 2))) - -@test_throws ParseError parse("[2for i=1:10]") -@test_throws ParseError parse("[1 for i in 1:2for j in 2]") -@test_throws ParseError parse("(1 for i in 1:2for j in 2)") -# issue #20441 -@test_throws ParseError parse("[x.2]") -@test_throws ParseError parse("x.2") -@test parse("[x;.2]") == Expr(:vcat, :x, 0.2) - -# issue #22840 -@test parse("[:a :b]") == Expr(:hcat, QuoteNode(:a), QuoteNode(:b)) - -# issue #22868 -@test_throws ParseError parse("x@time 2") -@test_throws ParseError parse("@ time") - -# issue #7479 -@test Meta.lower(Main, parse("(true &&& false)")) == Expr(:error, "misplaced \"&\" expression") - -# if an indexing expression becomes a cat expression, `end` is not special -@test_throws ParseError parse("a[end end]") -@test_throws ParseError parse("a[end;end]") -#@test_throws ParseError parse("a[end;]") # this is difficult to fix -let a = rand(8), i = 3 - @test a[[1:i-1; i+1:end]] == a[[1,2,4,5,6,7,8]] -end - -# issue #18935 -@test [begin - @inbounds for i = 1:10 end - end for i = 1:5] == fill(nothing, 5) - -# issue #18912 -@test_throws ParseError parse("(::)") -@test parse(":(::)") == QuoteNode(Symbol("::")) -@test_throws ParseError parse("f(::) = ::") -@test parse("(::A)") == Expr(Symbol("::"), :A) -@test_throws ParseError parse("(::, 1)") -@test_throws ParseError parse("(1, ::)") - -# issue #18650 -let ex = parse("maximum(@elapsed sleep(1) for k = 1:10)") - @test isa(ex, Expr) && ex.head === :call && ex.args[2].head === :generator && - ex.args[2].args[1].head === :macrocall -end - -# issue #23173 -@test_throws ErrorException("invalid module path") eval(:(import $(:.))) - -# issue #23234 -let - f = function (x=0) - x - end - @test f() == 0 - @test f(2) == 2 -end - -# issue #18730 -@test Meta.lower(Main, quote - function f() - local Int - x::Int -> 2 - end - end) == Expr(:error, "local variable Int cannot be used in closure declaration") - -# some issues with backquote -# preserve QuoteNode and LineNumberNode -@test eval(Expr(:quote, QuoteNode(Expr(:tuple, 1, Expr(:$, :(1+2)))))) == QuoteNode(Expr(:tuple, 1, 3)) -@test eval(Expr(:quote, Expr(:line, Expr(:$, :(1+2))))) === LineNumberNode(3, nothing) -# splicing at the top level should be an error -xs23917 = [1,2,3] -@test_throws ErrorException eval(:(:($(xs23917...)))) -let ex2 = eval(:(:(:($$(xs23917...))))) - @test ex2 isa Expr - @test_throws ErrorException eval(ex2) - @test eval(:($(xs23917...),)) == (1,2,3) # adding a comma gives a tuple -end -# multi-unquote of splice in nested quote -let xs = [:(1+2), :(3+4), :(5+6)] - ex = quote quote $$(xs...) end end - @test ex.args[2].args[1].args[2].args[2] == :(3 + 4) - ex2 = eval(ex) - @test ex2.args[2:end] == [3,7,11] -end - -# issue #23519 -@test parse("@foo[1]") == parse("@foo([1])") -@test parse("@foo[1 2; 3 4]") == parse("@foo([1 2; 3 4])") -@test parse("@foo[1] + [2]") == parse("@foo([1]) + [2]") -@test parse("@foo [1] + [2]") == parse("@foo([1] + [2])") -@test parse("@Mdl.foo[1] + [2]") == parse("@Mdl.foo([1]) + [2]") -@test parse("@Mdl.foo [1] + [2]") == parse("@Mdl.foo([1] + [2])") - -# issue #24289 -macro m24289() - :(global $(esc(:x24289)) = 1) -end -@test (@macroexpand @m24289) == :(global x24289 = 1) diff --git a/test/serialize.jl b/test/serialize.jl index bb87f96eb4f50..ca8aa059c7bda 100644 --- a/test/serialize.jl +++ b/test/serialize.jl @@ -126,8 +126,8 @@ end create_serialization_stream() do s # user-defined module mod = b"SomeModule" modstring = String(mod) - eval(parse("module $(modstring); end")) - modtype = eval(parse("$(modstring)")) + eval(Meta.parse("module $(modstring); end")) + modtype = eval(Meta.parse("$(modstring)")) serialize(s, modtype) seek(s, 0) @test deserialize(s) === modtype @@ -147,8 +147,8 @@ end create_serialization_stream() do s # user-defined type usertype = "SerializeSomeType" - eval(parse("abstract type $(usertype) end")) - utype = eval(parse("$(usertype)")) + eval(Meta.parse("abstract type $(usertype) end")) + utype = eval(Meta.parse("$(usertype)")) serialize(s, utype) seek(s, 0) @test deserialize(s) === utype @@ -156,8 +156,8 @@ end create_serialization_stream() do s # user-defined type usertype = "SerializeSomeType1" - eval(parse("mutable struct $(usertype); end")) - utype = eval(parse("$(usertype)")) + eval(Meta.parse("mutable struct $(usertype); end")) + utype = eval(Meta.parse("$(usertype)")) serialize(s, utype) seek(s, 0) @test deserialize(s) === utype @@ -165,8 +165,8 @@ end create_serialization_stream() do s # user-defined type usertype = "SerializeSomeType2" - eval(parse("abstract type $(usertype){T} end")) - utype = eval(parse("$(usertype)")) + eval(Meta.parse("abstract type $(usertype){T} end")) + utype = eval(Meta.parse("$(usertype)")) serialize(s, utype) seek(s, 0) @test deserialize(s) == utype @@ -174,8 +174,8 @@ end create_serialization_stream() do s # immutable struct with 1 field usertype = "SerializeSomeType3" - eval(parse("struct $(usertype){T}; a::T; end")) - utype = eval(parse("$(usertype)")) + eval(Meta.parse("struct $(usertype){T}; a::T; end")) + utype = eval(Meta.parse("$(usertype)")) serialize(s, utype) seek(s, 0) @test deserialize(s) == utype @@ -183,8 +183,8 @@ end create_serialization_stream() do s # immutable struct with 2 field usertype = "SerializeSomeType4" - eval(parse("struct $(usertype){T}; a::T; b::T; end")) - utval = eval(parse("$(usertype)(1,2)")) + eval(Meta.parse("struct $(usertype){T}; a::T; b::T; end")) + utval = eval(Meta.parse("$(usertype)(1,2)")) serialize(s, utval) seek(s, 0) @test deserialize(s) === utval @@ -192,8 +192,8 @@ end create_serialization_stream() do s # immutable struct with 3 field usertype = "SerializeSomeType5" - eval(parse("struct $(usertype){T}; a::T; b::T; c::T; end")) - utval = eval(parse("$(usertype)(1,2,3)")) + eval(Meta.parse("struct $(usertype){T}; a::T; b::T; c::T; end")) + utval = eval(Meta.parse("$(usertype)(1,2,3)")) serialize(s, utval) seek(s, 0) @test deserialize(s) === utval @@ -201,8 +201,8 @@ end create_serialization_stream() do s # immutable struct with 4 field usertype = "SerializeSomeType6" - eval(parse("struct $(usertype){T}; a::T; b::T; c::T; d::T; end")) - utval = eval(parse("$(usertype)(1,2,3,4)")) + eval(Meta.parse("struct $(usertype){T}; a::T; b::T; c::T; d::T; end")) + utval = eval(Meta.parse("$(usertype)(1,2,3,4)")) serialize(s, utval) seek(s, 0) @test deserialize(s) === utval @@ -210,10 +210,10 @@ end # Expression create_serialization_stream() do s - expr = parse("a = 1") + expr = Meta.parse("a = 1") serialize(s, expr) - expr2 = parse(repeat("a = 1;", 300)) + expr2 = Meta.parse(repeat("a = 1;", 300)) serialize(s, expr2) seek(s, 0) diff --git a/test/show.jl b/test/show.jl index a3075d722ba16..71a9577899615 100644 --- a/test/show.jl +++ b/test/show.jl @@ -15,10 +15,10 @@ struct T5589 end @test replstr(T5589(Array{String,1}(100))) == "$(curmod_prefix)T5589([#undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef … #undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef])" -@test replstr(parse("mutable struct X end")) == ":(mutable struct X\n #= none:1 =#\n end)" -@test replstr(parse("struct X end")) == ":(struct X\n #= none:1 =#\n end)" +@test replstr(Meta.parse("mutable struct X end")) == ":(mutable struct X\n #= none:1 =#\n end)" +@test replstr(Meta.parse("struct X end")) == ":(struct X\n #= none:1 =#\n end)" let s = "ccall(:f, Int, (Ptr{Void},), &x)" - @test replstr(parse(s)) == ":($s)" + @test replstr(Meta.parse(s)) == ":($s)" end # recursive array printing @@ -39,9 +39,9 @@ macro test_repr(x) # This could produce a few false positives, but until string # interpolation works we don't really have a choice. let - local x1 = parse($x) - local x2 = eval(parse(repr(x1))) - local x3 = eval(parse(repr(x2))) + local x1 = Meta.parse($x) + local x2 = eval(Meta.parse(repr(x1))) + local x3 = eval(Meta.parse(repr(x2))) if x3 != x1 error(string( "repr test failed:", @@ -105,8 +105,8 @@ end # Complex -# parse(repr(:(...))) returns a double-quoted block, so we need to eval twice to unquote it -@test iszero(eval(eval(parse(repr(:($(1 + 2im) - $(1 + 2im))))))) +# Meta.parse(repr(:(...))) returns a double-quoted block, so we need to eval twice to unquote it +@test iszero(eval(eval(Meta.parse(repr(:($(1 + 2im) - $(1 + 2im))))))) # control structures (shamelessly stolen from base/bitarray.jl) @@ -342,7 +342,7 @@ end" # issue #9474 for s in ("(1::Int64 == 1::Int64)::Bool", "(1:2:3) + 4", "x = 1:2:3") local s - @test sprint(show, parse(s)) == ":("*s*")" + @test sprint(show, Meta.parse(s)) == ":("*s*")" end # parametric type instantiation printing @@ -350,8 +350,8 @@ struct TParametricPrint{a}; end @test sprint(show, :(TParametricPrint{false}())) == ":(TParametricPrint{false}())" # issue #9797 -let q1 = parse(repr(:("$(a)b"))), - q2 = parse(repr(:("$ab"))) +let q1 = Meta.parse(repr(:("$(a)b"))), + q2 = Meta.parse(repr(:("$ab"))) @test isa(q1, Expr) @test q1.args[1].head === :string @test q1.args[1].args == [:a, "b"] @@ -363,8 +363,8 @@ end x8d003 = 2 let a = Expr(:quote,Expr(:$,:x8d003)) - @test eval(parse(repr(a))) == a - @test eval(eval(parse(repr(a)))) == 2 + @test eval(Meta.parse(repr(a))) == a + @test eval(eval(Meta.parse(repr(a)))) == 2 end # issue #9865 @@ -765,7 +765,7 @@ end @test_repr "(x for a in b, c in d for e in f)" for op in (:(.=), :(.+=), :(.&=)) - @test repr(parse("x $op y")) == ":(x $op y)" + @test repr(Meta.parse("x $op y")) == ":(x $op y)" end # pretty-printing of compact broadcast expressions (#17289) diff --git a/test/strings/basic.jl b/test/strings/basic.jl index 0c7cdb54824ae..17c1608bbee1f 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -72,7 +72,7 @@ end @test string(sym) == string(Char(0xdcdb)) @test String(sym) == string(Char(0xdcdb)) @test Meta.lower(Main, sym) === sym - res = string(parse(string(Char(0xdcdb)," = 1"),1,raise=false)[1]) + res = string(Meta.parse(string(Char(0xdcdb)," = 1"),1,raise=false)[1]) @test res == """\$(Expr(:error, "invalid character \\\"\\udcdb\\\"\"))""" end @@ -561,8 +561,8 @@ end end @testset "unrecognized escapes in string/char literals" begin - @test_throws ParseError parse("\"\\.\"") - @test_throws ParseError parse("\'\\.\'") + @test_throws Meta.ParseError Meta.parse("\"\\.\"") + @test_throws Meta.ParseError Meta.parse("\'\\.\'") end @testset "prevind and nextind" begin diff --git a/test/syntax.jl b/test/syntax.jl new file mode 100644 index 0000000000000..0dbcf10c72125 --- /dev/null +++ b/test/syntax.jl @@ -0,0 +1,1158 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +# tests for parser and syntax lowering + +import Base.Meta.ParseError + +function parseall(str) + pos = start(str) + exs = [] + while !done(str, pos) + ex, pos = Meta.parse(str, pos) + push!(exs, ex) + end + if length(exs) == 0 + throw(ParseError("end of input")) + elseif length(exs) == 1 + return exs[1] + else + return Expr(:block, exs...) + end +end + +# issue #9684 +let + undot(op) = Symbol(string(op)[2:end]) + for (ex1, ex2) in [("5 .≠ x", "5 .!= x"), + ("5 .≥ x", "5 .>= x"), + ("5 .≤ x", "5 .<= x")] + ex1 = Meta.parse(ex1); ex2 = Meta.parse(ex2) + @test ex1.head === :call && (ex1.head === ex2.head) + @test ex1.args[2] === 5 && ex2.args[2] === 5 + @test eval(Main, undot(ex1.args[1])) === eval(Main, undot(ex2.args[1])) + @test ex1.args[3] === :x && (ex1.args[3] === ex2.args[3]) + end +end + +# issue #9704 +let a = :a + @test :(try + catch $a + end) == :(try + catch a + end) + @test :(module $a end) == :(module a + end) +end + +# string literals +macro test999_str(args...); args; end +@test test999"a"b == ("a","b") +@test test999"""a"""b == ("a","b") +@test test999" + a + b" == (" + a + b",) +@test test999""" + a + b""" == ("a\nb",) + +# issue #5997 +@test_throws ParseError Meta.parse(": x") +@test_throws ParseError Meta.parse("d[: 2]") + +# issue #6770 +@test_throws ParseError Meta.parse("x.3") + +# issue #8763 +@test_throws ParseError Meta.parse("sqrt(16)2") +@test_throws ParseError Meta.parse("x' y") +@test_throws ParseError Meta.parse("x 'y") +@test Meta.parse("x'y") == Expr(:call, :*, Expr(Symbol("'"), :x), :y) + +# issue #8301 +@test_throws ParseError Meta.parse("&*s") + +# issue #10677 +@test_throws ParseError Meta.parse("/1") +@test_throws ParseError Meta.parse("/pi") +@test Meta.parse("- = 2") == Expr(:(=), :(-), 2) +@test Meta.parse("/ = 2") == Expr(:(=), :(/), 2) +@test_throws ParseError Meta.parse("< : 2") +@test_throws ParseError Meta.parse("+ : 2") +@test_throws ParseError Meta.parse("< :2") +@test Meta.parse("+ :2") == Expr(:call, :(+), QuoteNode(2)) + +# issue #10900 +@test_throws ParseError Meta.parse("+=") +@test_throws ParseError Meta.parse(".") +@test_throws ParseError Meta.parse("...") + +# issue #10901 +@test Meta.parse("/([1], 1)[1]") == :(([1] / 1)[1]) + +# issue #10997 +@test Meta.parse(":(x.\$f[i])") == Expr(:quote, + Expr(:ref, + Expr(Symbol("."), :x, + QuoteNode(Expr(:$, :f))), + :i)) + +# issue #10994 +@test Meta.parse("1 + #= \0 =# 2") == :(1 + 2) + +# issue #10910 +@test Meta.parse(":(using A)") == Expr(:quote, Expr(:using, :A)) +@test Meta.parse(":(using A.b, B)") == Expr(:quote, + Expr(:toplevel, + Expr(:using, :A, :b), + Expr(:using, :B))) +@test Meta.parse(":(using A: b, c.d)") == Expr(:quote, + Expr(:toplevel, + Expr(:using, :A, :b), + Expr(:using, :A, :c, :d))) + +@test Meta.parse(":(import A)") == Expr(:quote, Expr(:import, :A)) +@test Meta.parse(":(import A.b, B)") == Expr(:quote, + Expr(:toplevel, + Expr(:import, :A, :b), + Expr(:import, :B))) +@test Meta.parse(":(import A: b, c.d)") == Expr(:quote, + Expr(:toplevel, + Expr(:import, :A, :b), + Expr(:import, :A, :c, :d))) + +# issue #11332 +@test Meta.parse("export \$(Symbol(\"A\"))") == :(export $(Expr(:$, :(Symbol("A"))))) +@test Meta.parse("export \$A") == :(export $(Expr(:$, :A))) +@test Meta.parse("using \$a.\$b") == Expr(:using, Expr(:$, :a), Expr(:$, :b)) +@test Meta.parse("using \$a.\$b, \$c") == Expr(:toplevel, Expr(:using, Expr(:$, :a), + Expr(:$, :b)), + Expr(:using, Expr(:$, :c))) +@test Meta.parse("using \$a: \$b, \$c.\$d") == + Expr(:toplevel, Expr(:using, Expr(:$, :a), Expr(:$, :b)), + Expr(:using, Expr(:$, :a), Expr(:$, :c), Expr(:$, :d))) + +# fix pr #11338 and test for #11497 +@test parseall("using \$\na") == Expr(:block, Expr(:using, :$), :a) +@test parseall("using \$,\na") == Expr(:toplevel, Expr(:using, :$), + Expr(:using, :a)) +@test parseall("using &\na") == Expr(:block, Expr(:using, :&), :a) + +@test parseall("a = &\nb") == Expr(:block, Expr(:(=), :a, :&), :b) +@test parseall("a = \$\nb") == Expr(:block, Expr(:(=), :a, :$), :b) +@test parseall(":(a = &\nb)") == Expr(:quote, Expr(:(=), :a, Expr(:&, :b))) +@test parseall(":(a = \$\nb)") == Expr(:quote, Expr(:(=), :a, Expr(:$, :b))) + +# issue 11970 +@test parseall(""" + macro f(args...) end; @f "macro argument" +""") == Expr(:toplevel, + Expr(:macro, Expr(:call, :f, Expr(:..., :args)), Expr(:block, LineNumberNode(1, :none))), + Expr(:macrocall, Symbol("@f"), LineNumberNode(1, :none), "macro argument")) + +# blocks vs. tuples +@test Meta.parse("()") == Expr(:tuple) +@test Meta.parse("(;)") == Expr(:block) +@test Meta.parse("(;;;;)") == Expr(:block) +@test_throws ParseError Meta.parse("(,)") +@test_throws ParseError Meta.parse("(;,)") +@test_throws ParseError Meta.parse("(,;)") +@test Meta.parse("(x;)") == Expr(:block, :x) +@test Meta.parse("(;x)") == Expr(:tuple, Expr(:parameters, :x)) +@test Meta.parse("(;x,)") == Expr(:tuple, Expr(:parameters, :x)) +@test Meta.parse("(x,)") == Expr(:tuple, :x) +@test Meta.parse("(x,;)") == Expr(:tuple, :x) +@test Meta.parse("(x;y)") == Expr(:block, :x, :y) +@test Meta.parse("(x=1;y=2)") == Expr(:block, Expr(:(=), :x, 1), Expr(:(=), :y, 2)) +@test Meta.parse("(x,;y)") == Expr(:tuple, Expr(:parameters, :y), :x) +@test Meta.parse("(x,;y=1)") == Expr(:tuple, Expr(:parameters, Expr(:kw, :y, 1)), :x) +@test Meta.parse("(x,a;y=1)") == Expr(:tuple, Expr(:parameters, Expr(:kw, :y, 1)), :x, :a) +@test Meta.parse("(x,a;y=1,z=2)") == Expr(:tuple, Expr(:parameters, Expr(:kw,:y,1), Expr(:kw,:z,2)), :x, :a) +@test Meta.parse("(a=1, b=2)") == Expr(:tuple, Expr(:(=), :a, 1), Expr(:(=), :b, 2)) +@test_throws ParseError Meta.parse("(1 2)") # issue #15248 + +@test Meta.parse("1 == 2|>3") == Expr(:call, :(==), 1, Expr(:call, :(|>), 2, 3)) + +# issue #24153 +@test Meta.parse("a|>b|>c|>d") == Meta.parse("((a|>b)|>c)|>d") +@test Meta.parse("a<|b<|c<|d") == Meta.parse("a<|(b<|(c<|d))") + +# issue #12501 and pr #12502 +Meta.parse(""" + baremodule A + "a" in b + end + """) +Meta.parse(""" + baremodule A + "a" + end + """) + +# issue #12626 +@test Meta.parse("a .÷ 1") == Expr(:call, :.÷, :a, 1) +@test Meta.parse("a .÷= 1") == Expr(:.÷=, :a, 1) + +# issue #12771 +@test -(3)^2 == -9 + +# issue #13302 +let p = Meta.parse("try + a + catch + b, c = t + end") + @test isa(p,Expr) && p.head === :try + @test p.args[2] === false + @test p.args[3].args[end] == Meta.parse("b,c = t") +end + +# pr #13078 +@test Meta.parse("a in b in c") == Expr(:comparison, :a, :in, :b, :in, :c) +@test Meta.parse("a||b→c&&d") == Expr(:call, :→, + Expr(Symbol("||"), :a, :b), + Expr(Symbol("&&"), :c, :d)) + +# issue #11988 -- normalize \r and \r\n in literal strings to \n +@test "foo\nbar" == Meta.parse("\"\"\"\r\nfoo\r\nbar\"\"\"") == + Meta.parse("\"\"\"\nfoo\nbar\"\"\"") == Meta.parse("\"\"\"\rfoo\rbar\"\"\"") == + Meta.parse("\"foo\r\nbar\"") == Meta.parse("\"foo\rbar\"") == Meta.parse("\"foo\nbar\"") +@test '\r' == first("\r") == first("\r\n") # still allow explicit \r + +# issue #14561 - generating 0-method generic function def +let fname = :f + @test :(function $fname end) == Expr(:function, :f) +end + +# issue #14977 +@test Meta.parse("x = 1", 1) == (:(x = 1), 6) +@test Meta.parse("x = 1", 6) == (nothing, 6) +@test_throws BoundsError Meta.parse("x = 1", 0) +@test_throws BoundsError Meta.parse("x = 1", -1) +@test_throws BoundsError Meta.parse("x = 1", 7) + +# issue #14683 +@test_throws ParseError Meta.parse("'\\A\"'") +@test Meta.parse("'\"'") == Meta.parse("'\\\"'") == '"' == "\""[1] == '\42' + +@test_throws ParseError Meta.parse("f(2x for x=1:10, y") + +# issue #15223 +call0(f) = f() +call1(f,x) = f(x) +call2(f,x,y) = f(x,y) +@test (call0() do; 42 end) == 42 +@test (call1(42) do x; x+1 end) == 43 +@test (call2(42,1) do x,y; x+y+1 end) == 44 + +# definitions using comparison syntax +let a⊂b = reduce(&, x ∈ b for x in a) && length(b)>length(a) + @test [1,2] ⊂ [1,2,3,4] + @test !([1,2] ⊂ [1,3,4]) + @test !([1,2] ⊂ [1,2]) +end + +# issue #9503 +@test Meta.parse("x<:y") == Expr(:(<:), :x, :y) +@test Meta.parse("x>:y") == Expr(:(>:), :x, :y) +@test Meta.parse("x<:y<:z").head === :comparison +@test Meta.parse("x>:y<:z").head === :comparison + +# reason PR #19765, <- operator, was reverted +@test -2<-1 # DO NOT ADD SPACES + +# issue #11169 +uncalled(x) = @test false +fret() = uncalled(return true) +@test fret() + +# issue #9617 +let p = 15 + @test 2p+1 == 31 # not a hex float literal +end + +function test_parseerror(str, msg) + try + Meta.parse(str) + @test false + catch e + @test isa(e,ParseError) && e.msg == msg + end +end +test_parseerror("0x", "invalid numeric constant \"0x\"") +test_parseerror("0b", "invalid numeric constant \"0b\"") +test_parseerror("0o", "invalid numeric constant \"0o\"") +test_parseerror("0x0.1", "hex float literal must contain \"p\" or \"P\"") +test_parseerror("0x1.0p", "invalid numeric constant \"0x1.0\"") + +# issue #15798 +@test Meta.lower(Main, Base.parse_input_line(""" + try = "No" + """)) == Expr(:error, "unexpected \"=\"") + +# issue #19861 make sure macro-expansion happens in the newest world for top-level expression +@test eval(Base.parse_input_line(""" + macro X19861() + return 23341 + end + @X19861 + """)::Expr) == 23341 + +# test parse_input_line for a streaming IO input +let b = IOBuffer(""" + let x = x + x + end + f() + """) + @test Base.parse_input_line(b) == Expr(:let, Expr(:(=), :x, :x), Expr(:block, LineNumberNode(2, :none), :x)) + @test Base.parse_input_line(b) == Expr(:call, :f) + @test Base.parse_input_line(b) === nothing +end + +# issue #15763 +test_parseerror("if\nfalse\nend", "missing condition in \"if\" at none:1") +test_parseerror("if false\nelseif\nend", "missing condition in \"elseif\" at none:2") + +# issue #15828 +@test Meta.lower(Main, Meta.parse("x...")) == Expr(:error, "\"...\" expression outside call") + +# issue #15830 +@test Meta.lower(Main, Meta.parse("foo(y = (global x)) = y")) == Expr(:error, "misplaced \"global\" declaration") + +# issue #15844 +function f15844(x) + x +end + +g15844 = let + local function f15844(x::Int32) + 2x + end +end + +function add_method_to_glob_fn!() + global function f15844(x::Int64) + 3x + end +end + +add_method_to_glob_fn!() +@test g15844 !== f15844 +@test g15844(Int32(1)) == 2 +@test f15844(Int32(1)) == 1 +@test f15844(Int64(1)) == 3 + +# issue #15661 +@test_throws ParseError Meta.parse("function catch() end") +@test_throws ParseError Meta.parse("function end() end") +@test_throws ParseError Meta.parse("function finally() end") + +# PR #16170 +@test Meta.lower(Main, Meta.parse("true(x) = x")) == Expr(:error, "invalid function name \"true\"") +@test Meta.lower(Main, Meta.parse("false(x) = x")) == Expr(:error, "invalid function name \"false\"") + +# issue #16355 +@test Meta.lower(Main, :(f(d:Int...) = nothing)) == Expr(:error, "\"d:Int\" is not a valid function argument name") + +# issue #16517 +@test (try error(); catch; 0; end) === 0 +@test (try error(); catch; false; end) === false # false and true are Bool literals, not variables +@test (try error(); catch; true; end) === true +f16517() = try error(); catch; 0; end +@test f16517() === 0 + +# issue #16671 +@test Meta.parse("1.") === 1.0 + +isline(x) = isa(x, LineNumberNode) + +# issue #16672 +@test count(isline, Meta.parse("begin end").args) == 1 +@test count(isline, Meta.parse("begin; end").args) == 1 +@test count(isline, Meta.parse("begin; x+2; end").args) == 1 +@test count(isline, Meta.parse("begin; x+2; y+1; end").args) == 2 + +# issue #16736 +let + local lineoffset0 = @__LINE__() + 1 + local lineoffset1 = @__LINE__() + local lineoffset2 = @__LINE__() - 1 + @test lineoffset0 == lineoffset1 == lineoffset2 +end + +# issue #16686 +@test Meta.parse("try x + catch; test() + y + end") == Expr(:try, + Expr(:block, + LineNumberNode(1, :none), + :x), + false, + Expr(:block, + LineNumberNode(2, :none), + Expr(:call, :test), + LineNumberNode(3, :none), + :y)) + +# test that pre 0.5 deprecated syntax is a parse error +@test_throws ParseError Meta.parse("Int [1,2,3]") +@test_throws ParseError Meta.parse("Int [x for x in 1:10]") +@test_throws ParseError Meta.parse("foo (x) = x") +@test_throws ParseError Meta.parse("foo {T<:Int}(x::T) = x") + +@test_throws ParseError Meta.parse("Foo .bar") + +@test_throws ParseError Meta.parse("import x .y") +@test_throws ParseError Meta.parse("using x .y") + +@test_throws ParseError Meta.parse("--x") +@test_throws ParseError Meta.parse("stagedfunction foo(x); end") + +@test Meta.parse("A=>B") == Expr(:call, :(=>), :A, :B) + +@test Meta.parse("{1,2,3}") == Expr(:braces, 1, 2, 3) +@test Meta.parse("{1 2 3 4}") == Expr(:bracescat, Expr(:row, 1, 2, 3, 4)) +@test Meta.parse("{1 2; 3 4}") == Expr(:bracescat, Expr(:row, 1, 2), Expr(:row, 3, 4)) +@test Meta.parse("{x for x in 1:10}") == Expr(:braces, :(x for x in 1:10)) +@test Meta.parse("{x=>y for (x,y) in zip([1,2,3],[4,5,6])}") == Expr(:braces, :(x=>y for (x,y) in zip([1,2,3],[4,5,6]))) +@test Meta.parse("{:a=>1, :b=>2}") == Expr(:braces, Expr(:call, :(=>), QuoteNode(:a), 1), + Expr(:call, :(=>), QuoteNode(:b), 2)) + +@test Meta.parse("[a,b;c]") == Expr(:vect, Expr(:parameters, :c), :a, :b) +@test Meta.parse("[a,;c]") == Expr(:vect, Expr(:parameters, :c), :a) +@test Meta.parse("a[b,c;d]") == Expr(:ref, :a, Expr(:parameters, :d), :b, :c) +@test Meta.parse("a[b,;d]") == Expr(:ref, :a, Expr(:parameters, :d), :b) +@test_throws ParseError Meta.parse("[a,;,b]") +@test Meta.parse("{a,b;c}") == Expr(:braces, Expr(:parameters, :c), :a, :b) +@test Meta.parse("{a,;c}") == Expr(:braces, Expr(:parameters, :c), :a) +@test Meta.parse("a{b,c;d}") == Expr(:curly, :a, Expr(:parameters, :d), :b, :c) +@test Meta.parse("a{b,;d}") == Expr(:curly, :a, Expr(:parameters, :d), :b) + +# this now is parsed as getindex(Pair{Any,Any}, ...) +@test_throws MethodError eval(Meta.parse("(Any=>Any)[]")) +@test_throws MethodError eval(Meta.parse("(Any=>Any)[:a=>1,:b=>2]")) + +# issue #16720 +let err = try + include_string(@__MODULE__, "module A + + function broken() + + x[1] = some_func( + + end + + end") + catch e + e + end + @test err.line == 7 +end + +# PR #17393 +for op in (:.==, :.&, :.|, :.≤) + @test Meta.parse("a $op b") == Expr(:call, op, :a, :b) +end +for op in (:.=, :.+=) + @test Meta.parse("a $op b") == Expr(op, :a, :b) +end + +# issue #17489 +let m_error, error_out, filename = Base.source_path() + m_error = try @eval method_c6(a::(:A)) = 1; catch e; e; end + error_out = sprint(showerror, m_error) + @test startswith(error_out, "ArgumentError: invalid type for argument a in method definition for method_c6 at $filename:") + + m_error = try @eval method_c6(::(:A)) = 2; catch e; e; end + error_out = sprint(showerror, m_error) + @test startswith(error_out, "ArgumentError: invalid type for argument number 1 in method definition for method_c6 at $filename:") + + m_error = try @eval method_c6(A; B) = 3; catch e; e; end + error_out = sprint(showerror, m_error) + @test error_out == "syntax: keyword argument \"B\" needs a default value" + + # issue #20614 + m_error = try @eval foo(types::NTuple{N}, values::Vararg{Any,N}, c) where {N} = nothing; catch e; e; end + error_out = sprint(showerror, m_error) + @test startswith(error_out, "ArgumentError: Vararg on non-final argument") +end + +# issue #7272 +@test Meta.lower(Main, Meta.parse("let + global x = 2 + local x = 1 + end")) == Expr(:error, "variable \"x\" declared both local and global") + +@test Meta.lower(Main, Meta.parse("let + local x = 2 + local x = 1 + end")) == Expr(:error, "local \"x\" declared twice") + +@test Meta.lower(Main, Meta.parse("let x + local x = 1 + end")) == Expr(:error, "local \"x\" declared twice") + +@test Meta.lower(Main, Meta.parse("let x = 2 + local x = 1 + end")) == Expr(:error, "local \"x\" declared twice") + +# issue #23673 +@test :(let $([:(x=1),:(y=2)]...); x+y end) == :(let x = 1, y = 2; x+y end) + +# make sure front end can correctly print values to error messages +let ex = Meta.lower(Main, Meta.parse("\"a\"=1")) + @test ex == Expr(:error, "invalid assignment location \"\"a\"\"") +end + +# make sure that incomplete tags are detected correctly +# (i.e. error messages in src/julia-parser.scm must be matched correctly +# by the code in base/client.jl) +for (str, tag) in Dict("" => :none, "\"" => :string, "#=" => :comment, "'" => :char, + "`" => :cmd, "begin;" => :block, "quote;" => :block, + "let;" => :block, "for i=1;" => :block, "function f();" => :block, + "f() do x;" => :block, "module X;" => :block, "mutable struct X;" => :block, + "struct X;" => :block, "(" => :other, "[" => :other, + "begin" => :other, "quote" => :other, + "let" => :other, "for" => :other, "function" => :other, + "f() do" => :other, "module" => :other, "mutable struct" => :other, + "struct" => :other) + @test Base.incomplete_tag(Meta.parse(str, raise=false)) == tag +end + +# meta nodes for optional positional arguments +@test Meta.lower(Main, :(@inline f(p::Int=2) = 3)).args[2].args[3].inlineable + +# issue #16096 +module M16096 +macro iter() + return quote + @inline function foo16096(sub) + it = 1 + end + end +end +end +let ex = Meta.lower(M16096, :(@iter)) + @test isa(ex, Expr) && ex.head === :thunk +end +let ex = Meta.lower(Main, :($M16096.@iter)) + @test isa(ex, Expr) && ex.head === :thunk +end +let thismodule = @__MODULE__, + ex = Meta.lower(thismodule, :(@M16096.iter)) + @test isa(ex, Expr) && ex.head === :thunk + @test !isdefined(M16096, :foo16096) + local_foo16096 = eval(@__MODULE__, ex) + @test local_foo16096(2.0) == 1 + @test !@isdefined foo16096 + @test !@isdefined it + @test !isdefined(M16096, :foo16096) + @test !isdefined(M16096, :it) + @test typeof(local_foo16096).name.module === thismodule + @test typeof(local_foo16096).name.mt.module === thismodule + @test getfield(thismodule, typeof(local_foo16096).name.mt.name) === local_foo16096 + @test getfield(thismodule, typeof(local_foo16096).name.name) === typeof(local_foo16096) + @test !isdefined(M16096, typeof(local_foo16096).name.mt.name) + @test !isdefined(M16096, typeof(local_foo16096).name.name) +end + +macro f16096() + quote + g16096($(esc(:x))) = 2x + end +end +let g = @f16096 + @test g(3) == 6 +end +macro f16096_2() + quote + g16096_2(; $(esc(:x))=2) = 2x + end +end +let g = @f16096_2 + @test g() == 4 +end + +# issue #15838 +module A15838 + macro f() end + const x = :a +end +module B15838 + import ..A15838.@f + macro f(x); return :x; end + const x = :b +end +@test A15838.@f() === nothing +@test A15838.@f(1) === :b +let ex = :(A15838.@f(1, 2)), __source__ = LineNumberNode(@__LINE__, Symbol(@__FILE__)) + nometh = try + macroexpand(@__MODULE__, ex) + false + catch ex + ex + end::LoadError + @test nometh.file === string(__source__.file) + @test nometh.line === __source__.line + e = nometh.error::MethodError + @test e.f === getfield(A15838, Symbol("@f")) + @test e.args === (__source__, @__MODULE__, 1, 2) +end + +# issue 10046 +for op in ["+", "-", "\$", "|", ".+", ".-", "*", ".*"] + @test_throws ParseError Meta.parse("$op in [+, -]") +end + +# issue #17701 +@test Meta.lower(Main, :(i==3 && i+=1)) == Expr(:error, "invalid assignment location \"==(i, 3) && i\"") + +# issue #18667 +@test Meta.lower(Main, :(true = 1)) == Expr(:error, "invalid assignment location \"true\"") +@test Meta.lower(Main, :(false = 1)) == Expr(:error, "invalid assignment location \"false\"") + +# PR #15592 +let str = "[1] [2]" + @test_throws ParseError Meta.parse(str) +end + +# issue 15896 and PR 15913 +@test_throws ErrorException eval(:(macro test15896(d; y=0) end)) + +# Issue #16578 (Lowering) mismatch between push_loc and pop_loc +module TestMeta_16578 +using Test +function get_expr_list(ex::CodeInfo) + return ex.code::Array{Any,1} +end +function get_expr_list(ex::Expr) + if ex.head == :thunk + return get_expr_list(ex.args[1]) + else + return ex.args + end +end + +function count_meta_loc(exprs) + push_count = 0 + pop_count = 0 + for expr in exprs + Meta.isexpr(expr, :meta) || continue + expr = expr::Expr + if expr.args[1] === :push_loc + push_count += 1 + elseif expr.args[1] === :pop_loc + pop_count += 1 + end + @test push_count >= pop_count + end + @test push_count == pop_count + return push_count +end + +function is_return_ssavalue(ex::Expr) + ex.head === :return && isa(ex.args[1], SSAValue) +end + +function is_pop_loc(ex::Expr) + ex.head === :meta && ex.args[1] === :pop_loc +end + +# Macros +macro m1() + quote + sin(1) + end +end +macro m2() + quote + 1 + end +end +include_string(@__MODULE__, """ +macro m3() + quote + @m1 + end +end +macro m4() + quote + @m2 + end +end +""", "another_file.jl") +m1_exprs = get_expr_list(Meta.lower(@__MODULE__, :(@m1))) +m2_exprs = get_expr_list(Meta.lower(@__MODULE__, :(@m2))) +m3_exprs = get_expr_list(Meta.lower(@__MODULE__, :(@m3))) +m4_exprs = get_expr_list(Meta.lower(@__MODULE__, :(@m4))) + +# Check the expanded expresion has expected number of matching push/pop +# and the return is handled correctly +@test count_meta_loc(m1_exprs) == 1 +@test is_return_ssavalue(m1_exprs[end]) +@test is_pop_loc(m1_exprs[end - 1]) + +@test count_meta_loc(m2_exprs) == 1 +@test m2_exprs[end] == :(return 1) +@test is_pop_loc(m2_exprs[end - 1]) + +@test count_meta_loc(m3_exprs) == 2 +@test is_return_ssavalue(m3_exprs[end]) +@test is_pop_loc(m3_exprs[end - 1]) + +@test count_meta_loc(m4_exprs) == 2 +@test m4_exprs[end] == :(return 1) +@test is_pop_loc(m4_exprs[end - 1]) + +function f1(a) + b = a + 100 + b +end + +@generated function f2(a) + quote + b = a + 100 + b + end +end + +f1_exprs = get_expr_list(@code_typed(f1(1))[1]) +f2_exprs = get_expr_list(@code_typed(f2(1))[1]) + +@test Meta.isexpr(f1_exprs[end], :return) +@test is_pop_loc(f2_exprs[end]) +@test Meta.isexpr(f2_exprs[end - 1], :return) + +if Base.JLOptions().code_coverage != 0 && Base.JLOptions().can_inline != 0 + @test count_meta_loc(f1_exprs) == 1 + @test count_meta_loc(f2_exprs) == 2 +else + @test count_meta_loc(f1_exprs) == 0 + @test count_meta_loc(f2_exprs) == 1 +end + +# Check that string and command literals are parsed to the appropriate macros +@test :(x"s") == :(@x_str "s") +@test :(x"s"flag) == :(@x_str "s" "flag") +@test :(x"s\"`\x\$\\") == :(@x_str "s\"`\\x\\\$\\\\") +@test :(x`s`) == :(@x_cmd "s") +@test :(x`s`flag) == :(@x_cmd "s" "flag") +@test :(x`s\`"\x\$\\`) == :(@x_cmd "s`\"\\x\\\$\\\\") + +# Check multiline command literals +@test :(@cmd "multiline\ncommand\n") == :``` +multiline +command +``` + +macro julia_cmd(s) + Meta.quot(Meta.parse(s)) +end +@test julia``` +if test + test == test + println(test) +end +```.head == :if + +end + +# issue 18756 +module Mod18756 +mutable struct Type +end +end +@test method_exists(Mod18756.Type, ()) + +# issue 18002 +@test Meta.parse("Foo{T} = Bar{T}") == Expr(:(=), Expr(:curly, :Foo, :T), Expr(:curly, :Bar, :T)) + +# don't insert push_loc for filename `none` at the top level +let ex = Meta.lower(Main, Meta.parse(""" +begin + x = 1 +end""")) + @test !any(x->(x == Expr(:meta, :push_loc, :none)), ex.args) +end + +# Check qualified string macros +Base.r"regex" == r"regex" + +module QualifiedStringMacro +module SubModule +macro x_str(x) + 1 +end +macro y_cmd(x) + 2 +end +end +end + +@test QualifiedStringMacro.SubModule.x"" === 1 +@test QualifiedStringMacro.SubModule.y`` === 2 + +let ..(x,y) = x + y + @test 3 .. 4 === 7 +end + +# issue #7669 +@test Meta.parse("@a(b=1, c=2)") == Expr(:macrocall, Symbol("@a"), LineNumberNode(1, :none), :(b=1), :(c=2)) + +# issue #19685 +let f = function (x; kw...) + return (x, kw) + end, + g = function (x; a = 2) + return (x, a) + end + @test f(1) == (1, Any[]) + @test g(1) == (1, 2) +end + +# normalization of Unicode symbols (#19464) +let ε=1, μ=2, x=3, î=4 + # issue #5434 (mu vs micro): + @test Meta.parse("\u00b5") === Meta.parse("\u03bc") + @test µ == μ == 2 + # NFC normalization of identifiers: + @test Meta.parse("\u0069\u0302") === Meta.parse("\u00ee") + @test î == 4 + # latin vs greek ε (#14751) + @test Meta.parse("\u025B") === Meta.parse("\u03B5") + @test ɛ == ε == 1 +end + +# issue #8925 +let + global const (c8925, d8925) = (3, 4) +end +@test c8925 == 3 && isconst(@__MODULE__, :c8925) +@test d8925 == 4 && isconst(@__MODULE__, :d8925) + +# issue #18754: parse ccall as a regular function +@test Meta.parse("ccall([1], 2)[3]") == Expr(:ref, Expr(:call, :ccall, Expr(:vect, 1), 2), 3) +@test Meta.parse("ccall(a).member") == Expr(:., Expr(:call, :ccall, :a), QuoteNode(:member)) + +# Check that the body of a `where`-qualified short form function definition gets +# a :block for its body +short_where_call = :(f(x::T) where T = T) +@test short_where_call.args[2].head == :block + +# `where` with multi-line anonymous functions +let f = function (x::T) where T + T + end + @test f(:x) === Symbol +end + +let f = function (x::T, y::S) where T<:S where S + (T,S) + end + @test f(0,1) === (Int,Int) +end + +# issue #20541 +@test Meta.parse("[a .!b]") == Expr(:hcat, :a, Expr(:call, :(.!), :b)) + +@test Meta.lower(Main, :(a{1} = b)) == Expr(:error, "invalid type parameter name \"1\"") +@test Meta.lower(Main, :(a{2<:Any} = b)) == Expr(:error, "invalid type parameter name \"2\"") + +# issue #20653 +@test_throws UndefVarError Base.call(::Int) = 1 +module Test20653 +using Test +struct A +end +call(::A) = 1 +const a = A() +@test_throws MethodError a() +@test call(a) === 1 +end + +# issue #20729 +macro m20729() + ex = Expr(:head) + resize!(ex.args, 1) + return ex +end + +@test_throws ErrorException eval(@__MODULE__, :(@m20729)) +@test Meta.lower(@__MODULE__, :(@m20729)) == Expr(:error, "undefined reference in AST") + +macro err20000() + return Expr(:error, "oops!") +end + +@test Meta.lower(@__MODULE__, :(@err20000)) == Expr(:error, "oops!") + +# issue #20000 +@test Meta.parse("@m(a; b=c)") == Expr(:macrocall, Symbol("@m"), LineNumberNode(1, :none), + Expr(:parameters, Expr(:kw, :b, :c)), :a) + +# issue #21054 +macro make_f21054(T) + quote + $(esc(:f21054))(X::Type{<:$T}) = 1 + end +end +@eval @make_f21054 $Array +@test isa(f21054, Function) +g21054(>:) = >:2 +@test g21054(-) == -2 + +# issue #21168 +@test Meta.lower(Main, :(a.[1])) == Expr(:error, "invalid syntax a.[1]") +@test Meta.lower(Main, :(a.{1})) == Expr(:error, "invalid syntax a.{1}") + +# Issue #21225 +let abstr = Meta.parse("abstract type X end") + @test Meta.parse("abstract type X; end") == abstr + @test Meta.parse(string("abstract type X", ";"^5, " end")) == abstr + @test Meta.parse("abstract type X\nend") == abstr + @test Meta.parse(string("abstract type X", "\n"^5, "end")) == abstr +end +let prim = Meta.parse("primitive type X 8 end") + @test Meta.parse("primitive type X 8; end") == prim + @test Meta.parse(string("primitive type X 8", ";"^5, " end")) == prim + @test Meta.parse("primitive type X 8\nend") == prim + @test Meta.parse(string("primitive type X 8", "\n"^5, "end")) == prim +end + +# issue #21155 +@test filter(!isline, + Meta.parse("module B + using ..x, + ..y + end").args[3].args)[1] == + Expr(:toplevel, + Expr(:using, Symbol("."), Symbol("."), :x), + Expr(:using, Symbol("."), Symbol("."), :y)) + +@test filter(!isline, + Meta.parse("module A + using .B, + .C + end").args[3].args)[1] == + Expr(:toplevel, + Expr(:using, Symbol("."), :B), + Expr(:using, Symbol("."), :C)) + +# issue #21440 +@test Meta.parse("+(x::T,y::T) where {T} = 0") == Meta.parse("(+)(x::T,y::T) where {T} = 0") +@test Meta.parse("a::b::c") == Expr(:(::), Expr(:(::), :a, :b), :c) + +# issue #21545 +f21545(::Type{<: AbstractArray{T,N} where N}) where T = T +@test f21545(Array{Int8}) === Int8 +@test Meta.parse("<:{T} where T") == Expr(:where, Expr(:curly, :(<:), :T), :T) +@test Meta.parse("<:(T) where T") == Expr(:where, Expr(:(<:), :T), :T) +@test Meta.parse("<:{T}(T) where T") == Expr(:where, Expr(:call, Expr(:curly, :(<:), :T), :T), :T) + +# issue #21586 +macro m21586(x) + Expr(:kw, esc(x), 42) +end + +f21586(; @m21586(a), @m21586(b)) = a + b +@test f21586(a=10) == 52 + +# issue #21604 +@test_nowarn @eval module Test21604 + const Foo = Any + struct X + x::Foo + end +end +@test Test21604.X(1.0) === Test21604.X(1.0) + +# issue #20575 +@test_throws ParseError Meta.parse("\"a\"x") +@test_throws ParseError Meta.parse("\"a\"begin end") + +# comment 298107224 on pull #21607 +module Test21607 + using Test + const Any = Integer + + # check that X <: Core.Any, not Integer + mutable struct X; end + @test supertype(X) === Core.Any + + # check that return type is Integer + f()::Any = 1.0 + @test f() === 1 + + # check that constructor accepts Any + struct Y + x + end + @test Y(1.0) !== Y(1) + + # check that function default argument type is Any + g(x) = x + @test g(1.0) === 1.0 + + # check that asserted variable type is Integer + @test let + x::Any = 1.0 + x + end === 1 + + # check that unasserted variable type is not Integer + @test let + x = 1.0 + x + end === 1.0 +end + +# issue #16937 +@test Meta.lower(Main, :(f(2, a=1, w=3, c=3, w=4, b=2))) == + Expr(:error, "keyword argument \"w\" repeated in call to \"f\"") + +let f(x) = + g(x) = 1 + @test functionloc(f(1))[2] > functionloc(f)[2] +end + +# let-bound functions with `where` and static parameters +@test let f()::Int = 2.0 + f() +end === 2 +@test let (f(x::T)::Tuple{Int,Any}) where {T} = (3.0, T) + f("") +end === (3, String) + +# operator suffixes +@test Meta.parse("3 +̂ 4") == Expr(:call, :+̂, 3, 4) +@test Meta.parse("3 +̂′ 4") == Expr(:call, :+̂′, 3, 4) +@test Meta.parse("3 +⁽¹⁾ 4") == Expr(:call, :+⁽¹⁾, 3, 4) +@test Meta.parse("3 +₍₀₎ 4") == Expr(:call, :+₍₀₎, 3, 4) +for bad in ('=', '$', ':', "||", "&&", "->", "<:") + @test_throws ParseError Meta.parse("3 $(bad)⁽¹⁾ 4") +end +@test Base.operator_precedence(:+̂) == Base.operator_precedence(:+) + +# issue #19351 +# adding return type decl should not affect parse of function body +@test :(t(abc) = 3).args[2] == :(t(abc)::Int = 3).args[2] + +# issue #7314 +@test Meta.parse("local x, y = 1, 2") == Expr(:local, Expr(:(=), + Expr(:tuple, :x, :y), + Expr(:tuple, 1, 2))) + +@test_throws ParseError Meta.parse("[2for i=1:10]") +@test_throws ParseError Meta.parse("[1 for i in 1:2for j in 2]") +@test_throws ParseError Meta.parse("(1 for i in 1:2for j in 2)") +# issue #20441 +@test_throws ParseError Meta.parse("[x.2]") +@test_throws ParseError Meta.parse("x.2") +@test Meta.parse("[x;.2]") == Expr(:vcat, :x, 0.2) + +# issue #22840 +@test Meta.parse("[:a :b]") == Expr(:hcat, QuoteNode(:a), QuoteNode(:b)) + +# issue #22868 +@test_throws ParseError Meta.parse("x@time 2") +@test_throws ParseError Meta.parse("@ time") + +# issue #7479 +@test Meta.lower(Main, Meta.parse("(true &&& false)")) == Expr(:error, "misplaced \"&\" expression") + +# if an indexing expression becomes a cat expression, `end` is not special +@test_throws ParseError Meta.parse("a[end end]") +@test_throws ParseError Meta.parse("a[end;end]") +#@test_throws ParseError Meta.parse("a[end;]") # this is difficult to fix +let a = rand(8), i = 3 + @test a[[1:i-1; i+1:end]] == a[[1,2,4,5,6,7,8]] +end + +# issue #18935 +@test [begin + @inbounds for i = 1:10 end + end for i = 1:5] == fill(nothing, 5) + +# issue #18912 +@test_throws ParseError Meta.parse("(::)") +@test Meta.parse(":(::)") == QuoteNode(Symbol("::")) +@test_throws ParseError Meta.parse("f(::) = ::") +@test Meta.parse("(::A)") == Expr(Symbol("::"), :A) +@test_throws ParseError Meta.parse("(::, 1)") +@test_throws ParseError Meta.parse("(1, ::)") + +# issue #18650 +let ex = Meta.parse("maximum(@elapsed sleep(1) for k = 1:10)") + @test isa(ex, Expr) && ex.head === :call && ex.args[2].head === :generator && + ex.args[2].args[1].head === :macrocall +end + +# issue #23173 +@test_throws ErrorException("invalid module path") eval(:(import $(:.))) + +# issue #23234 +let + f = function (x=0) + x + end + @test f() == 0 + @test f(2) == 2 +end + +# issue #18730 +@test Meta.lower(Main, quote + function f() + local Int + x::Int -> 2 + end + end) == Expr(:error, "local variable Int cannot be used in closure declaration") + +# some issues with backquote +# preserve QuoteNode and LineNumberNode +@test eval(Expr(:quote, QuoteNode(Expr(:tuple, 1, Expr(:$, :(1+2)))))) == QuoteNode(Expr(:tuple, 1, 3)) +@test eval(Expr(:quote, Expr(:line, Expr(:$, :(1+2))))) === LineNumberNode(3, nothing) +# splicing at the top level should be an error +xs23917 = [1,2,3] +@test_throws ErrorException eval(:(:($(xs23917...)))) +let ex2 = eval(:(:(:($$(xs23917...))))) + @test ex2 isa Expr + @test_throws ErrorException eval(ex2) + @test eval(:($(xs23917...),)) == (1,2,3) # adding a comma gives a tuple +end +# multi-unquote of splice in nested quote +let xs = [:(1+2), :(3+4), :(5+6)] + ex = quote quote $$(xs...) end end + @test ex.args[2].args[1].args[2].args[2] == :(3 + 4) + ex2 = eval(ex) + @test ex2.args[2:end] == [3,7,11] +end + +# issue #23519 +@test Meta.parse("@foo[1]") == Meta.parse("@foo([1])") +@test Meta.parse("@foo[1 2; 3 4]") == Meta.parse("@foo([1 2; 3 4])") +@test Meta.parse("@foo[1] + [2]") == Meta.parse("@foo([1]) + [2]") +@test Meta.parse("@foo [1] + [2]") == Meta.parse("@foo([1] + [2])") +@test Meta.parse("@Mdl.foo[1] + [2]") == Meta.parse("@Mdl.foo([1]) + [2]") +@test Meta.parse("@Mdl.foo [1] + [2]") == Meta.parse("@Mdl.foo([1] + [2])") + +# issue #24289 +macro m24289() + :(global $(esc(:x24289)) = 1) +end +@test (@macroexpand @m24289) == :(global x24289 = 1) + +# parsing numbers with _ and . +@test Meta.parse("1_2.3_4") == 12.34 +@test_throws ParseError Meta.parse("1._") +@test_throws ParseError Meta.parse("1._5") +@test_throws ParseError Meta.parse("1e.3") +@test_throws ParseError Meta.parse("1e3.") +@test Meta.parse("2e_1") == Expr(:call, :*, 2, :e_1) +# issue #17705 +@test Meta.parse("2e3_") == Expr(:call, :*, 2e3, :_) +@test Meta.parse("2e-3_") == Expr(:call, :*, 2e-3, :_) +@test Meta.parse("2e3_\"x\"") == Expr(:call, :*, 2e3, Expr(:macrocall, Symbol("@__str"), LineNumberNode(1, :none), "x")) +