From 6978b9aa9a87cf319bb408172737203be847ffc3 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 8 Feb 2018 11:35:37 -0500 Subject: [PATCH 1/3] fix lowering of `<:` to handle `...` correctly --- src/julia-syntax.scm | 10 ++++------ test/syntax.jl | 6 ++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 754b0f470b41c..a46c6ff628d27 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1617,10 +1617,6 @@ `(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) ,@(map expand-forms (cdr e)))) - ;; wrap `expr` in a function appropriate for consuming values from given ranges (define (func-for-generator-ranges expr range-exprs) (let* ((vars (map cadr range-exprs)) @@ -1927,8 +1923,10 @@ (lambda (e) (expand-fuse-broadcast (cadr e) (caddr e))) - '|<:| syntactic-op-to-call - '|>:| syntactic-op-to-call + '|<:| + (lambda (e) (expand-forms `(call |<:| ,@(cdr e)))) + '|>:| + (lambda (e) (expand-forms `(call |>:| ,@(cdr e)))) 'where (lambda (e) (expand-forms (expand-wheres (cadr e) (cddr e)))) diff --git a/test/syntax.jl b/test/syntax.jl index 2cae098ee11be..d88701528346b 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -1265,6 +1265,12 @@ function bar16239() end @test bar16239() == 0 +# lowering of <: and >: +let args = (Int, Any) + @test <:(args...) + @test >:(reverse(args)...) +end + # issue #25020 @test_throws ParseError Meta.parse("using Colors()") From 125e3e08108cc3290e4bcafd400522697547e52b Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 8 Feb 2018 12:02:51 -0500 Subject: [PATCH 2/3] parse `:` like other operators, instead of lowering to `colon` --- NEWS.md | 3 +++ base/broadcast.jl | 3 ++- base/deprecated.jl | 1 + base/essentials.jl | 5 +++- base/exports.jl | 1 - base/range.jl | 49 ++++++++++++++-------------------- base/show.jl | 10 +++---- base/twiceprecision.jl | 2 +- doc/src/base/math.md | 2 +- doc/src/base/punctuation.md | 6 ++--- doc/src/manual/functions.md | 1 - src/ast.scm | 18 +++++++------ src/julia-parser.scm | 21 +++++---------- src/julia-syntax.scm | 25 ++++------------- stdlib/Dates/src/deprecated.jl | 8 +++--- test/ranges.jl | 18 ++++++------- test/show.jl | 9 +++++++ test/syntax.jl | 2 +- 18 files changed, 84 insertions(+), 100 deletions(-) diff --git a/NEWS.md b/NEWS.md index fd68ecce6d5ed..651f42c9ad53a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -82,6 +82,9 @@ Language changes * The parsing of `<|` is now right associative. `|>` remains left associative ([#24153]). + * `:` now parses like other operators, as a call to a function named `:`, instead of + calling `colon` ([#25947]). + * `{ }` expressions now use `braces` and `bracescat` as expression heads instead of `cell1d` and `cell2d`, and parse similarly to `vect` and `vcat` ([#8470]). diff --git a/base/broadcast.jl b/base/broadcast.jl index 6e317640e53d6..8c495c14f8b43 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -817,7 +817,8 @@ Base.@propagate_inbounds dotview(args...) = Base.maybeview(args...) # broadcasting "dot" calls/assignments: dottable(x) = false # avoid dotting spliced objects (e.g. view calls inserted by @view) -dottable(x::Symbol) = !isoperator(x) || first(string(x)) != '.' || x == :.. # don't add dots to dot operators +# don't add dots to dot operators +dottable(x::Symbol) = (!isoperator(x) || first(string(x)) != '.' || x === :..) && x !== :(:) dottable(x::Expr) = x.head != :$ undot(x) = x function undot(x::Expr) diff --git a/base/deprecated.jl b/base/deprecated.jl index b76b6c987cce3..371102cef825f 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -246,6 +246,7 @@ DEPRECATED: use @__MODULE__ instead end export current_module +@deprecate colon (:) module Operators for op in [:!, :(!=), :(!==), :%, :&, :*, :+, :-, :/, ://, :<, :<:, :<<, :(<=), diff --git a/base/essentials.jl b/base/essentials.jl index 87c2eb833b6e5..6ead9541b318e 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -591,8 +591,11 @@ Colons (:) are used to signify indexing entire objects or dimensions at once. Very few operations are defined on Colons directly; instead they are converted by [`to_indices`](@ref) to an internal vector type (`Base.Slice`) to represent the collection of indices they span before being used. + +The singleton instance of `Colon` is also a function used to construct ranges; +see [`:`](@ref). """ -struct Colon +struct Colon <: Function end const (:) = Colon() diff --git a/base/exports.jl b/base/exports.jl index e3d946d7b85dc..d99ea0f2181b6 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -367,7 +367,6 @@ export circshift, circshift!, clamp!, - colon, conj!, copy!, copyto!, diff --git a/base/range.jl b/base/range.jl index 18472f2bc9518..c8122e24e7566 100644 --- a/base/range.jl +++ b/base/range.jl @@ -1,33 +1,23 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -colon(a::Real, b::Real) = colon(promote(a,b)...) +(:)(a::Real, b::Real) = (:)(promote(a,b)...) -colon(start::T, stop::T) where {T<:Real} = UnitRange{T}(start, stop) +(:)(start::T, stop::T) where {T<:Real} = UnitRange{T}(start, stop) range(a::Real, len::Integer) = UnitRange{typeof(a)}(a, oftype(a, a+len-1)) -colon(start::T, stop::T) where {T} = colon(start, oftype(stop-start, 1), stop) +(:)(start::T, stop::T) where {T} = (:)(start, oftype(stop-start, 1), stop) range(a, len::Integer) = range(a, oftype(a-a, 1), len) # first promote start and stop, leaving step alone -colon(start::A, step, stop::C) where {A<:Real,C<:Real} = - colon(convert(promote_type(A,C),start), step, convert(promote_type(A,C),stop)) -colon(start::T, step::Real, stop::T) where {T<:Real} = colon(promote(start, step, stop)...) +(:)(start::A, step, stop::C) where {A<:Real,C<:Real} = + (:)(convert(promote_type(A,C),start), step, convert(promote_type(A,C),stop)) +(:)(start::T, step::Real, stop::T) where {T<:Real} = (:)(promote(start, step, stop)...) -""" - colon(start, [step], stop) - -Called by `:` syntax for constructing ranges. - -```jldoctest -julia> colon(1, 2, 5) -1:2:5 -``` -""" -colon(start::T, step::T, stop::T) where {T<:AbstractFloat} = +(:)(start::T, step::T, stop::T) where {T<:AbstractFloat} = _colon(OrderStyle(T), ArithmeticStyle(T), start, step, stop) -colon(start::T, step::T, stop::T) where {T<:Real} = +(:)(start::T, step::T, stop::T) where {T<:Real} = _colon(OrderStyle(T), ArithmeticStyle(T), start, step, stop) _colon(::Ordered, ::Any, start::T, step, stop::T) where {T} = StepRange(start, step, stop) # for T<:Union{Float16,Float32,Float64} see twiceprecision.jl @@ -37,16 +27,17 @@ _colon(::Any, ::Any, start::T, step, stop::T) where {T} = StepRangeLen(start, step, floor(Int, (stop-start)/step)+1) """ - :(start, [step], stop) + (:)(start, [step], stop) Range operator. `a:b` constructs a range from `a` to `b` with a step size of 1, and `a:s:b` -is similar but uses a step size of `s`. These syntaxes call the function `colon`. The colon -is also used in indexing to select whole dimensions. +is similar but uses a step size of `s`. + +`:` is also used in indexing to select whole dimensions. """ -colon(start::T, step, stop::T) where {T} = _colon(start, step, stop) -colon(start::T, step, stop::T) where {T<:Real} = _colon(start, step, stop) +(:)(start::T, step, stop::T) where {T} = _colon(start, step, stop) +(:)(start::T, step, stop::T) where {T<:Real} = _colon(start, step, stop) # without the second method above, the first method above is ambiguous with -# colon(start::A, step, stop::C) where {A<:Real,C<:Real} +# (:)(start::A, step, stop::C) where {A<:Real,C<:Real} function _colon(start::T, step, stop::T) where T T′ = typeof(start+step) StepRange(convert(T′,start), step, convert(T′,stop)) @@ -64,12 +55,12 @@ _range(::Any, ::Any, a::T, step::S, len::Integer) where {T,S} = StepRangeLen{typeof(a+0*step),T,S}(a, step, len) # AbstractFloat specializations -colon(a::T, b::T) where {T<:AbstractFloat} = colon(a, T(1), b) +(:)(a::T, b::T) where {T<:AbstractFloat} = (:)(a, T(1), b) range(a::AbstractFloat, len::Integer) = range(a, oftype(a, 1), len) -colon(a::T, b::AbstractFloat, c::T) where {T<:Real} = colon(promote(a,b,c)...) -colon(a::T, b::AbstractFloat, c::T) where {T<:AbstractFloat} = colon(promote(a,b,c)...) -colon(a::T, b::Real, c::T) where {T<:AbstractFloat} = colon(promote(a,b,c)...) +(:)(a::T, b::AbstractFloat, c::T) where {T<:Real} = (:)(promote(a,b,c)...) +(:)(a::T, b::AbstractFloat, c::T) where {T<:AbstractFloat} = (:)(promote(a,b,c)...) +(:)(a::T, b::Real, c::T) where {T<:AbstractFloat} = (:)(promote(a,b,c)...) range(a::AbstractFloat, st::AbstractFloat, len::Integer) = range(promote(a, st)..., len) range(a::Real, st::AbstractFloat, len::Integer) = range(float(a), st, len) @@ -887,7 +878,7 @@ end Array{T,1}(r::AbstractRange{T}) where {T} = vcat(r) collect(r::AbstractRange) = vcat(r) -reverse(r::OrdinalRange) = colon(last(r), -step(r), first(r)) +reverse(r::OrdinalRange) = (:)(last(r), -step(r), first(r)) reverse(r::StepRangeLen) = StepRangeLen(r.ref, -r.step, length(r), length(r)-r.offset+1) reverse(r::LinSpace) = LinSpace(r.stop, r.start, length(r)) diff --git a/base/show.jl b/base/show.jl index 01d50820ddc35..d473b9816f9d0 100644 --- a/base/show.jl +++ b/base/show.jl @@ -971,8 +971,8 @@ end # show a normal (non-operator) function call, e.g. f(x, y) or A[z] function show_call(io::IO, head, func, func_args, indent) op, cl = expr_calls[head] - if isa(func, Symbol) || (isa(func, Expr) && - (func.head == :. || func.head == :curly)) + if (isa(func, Symbol) && func !== :(:)) || + (isa(func, Expr) && (func.head == :. || func.head == :curly)) show_unquoted(io, func, indent) else print(io, '(') @@ -1153,7 +1153,7 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) end # infix (i.e. "x <: y" or "x = y") - elseif (head in expr_infix_any && nargs==2) || (head === :(:) && nargs==3) + elseif (head in expr_infix_any && nargs==2) func_prec = operator_precedence(head) head_ = head in expr_infix_wide ? " $head " : head if func_prec <= prec @@ -1222,9 +1222,9 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) # binary operator (i.e. "x + y") elseif func_prec > 0 # is a binary operator na = length(func_args) - if (na == 2 || (na > 2 && func in (:+, :++, :*))) && + if (na == 2 || (na > 2 && func in (:+, :++, :*)) || (na == 3 && func === :(:))) && all(!isa(a, Expr) || a.head !== :... for a in func_args) - sep = " $func " + sep = func === :(:) ? "$func" : " $func " if func_prec <= prec show_enclosed_list(io, '(', func_args, sep, ')', indent, func_prec, true) diff --git a/base/twiceprecision.jl b/base/twiceprecision.jl index 305d3a8c507cd..41eb19e608b32 100644 --- a/base/twiceprecision.jl +++ b/base/twiceprecision.jl @@ -380,7 +380,7 @@ function floatrange(a::AbstractFloat, st::AbstractFloat, len::Real, divisor::Abs steprangelen_hp(T, (a,divisor), (st,divisor), nbitslen(T, len, 1), Int(len), 1) end -function colon(start::T, step::T, stop::T) where T<:Union{Float16,Float32,Float64} +function (:)(start::T, step::T, stop::T) where T<:Union{Float16,Float32,Float64} step == 0 && throw(ArgumentError("range step cannot be zero")) # see if the inputs have exact rational approximations (and if so, # perform all computations in terms of the rationals) diff --git a/doc/src/base/math.md b/doc/src/base/math.md index 6b8cbf0bdaa7f..46b3fc195067f 100644 --- a/doc/src/base/math.md +++ b/doc/src/base/math.md @@ -32,7 +32,7 @@ Base.denominator Base.:(<<) Base.:(>>) Base.:(>>>) -Base.colon +Base.:(:) Base.range Base.OneTo Base.StepRangeLen diff --git a/doc/src/base/punctuation.md b/doc/src/base/punctuation.md index 19f2604df3f61..817aa451d7122 100644 --- a/doc/src/base/punctuation.md +++ b/doc/src/base/punctuation.md @@ -36,9 +36,9 @@ Extended documentation for mathematical symbols & functions is [here](@ref math- | ``` ` ` ``` | delimit external process (command) specifications | | `...` | splice arguments into a function call or declare a varargs function | | `.` | access named fields in objects/modules (calling [`getproperty`](@ref Base.getproperty) or [`setproperty!`](@ref Base.setproperty!)), also prefixes elementwise function calls (calling [`broadcast`](@ref)) | -| `a:b` | range a, a+1, a+2, ..., b (calling [`colon`](@ref)) | -| `a:s:b` | range a, a+s, a+2s, ..., b (also calling [`colon`](@ref)) | -| `:` | index an entire dimension (firstindex:lastindex), see [`Colon`](@ref)) | +| `a:b` | range a, a+1, a+2, ..., b | +| `a:s:b` | range a, a+s, a+2s, ..., b | +| `:` | index an entire dimension (firstindex:lastindex), see [`Colon`](@ref)) | | `::` | type annotation or [`typeassert`](@ref), depending on context | | `:( )` | quoted expression | | `:a` | symbol a | diff --git a/doc/src/manual/functions.md b/doc/src/manual/functions.md index df9696fa4cde0..fc79f56401dac 100644 --- a/doc/src/manual/functions.md +++ b/doc/src/manual/functions.md @@ -164,7 +164,6 @@ A few special expressions correspond to calls to functions with non-obvious name | `[A; B; C; ...]` | [`vcat`](@ref) | | `[A B; C D; ...]` | [`hvcat`](@ref) | | `A'` | [`adjoint`](@ref) | -| `1:n` | [`colon`](@ref) | | `A[i]` | [`getindex`](@ref) | | `A[i] = x` | [`setindex!`](@ref) | | `A.n` | [`getproperty`](@ref Base.getproperty) | diff --git a/src/ast.scm b/src/ast.scm index 4f7024ecee025..d0167ac52f7af 100644 --- a/src/ast.scm +++ b/src/ast.scm @@ -11,7 +11,7 @@ (string.join (map deparse l) sep))) (define (deparse-prefix-call head args opn cls) - (string (if (decl? head) + (string (if (or (decl? head) (eq? head ':)) (string "(" (deparse head) ")") (deparse head)) opn (deparse-arglist args) cls)) @@ -73,9 +73,15 @@ (case (car e) ;; calls and operators ((call) - (if (and (length= e 4) (operator? (cadr e))) - (string #\( (deparse (caddr e)) " " (cadr e) " " (deparse (cadddr e)) #\) ) - (deparse-prefix-call (cadr e) (cddr e) #\( #\)))) + (cond ((and (eq? (cadr e) ':) (or (length= e 4) (length= e 5))) + (string (deparse (caddr e)) ': (deparse (cadddr e)) + (if (length> e 4) + (string ': (deparse (caddddr e))) + ""))) + ((and (length= e 4) (operator? (cadr e))) + (string #\( (deparse (caddr e)) " " (cadr e) " " (deparse (cadddr e)) #\) )) + (else + (deparse-prefix-call (cadr e) (cddr e) #\( #\))))) (($ &) (if (pair? (cadr e)) (string (car e) "(" (deparse (cadr e)) ")") (string (car e) (deparse (cadr e))))) @@ -83,10 +89,6 @@ (string (car e) (deparse (cadr e))) (string (deparse (cadr e)) (car e) (deparse (caddr e))))) ((comparison) (string.join (map deparse (cdr e)) " ")) - ((:) (string (deparse (cadr e)) ': (deparse (caddr e)) - (if (length> e 3) - (string ': (deparse (cadddr e))) - ""))) ((macrocall) (string (cadr e) " " (deparse-arglist (cddr e) " "))) ((kw) (string (deparse (cadr e)) " = " (deparse (caddr e)))) ((where) (string (deparse (cadr e)) " where " diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 90acd72544ef8..340211409dacd 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -819,21 +819,12 @@ (define (parse-pipe< s) (parse-RtoL s parse-pipe> is-prec-pipe s) (parse-LtoR s parse-range is-prec-pipe>?)) -; parse ranges and postfix ... -; colon is strange; 3 arguments with 2 colons yields one call: -; 1:2 => (: 1 2) -; 1:2:3 => (: 1 2 3) -; 1: => (: 1 :) -; 1:2: => (: 1 2 :) -;; not enabled: -;;; :2 => (: 2) -;;; :1:2 => (: (: 1 2)) -;;; :1: => (: (: 1 :)) -; a simple state machine is up to the task. -; we will leave : expressions as a syntax form, not a call to ':', -; so they can be processed by syntax passes. +;; parse ranges and postfix ... +;; colon is strange; 3 arguments with 2 colons yields one call: +;; 1:2 => (call : 1 2) +;; 1:2:3 => (call : 1 2 3) (define (parse-range s) - (let loop ((ex (parse-expr s)) + (let loop ((ex (parse-expr s)) (first? #t)) (let* ((t (peek-token s)) (spc (ts:space? s))) @@ -860,7 +851,7 @@ (error (string "\":" argument "\" found instead of \"" argument ":\""))) (if first? - (loop (list t ex argument) #f) + (loop (list 'call t ex argument) #f) (loop (append ex (list argument)) #t))))) ((eq? t '...) (take-token s) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index a46c6ff628d27..02bae99181038 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1519,11 +1519,7 @@ (let ((a (cadr e)) (idxs (cddr e))) (let* ((reuse (and (pair? a) - (contains (lambda (x) - (or (eq? x 'end) - (eq? x ':) - (and (pair? x) - (eq? (car x) ':)))) + (contains (lambda (x) (eq? x 'end)) idxs))) (arr (if reuse (make-ssavalue) a)) (stmts (if reuse `((= ,arr ,a)) '()))) @@ -2052,10 +2048,7 @@ (idxs (cddr lhs)) (rhs (caddr e))) (let* ((reuse (and (pair? a) - (contains (lambda (x) - (or (eq? x 'end) - (and (pair? x) - (eq? (car x) ':)))) + (contains (lambda (x) (eq? x 'end)) idxs))) (arr (if reuse (make-ssavalue) a)) (stmts (if reuse `((= ,arr ,(expand-forms a))) '())) @@ -2294,16 +2287,6 @@ '>>>= lower-update-op '.>>>= lower-update-op - ': - (lambda (e) - (if (or (length= e 2) - (and (length= e 3) - (eq? (caddr e) ':)) - (and (length= e 4) - (eq? (cadddr e) ':))) - (error "invalid \":\" outside indexing")) - (expand-forms `(call colon ,@(cdr e)))) - '|...| (lambda (e) (error "\"...\" expression outside call")) @@ -2410,7 +2393,9 @@ (if (any (lambda (x) (eq? x ':)) ranges) (error "comprehension syntax with `:` ranges has been removed")) (and (every (lambda (x) (and (pair? x) (eq? (car x) '=) - (pair? (caddr x)) (eq? (car (caddr x)) ':))) + (pair? (caddr x)) + (eq? (car (caddr x)) 'call) + (eq? (cadr (caddr x)) ':))) ranges) ;; TODO: this is a hack to lower simple comprehensions to loops very ;; early, to greatly reduce the # of functions and load on the compiler diff --git a/stdlib/Dates/src/deprecated.jl b/stdlib/Dates/src/deprecated.jl index 8916633ecd26f..6ae9e95d165ed 100644 --- a/stdlib/Dates/src/deprecated.jl +++ b/stdlib/Dates/src/deprecated.jl @@ -1,6 +1,6 @@ # 0.7 deprecations -import Base.colon +import Base.(:) import Base.range # deprecate remaining vectorized methods from Dates @@ -34,9 +34,9 @@ import Base.range # 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 # (in physical units). -@deprecate colon(start::T, stop::T) where {T<:DateTime} start:Day(1):stop false -@deprecate colon(start::T, stop::T) where {T<:Date} start:Day(1):stop false -@deprecate colon(start::T, stop::T) where {T<:Time} start:Second(1):stop false +@deprecate (:)(start::T, stop::T) where {T<:DateTime} start:Day(1):stop false +@deprecate (:)(start::T, stop::T) where {T<:Date} start:Day(1):stop false +@deprecate (:)(start::T, stop::T) where {T<:Time} start:Second(1):stop false @deprecate range(start::DateTime, len::Integer) range(start, Day(1), len) false @deprecate range(start::Date, len::Integer) range(start, Day(1), len) false diff --git a/test/ranges.jl b/test/ranges.jl index 554317142397c..541eb1fc90f85 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -189,12 +189,12 @@ end @testset "ranges" begin @test size(10:1:0) == (0,) @testset "colon" begin - @inferred(colon(10, 1, 0)) - @inferred(colon(1, .2, 2)) - @inferred(colon(1., .2, 2.)) - @inferred(colon(2, -.2, 1)) - @inferred(colon(1, 0)) - @inferred(colon(0.0, -0.5)) + @inferred((:)(10, 1, 0)) + @inferred((:)(1, .2, 2)) + @inferred((:)(1., .2, 2.)) + @inferred((:)(2, -.2, 1)) + @inferred((:)(1, 0)) + @inferred((:)(0.0, -0.5)) end @testset "indexing" begin @@ -1155,7 +1155,7 @@ end end # issue #20382 -let r = @inferred(colon(big(1.0),big(2.0),big(5.0))) +let r = @inferred((:)(big(1.0),big(2.0),big(5.0))) @test eltype(r) == BigFloat end @@ -1185,13 +1185,13 @@ end @test r[4] === 3.0+im end -# ambiguity between colon methods (#20988) +# ambiguity between (:) methods (#20988) struct NotReal; val; end Base.:+(x, y::NotReal) = x + y.val Base.zero(y::NotReal) = zero(y.val) Base.rem(x, y::NotReal) = rem(x, y.val) Base.isless(x, y::NotReal) = isless(x, y.val) -@test colon(1, NotReal(1), 5) isa StepRange{Int,NotReal} +@test (:)(1, NotReal(1), 5) isa StepRange{Int,NotReal} isdefined(Main, :TestHelpers) || @eval Main include("TestHelpers.jl") using .Main.TestHelpers: Furlong diff --git a/test/show.jl b/test/show.jl index 0614388310e2d..15fa2b71b4a66 100644 --- a/test/show.jl +++ b/test/show.jl @@ -142,6 +142,15 @@ end @test_repr "import A.B.C: a, x, y.z" @test_repr "import ..A: a, x, y.z" +# range syntax +@test_repr "1:2" +@test_repr "3:4:5" +let ex4 = Expr(:call, :(:), 1, 2, 3, 4), + ex1 = Expr(:call, :(:), 1) + @test eval(Meta.parse(repr(ex4))) == ex4 + @test eval(Meta.parse(repr(ex1))) == ex1 +end + # Complex # Meta.parse(repr(:(...))) returns a double-quoted block, so we need to eval twice to unquote it diff --git a/test/syntax.jl b/test/syntax.jl index d88701528346b..3dbbba9391f8a 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -1250,7 +1250,7 @@ end # issue #25391 @test Meta.parse("0:-1, \"\"=>\"\"") == Meta.parse("(0:-1, \"\"=>\"\")") == - Expr(:tuple, Expr(:(:), 0, -1), Expr(:call, :(=>), "", "")) + Expr(:tuple, Expr(:call, :(:), 0, -1), Expr(:call, :(=>), "", "")) @test Meta.parse("a => b = c") == Expr(:(=), Expr(:call, :(=>), :a, :b), Expr(:block, LineNumberNode(1, :none), :c)) @test Meta.parse("a = b => c") == Expr(:(=), :a, Expr(:call, :(=>), :b, :c)) From 3afadd46a6316963b34495aec84fab4bb479745f Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 8 Feb 2018 12:09:56 -0500 Subject: [PATCH 3/3] make syntax that expands to calls always call functions in Base fixes #25947 --- src/julia-syntax.scm | 10 +++++----- test/syntax.jl | 12 ++++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 02bae99181038..6b9526f36aa28 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1527,7 +1527,7 @@ (new-idxs stuff) (process-indices arr idxs) `(block ,@(append stmts stuff) - (call getindex ,arr ,@new-idxs)))))) + (call (top getindex) ,arr ,@new-idxs)))))) (define (expand-update-operator op op= lhs rhs . declT) (cond ((and (pair? lhs) (eq? (car lhs) 'ref)) @@ -2062,7 +2062,7 @@ ,.(map expand-forms stuff) ,@rini ,(expand-forms - `(call setindex! ,arr ,r ,@new-idxs)) + `(call (top setindex!) ,arr ,r ,@new-idxs)) (unnecessary ,r)))))) ((|::|) ;; (= (|::| x T) rhs) @@ -2300,7 +2300,7 @@ (expand-forms `(call (top vect) ,@(cdr e)))) 'hcat - (lambda (e) (expand-forms `(call hcat ,@(cdr e)))) + (lambda (e) (expand-forms `(call (top hcat) ,@(cdr e)))) 'vcat (lambda (e) @@ -2317,10 +2317,10 @@ (cdr x) (list x))) a))) - `(call hvcat + `(call (top hvcat) (tuple ,.(map length rows)) ,.(apply append rows))) - `(call vcat ,@a)))))) + `(call (top vcat) ,@a)))))) 'typed_hcat (lambda (e) (expand-forms `(call (top typed_hcat) ,@(cdr e)))) diff --git a/test/syntax.jl b/test/syntax.jl index 3dbbba9391f8a..5405eeb9d5853 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -1271,6 +1271,18 @@ let args = (Int, Any) @test >:(reverse(args)...) end +# issue #25947 +let getindex = 0, setindex! = 1, colon = 2, vcat = 3, hcat = 4, hvcat = 5 + a = [10,9,8] + @test a[2] == 9 + @test 1:2 isa AbstractRange + a[1] = 1 + @test a[1] == 1 + @test length([1; 2]) == 2 + @test size([0 0]) == (1, 2) + @test size([1 2; 3 4]) == (2, 2) +end + # issue #25020 @test_throws ParseError Meta.parse("using Colors()")