diff --git a/NEWS.md b/NEWS.md index 50bef68b74857..f501d039b7e8b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -32,6 +32,12 @@ Language changes * A warning is always given when a method is overwritten (previously, this was done only when the new and old definitions were in separate modules) ([#14759]). + * `A <: B` is parsed as `Expr(:(<:), :A, :B)` in all cases ([#9503]). This also applies to the + `>:` operator. + + * Simple 2-argument comparisons like `A < B` are parsed as calls intead of using the + `:comparison` expression type. + Command-line option changes --------------------------- @@ -1690,6 +1696,7 @@ Too numerous to mention. [#9434]: https://github.com/JuliaLang/julia/issues/9434 [#9452]: https://github.com/JuliaLang/julia/issues/9452 [#9487]: https://github.com/JuliaLang/julia/issues/9487 +[#9503]: https://github.com/JuliaLang/julia/issues/9503 [#9569]: https://github.com/JuliaLang/julia/issues/9569 [#9575]: https://github.com/JuliaLang/julia/issues/9575 [#9578]: https://github.com/JuliaLang/julia/issues/9578 @@ -1793,4 +1800,6 @@ Too numerous to mention. [#14469]: https://github.com/JuliaLang/julia/issues/14469 [#14759]: https://github.com/JuliaLang/julia/issues/14759 [#14798]: https://github.com/JuliaLang/julia/issues/14798 +[#15192]: https://github.com/JuliaLang/julia/issues/15192 [#15242]: https://github.com/JuliaLang/julia/issues/15242 +[#15258]: https://github.com/JuliaLang/julia/issues/15258 diff --git a/base/linalg/cholesky.jl b/base/linalg/cholesky.jl index d70d5a8d880a5..416845e7b0724 100644 --- a/base/linalg/cholesky.jl +++ b/base/linalg/cholesky.jl @@ -276,7 +276,7 @@ end function det(C::Cholesky) dd = one(eltype(C)) - for i in 1:size(C.factors,1) dd *= abs2(C.factors[i,i]) end + for i in 1:size(C.factors,1); dd *= abs2(C.factors[i,i]) end dd end @@ -284,7 +284,7 @@ det(C::CholeskyPivoted) = C.rank < size(C.factors, 1) ? real(zero(eltype(C))) : function logdet(C::Cholesky) dd = zero(eltype(C)) - for i in 1:size(C.factors,1) dd += log(C.factors[i,i]) end + for i in 1:size(C.factors,1); dd += log(C.factors[i,i]) end dd + dd # instead of 2.0dd which can change the type end diff --git a/base/linalg/dense.jl b/base/linalg/dense.jl index 1918511cd202a..7462da43a7846 100644 --- a/base/linalg/dense.jl +++ b/base/linalg/dense.jl @@ -248,7 +248,7 @@ function expm!{T<:BlasFloat}(A::StridedMatrix{T}) LAPACK.gesv!(V-U, X) if s > 0 # squaring to reverse dividing by power of 2 - for t=1:si X *= X end + for t=1:si; X *= X end end end @@ -264,10 +264,10 @@ function expm!{T<:BlasFloat}(A::StridedMatrix{T}) end if ilo > 1 # apply lower permutations in reverse order - for j in (ilo-1):-1:1 rcswap!(j, Int(scale[j]), X) end + for j in (ilo-1):-1:1; rcswap!(j, Int(scale[j]), X) end end if ihi < n # apply upper permutations in forward order - for j in (ihi+1):n rcswap!(j, Int(scale[j]), X) end + for j in (ihi+1):n; rcswap!(j, Int(scale[j]), X) end end X end diff --git a/base/sparse/cholmod.jl b/base/sparse/cholmod.jl index dbf65105356fb..7f0d6510430a6 100644 --- a/base/sparse/cholmod.jl +++ b/base/sparse/cholmod.jl @@ -1517,7 +1517,7 @@ end function logdet{Tv<:VTypes}(F::Factor{Tv}) f = unsafe_load(get(F.p)) res = zero(Tv) - for d in diag(F) res += log(abs(d)) end + for d in diag(F); res += log(abs(d)) end f.is_ll!=0 ? 2res : res end diff --git a/base/sparse/linalg.jl b/base/sparse/linalg.jl index 36303403bb918..338484f55d883 100644 --- a/base/sparse/linalg.jl +++ b/base/sparse/linalg.jl @@ -6,14 +6,14 @@ import Base.LinAlg: checksquare # Convert from 1-based to 0-based indices function decrement!{T<:Integer}(A::AbstractArray{T}) - for i in 1:length(A) A[i] -= one(T) end + for i in 1:length(A); A[i] -= one(T) end A end decrement{T<:Integer}(A::AbstractArray{T}) = decrement!(copy(A)) # Convert from 0-based to 1-based indices function increment!{T<:Integer}(A::AbstractArray{T}) - for i in 1:length(A) A[i] += one(T) end + for i in 1:length(A); A[i] += one(T) end A end increment{T<:Integer}(A::AbstractArray{T}) = increment!(copy(A)) diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index 76016b87d2292..29b361245516a 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -3084,7 +3084,7 @@ spdiagm(B::AbstractVector, d::Number=0) = spdiagm((B,), (d,)) function expandptr{T<:Integer}(V::Vector{T}) if V[1] != 1 throw(ArgumentError("first index must be one")) end res = similar(V, (Int64(V[end]-1),)) - for i in 1:(length(V)-1), j in V[i]:(V[i+1] - 1) res[j] = i end + for i in 1:(length(V)-1), j in V[i]:(V[i+1] - 1); res[j] = i end res end diff --git a/base/strings/basic.jl b/base/strings/basic.jl index 4375b827d6da8..2cf4179b0f457 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -39,7 +39,7 @@ getindex(s::AbstractString, i::Integer) = s[Int(i)] getindex{T<:Integer}(s::AbstractString, r::UnitRange{T}) = s[Int(first(r)):Int(last(r))] # TODO: handle other ranges with stride ±1 specially? getindex(s::AbstractString, v::AbstractVector) = - sprint(length(v), io->(for i in v write(io,s[i]) end)) + sprint(length(v), io->(for i in v; write(io,s[i]) end)) symbol(s::AbstractString) = symbol(bytestring(s)) diff --git a/base/test.jl b/base/test.jl index 168a53b4c2258..0b1fad045c21e 100644 --- a/base/test.jl +++ b/base/test.jl @@ -151,6 +151,11 @@ Returns a `Pass` `Result` if it does, a `Fail` `Result` if it is """ macro test(ex) orig_ex = Expr(:quote,ex) + # Normalize comparison operator calls to :comparison expressions + if isa(ex, Expr) && ex.head == :call && length(ex.args)==3 && + Base.operator_precedence(ex.args[1]) == Base.operator_precedence(:(==)) + ex = Expr(:comparison, ex.args[2], ex.args[1], ex.args[3]) + end # If the test is a comparison if isa(ex, Expr) && ex.head == :comparison # Generate a temporary for every term in the expression diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 566134e6f5eeb..c7735026d32f1 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -780,12 +780,21 @@ (let loop ((ex (parse-pipes s)) (first #t)) (let ((t (peek-token s))) - (if (not (is-prec-comparison? t)) - ex - (begin (take-token s) - (if first - (loop (list 'comparison ex t (parse-pipes s)) #f) - (loop (append ex (list t (parse-pipes s))) #f))))))) + (cond ((is-prec-comparison? t) + (begin (take-token s) + (if first + (loop (list 'comparison ex t (parse-pipes s)) #f) + (loop (append ex (list t (parse-pipes s))) #f)))) + (first ex) + ((length= ex 4) + ;; only a single comparison; special chained syntax not required + (let ((op (caddr ex)) + (arg1 (cadr ex)) + (arg2 (cadddr ex))) + (if (or (eq? op '|<:|) (eq? op '|>:|)) + `(,op ,arg1 ,arg2) + `(call ,op ,arg1 ,arg2)))) + (else ex))))) (define closing-token? (let ((closer? (Set '(else elseif catch finally #\, #\) #\] #\} #\;)))) @@ -905,13 +914,6 @@ (else ex))))) -;; convert (comparison a <: b) to (<: a b) -(define (subtype-syntax e) - (if (and (pair? e) (eq? (car e) 'comparison) - (length= e 4) (eq? (caddr e) '|<:|)) - `(<: ,(cadr e) ,(cadddr e)) - e)) - (define (parse-unary-prefix s) (let ((op (peek-token s))) (if (syntactic-unary-op? op) @@ -1031,8 +1033,7 @@ (string (deparse ex) " " (deparse t)) (string (deparse ex) (deparse t)))) (take-token s) - (loop (list* 'curly ex - (map subtype-syntax (parse-arglist s #\} ))))) + (loop (list* 'curly ex (parse-arglist s #\} )))) ((#\") (if (and (symbol? ex) (not (operator? ex)) (not (ts:space? s))) @@ -1066,7 +1067,7 @@ " expected \"end\", got \"" t "\"")))))) (define (parse-subtype-spec s) - (subtype-syntax (parse-comparison s))) + (parse-comparison s)) ;; parse expressions or blocks introduced by syntactic reserved words (define (parse-resword s word) @@ -1399,14 +1400,20 @@ ;; as above, but allows both "i=r" and "i in r" (define (parse-iteration-spec s) - (let ((r (parse-eq* s))) - (cond ((and (pair? r) (eq? (car r) '=)) r) - ((eq? r ':) r) - ((and (length= r 4) (eq? (car r) 'comparison) - (or (eq? (caddr r) 'in) (eq? (caddr r) '∈))) - `(= ,(cadr r) ,(cadddr r))) - (else - (error "invalid iteration specification"))))) + (let* ((lhs (parse-pipes s)) + (t (peek-token s))) + (cond ((memq t '(= in ∈)) + (take-token s) + (let* ((rhs (parse-pipes s)) + (t (peek-token s))) + #;(if (not (or (closing-token? t) (newline? t))) + ;; should be: (error "invalid iteration specification") + (syntax-deprecation s (string "for " (deparse `(= ,lhs ,rhs)) " " t) + (string "for " (deparse `(= ,lhs ,rhs)) "; " t))) + `(= ,lhs ,rhs))) + ((and (eq? lhs ':) (closing-token? t)) + ':) + (else (error "invalid iteration specification"))))) (define (parse-comma-separated-iters s) (let loop ((ranges '())) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 260d43b7916c9..7a7bb95419cf9 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1482,6 +1482,10 @@ `(call (top next) ,coll ,state)) ,body)))))))) +;; convert an operator parsed as (op a b) to (call op a b) +(define (syntactic-op-to-call e) + `(call ,(car e) ,(expand-forms (cadr e)) ,(expand-forms (caddr e)))) + ;; table mapping expression head to a function expanding that form (define expand-table (table @@ -1518,9 +1522,8 @@ (lambda (e) `(call (top getfield) ,(expand-forms (cadr e)) ,(expand-forms (caddr e)))) - 'in - (lambda (e) - `(call in ,(expand-forms (cadr e)) ,(expand-forms (caddr e)))) + '|<:| syntactic-op-to-call + '|>:| syntactic-op-to-call 'const expand-const-decl 'local expand-local-or-global-decl diff --git a/test/parse.jl b/test/parse.jl index d0ff8b9fa094e..35e00542bb8c6 100644 --- a/test/parse.jl +++ b/test/parse.jl @@ -22,9 +22,9 @@ let ("5.≥x", "5.>=x"), ("5.≤x", "5.<=x")] ex1 = parse(ex1); ex2 = parse(ex2) - @test ex1.head === :comparison && (ex1.head === ex2.head) - @test ex1.args[1] === 5 && ex2.args[1] === 5 - @test is(eval(Main, ex1.args[2]), eval(Main, ex2.args[2])) + @test ex1.head === :call && (ex1.head === ex2.head) + @test ex1.args[2] === 5 && ex2.args[2] === 5 + @test is(eval(Main, ex1.args[1]), eval(Main, ex2.args[1])) @test ex1.args[3] === :x && (ex1.args[3] === ex2.args[3]) end end @@ -291,7 +291,7 @@ for T in (UInt8,UInt16,UInt32,UInt64) @test_throws OverflowError parse(T,string(big(typemax(T))+1)) end -@test parse("1 == 2|>3") == Expr(:comparison, 1, :(==), Expr(:call, :(|>), 2, 3)) +@test parse("1 == 2|>3") == Expr(:call, :(==), 1, Expr(:call, :(|>), 2, 3)) # issue #12501 and pr #12502 parse(""" @@ -365,3 +365,9 @@ let a⊂b = reduce(&, x ∈ b for x in a) && length(b)>length(a) @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