# 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(":(importall A)") == Expr(:quote, Expr(:importall, :A)) @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 "" """) == Expr(:toplevel, Expr(:macro, Expr(:call, :f, Expr(:..., :args)), Expr(:block, Expr(:line, 1, :none))), Expr(:macrocall, Symbol("@f"), "")) # 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) @test parse(Int32,"9",36) === Int32(9) @test parse(Int32,"A",36) === Int32(10) @test parse(Int32,"a",36) === Int32(10) @test parse(Int32,"B",36) === Int32(11) @test parse(Int32,"b",36) === Int32(11) @test parse(Int32,"F",36) === Int32(15) @test parse(Int32,"f",36) === Int32(15) @test parse(Int32,"Z",36) === Int32(35) @test parse(Int32,"z",36) === Int32(35) @test parse(Int,"0") == 0 @test parse(Int,"-0") == 0 @test parse(Int,"1") == 1 @test parse(Int,"-1") == -1 @test parse(Int,"9") == 9 @test parse(Int,"-9") == -9 @test parse(Int,"10") == 10 @test parse(Int,"-10") == -10 @test parse(Int64,"3830974272") == 3830974272 @test parse(Int64,"-3830974272") == -3830974272 @test parse(Int,'3') == 3 @test parse(Int,'3', 8) == 3 # Issue 20587 for T in vcat(subtypes(Signed), subtypes(Unsigned)) for s in ["", " ", " "] # Without a base (handles things like "0x00001111", etc) result = @test_throws ArgumentError parse(T, s) exception_without_base = result.value if T == Bool if s == "" @test exception_without_base.msg == "input string is empty" else @test exception_without_base.msg == "input string only contains whitespace" end else @test exception_without_base.msg == "input string is empty or only contains whitespace" end # With a base result = @test_throws ArgumentError parse(T, s, 16) exception_with_base = result.value if T == Bool if s == "" @test exception_with_base.msg == "input string is empty" else @test exception_with_base.msg == "input string only contains whitespace" end else @test exception_with_base.msg == "input string is empty or only contains whitespace" end end # Test `tryparse_internal` with part of a string let b = " " result = @test_throws ArgumentError get(Base.tryparse_internal(Bool, b, 7, 11, 0, true)) exception_bool = result.value @test exception_bool.msg == "input string only contains whitespace" result = @test_throws ArgumentError get(Base.tryparse_internal(Int, b, 7, 11, 0, true)) exception_int = result.value @test exception_int.msg == "input string is empty or only contains whitespace" result = @test_throws ArgumentError get(Base.tryparse_internal(UInt128, b, 7, 11, 0, true)) exception_uint = result.value @test exception_uint.msg == "input string is empty or only contains whitespace" end # Test that the entire input string appears in error messages let s = " false true " result = @test_throws(ArgumentError, get(Base.tryparse_internal(Bool, s, start(s), endof(s), 0, true))) @test result.value.msg == "invalid Bool representation: $(repr(s))" end # Test that leading and trailing whitespace is ignored. for v in (1, 2, 3) @test parse(Int, " $v" ) == v @test parse(Int, " $v\n" ) == v @test parse(Int, "$v " ) == v @test parse(Int, " $v ") == v end for v in (true, false) @test parse(Bool, " $v" ) == v @test parse(Bool, " $v\n" ) == v @test parse(Bool, "$v " ) == v @test parse(Bool, " $v ") == v end for v in (0.05, -0.05, 2.5, -2.5) @test parse(Float64, " $v" ) == v @test parse(Float64, " $v\n" ) == v @test parse(Float64, "$v " ) == v @test parse(Float64, " $v ") == v end @test parse(Float64, " .5" ) == 0.5 @test parse(Float64, " .5\n" ) == 0.5 @test parse(Float64, " .5 ") == 0.5 @test parse(Float64, ".5 " ) == 0.5 end @test parse(Bool, "\u202f true") === true @test parse(Bool, "\u202f false") === false parsebin(s) = parse(Int,s,2) parseoct(s) = parse(Int,s,8) parsehex(s) = parse(Int,s,16) @test parsebin("0") == 0 @test parsebin("-0") == 0 @test parsebin("1") == 1 @test parsebin("-1") == -1 @test parsebin("10") == 2 @test parsebin("-10") == -2 @test parsebin("11") == 3 @test parsebin("-11") == -3 @test parsebin("1111000011110000111100001111") == 252645135 @test parsebin("-1111000011110000111100001111") == -252645135 @test parseoct("0") == 0 @test parseoct("-0") == 0 @test parseoct("1") == 1 @test parseoct("-1") == -1 @test parseoct("7") == 7 @test parseoct("-7") == -7 @test parseoct("10") == 8 @test parseoct("-10") == -8 @test parseoct("11") == 9 @test parseoct("-11") == -9 @test parseoct("72") == 58 @test parseoct("-72") == -58 @test parseoct("3172207320") == 434704080 @test parseoct("-3172207320") == -434704080 @test parsehex("0") == 0 @test parsehex("-0") == 0 @test parsehex("1") == 1 @test parsehex("-1") == -1 @test parsehex("9") == 9 @test parsehex("-9") == -9 @test parsehex("a") == 10 @test parsehex("-a") == -10 @test parsehex("f") == 15 @test parsehex("-f") == -15 @test parsehex("10") == 16 @test parsehex("-10") == -16 @test parsehex("0BADF00D") == 195948557 @test parsehex("-0BADF00D") == -195948557 @test parse(Int64,"BADCAB1E",16) == 3135023902 @test parse(Int64,"-BADCAB1E",16) == -3135023902 @test parse(Int64,"CafeBabe",16) == 3405691582 @test parse(Int64,"-CafeBabe",16) == -3405691582 @test parse(Int64,"DeadBeef",16) == 3735928559 @test parse(Int64,"-DeadBeef",16) == -3735928559 @test parse(Int,"2\n") == 2 @test parse(Int," 2 \n ") == 2 @test parse(Int," 2 ") == 2 @test parse(Int,"2 ") == 2 @test parse(Int," 2") == 2 @test parse(Int,"+2\n") == 2 @test parse(Int,"-2") == -2 @test_throws ArgumentError parse(Int," 2 \n 0") @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"), "x")) # multibyte spaces @test parse(Int, "3\u2003\u202F") == 3 @test_throws ArgumentError parse(Int, "3\u2003\u202F,") @test parse(Int,'a') == 10 @test_throws ArgumentError parse(Int,typemax(Char)) @test parse(Int,"1234") == 1234 @test parse(Int,"0x1234") == 0x1234 @test parse(Int,"0o1234") == 0o1234 @test parse(Int,"0b1011") == 0b1011 @test parse(Int,"-1234") == -1234 @test parse(Int,"-0x1234") == -Int(0x1234) @test parse(Int,"-0o1234") == -Int(0o1234) @test parse(Int,"-0b1011") == -Int(0b1011) for T in (Int8, Int16, Int32, Int64, Int128) @test parse(T,string(typemin(T))) == typemin(T) @test parse(T,string(typemax(T))) == typemax(T) @test_throws OverflowError parse(T,string(big(typemin(T))-1)) @test_throws OverflowError parse(T,string(big(typemax(T))+1)) end for T in (UInt8,UInt16,UInt32,UInt64,UInt128) @test parse(T,string(typemin(T))) == typemin(T) @test parse(T,string(typemax(T))) == typemax(T) @test_throws ArgumentError parse(T,string(big(typemin(T))-1)) @test_throws OverflowError parse(T,string(big(typemax(T))+1)) end @test parse("1 == 2|>3") == Expr(:call, :(==), 1, Expr(:call, :(|>), 2, 3)) # 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 expand(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(:block, Expr(:line, 2, :none), :x), Expr(:(=), :x, :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 expand(parse("x...")) == Expr(:error, "\"...\" expression outside call") # issue #15830 @test expand(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 expand(parse("true(x) = x")) == Expr(:error, "invalid function name \"true\"") @test expand(parse("false(x) = x")) == Expr(:error, "invalid function name \"false\"") # issue #16355 @test expand(:(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,Expr) && x.head === :line # 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, Expr(:line, 1, :none), :x), false, Expr(:block, Expr(:line, 2, :none), Expr(:call, :test), Expr(:line, 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_throws ParseError parse("{1,2,3}") #@test_throws ParseError parse("{1 2 3 4}") #@test_throws ParseError parse("{1,2; 3,4}") @test_throws ParseError parse("{x for x in 1:10}") @test_throws ParseError parse("{x=>y for (x,y) in zip([1,2,3],[4,5,6])}") #@test_throws ParseError parse("{:a=>1, :b=>2}") @test parse("A=>B") == Expr(:call, :(=>), :A, :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)) @test n == 123 @test isa(n, T) end end # issue #16720 let err = try include_string("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 @test parse(Bool, "false") === false @test get(tryparse(Bool, "true")) === get(Nullable{Bool}(true)) @test get(tryparse(Bool, "false")) === get(Nullable{Bool}(false)) @test_throws ArgumentError parse(Int, "2", 1) @test_throws ArgumentError parse(Int, "2", 63) # issue #17333: tryparse should still throw on invalid base for T in (Int32, BigInt), base in (0,1,100) @test_throws ArgumentError tryparse(T, "0", base) end # error throwing branch from #10560 @test_throws ArgumentError Base.tryparse_internal(Bool, "foo", 1, 2, 10, true) @test tryparse(Float64, "1.23") === Nullable(1.23) @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{N}(types::NTuple{N}, values::Vararg{Any,N}, c) = 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 expand(parse("let global x = 2 local x = 1 end")) == Expr(:error, "variable \"x\" declared both local and global") @test expand(parse("let local x = 2 local x = 1 end")) == Expr(:error, "local \"x\" declared twice") @test expand(parse("let x local x = 1 end")) == Expr(:error, "local \"x\" declared twice") @test expand(parse("let x = 2 local x = 1 end")) == Expr(:error, "local \"x\" declared twice") # make sure front end can correctly print values to error messages let ex = expand(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 expand(:(@inline f(p::Int=2) = 3)).args[2].args[3].inlineable # issue #16096 module M16096 macro iter() quote @inline function foo(sub) it = 1 end end end end let ex = expand(:(@M16096.iter)) @test !(isa(ex,Expr) && ex.head === :error) 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 nometh = expand(:(A15838.@f(1, 2))) @test (nometh::Expr).head === :error @test length(nometh.args) == 1 e = nometh.args[1]::MethodError @test e.f === getfield(A15838, Symbol("@f")) @test e.args === (1,2) end # issue 10046 for op in ["+", "-", "\$", "|", ".+", ".-", "*", ".*"] @test_throws ParseError parse("$op in [+, -]") end # issue #17701 @test expand(:(i==3 && i+=1)) == Expr(:error, "invalid assignment location \"==(i,3)&&i\"") # issue #18667 @test expand(:(true = 1)) == Expr(:error, "invalid assignment location \"true\"") @test expand(:(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 Base.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(""" macro m3() quote @m1 end end macro m4() quote @m2 end end """, "another_file.jl") m1_exprs = get_expr_list(expand(:(@m1))) m2_exprs = get_expr_list(expand(:(@m2))) m3_exprs = get_expr_list(expand(:(@m3))) m4_exprs = get_expr_list(expand(:(@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 - 1]) @test Meta.isexpr(f2_exprs[end], :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 :``` multiline command ``` == :(@cmd "multiline\ncommand\n") 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 = expand(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"), :(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(:c8925) @test d8925 == 4 && isconst(: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 expand(:(a{1} = b)) == Expr(:error, "invalid type parameter name \"1\"") @test expand(:(a{2<:Any} = b)) == Expr(:error, "invalid type parameter name \"2\"") # issue #20653 @test_throws UndefVarError Base.call(::Int) = 1 module Test20653 using Base.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(:(@m20729)) @test expand(:(@m20729)) == Expr(:error, "undefined reference in AST") macro err20000() return Expr(:error, "oops!") end @test expand(:(@err20000)) == Expr(:error, "oops!") # issue #20000 @test parse("@m(a; b=c)") == Expr(:macrocall, Symbol("@m"), 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 expand(:(a.[1])) == Expr(:error, "invalid syntax a.[1]") @test expand(:(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) # comment 298107224 on pull #21607 module Test21607 using Base.Test @test_warn( "WARNING: imported binding for Any overwritten in module Test21607", @eval 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 # 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) # 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 #23234 let f = function (x=0) x end @test f() == 0 @test f(2) == 2 end