diff --git a/NEWS.md b/NEWS.md index 155e4e384f804..565ed28438282 100644 --- a/NEWS.md +++ b/NEWS.md @@ -114,6 +114,11 @@ Language changes macro. Instead, the string is first unindented and then `x_str` is invoked, as if the string had been single-quoted ([#10228]). + * Colons (`:`) within indexing expressions are no longer lowered to the range + `1:end`. Instead, the `:` identifier is passed directly. Custom array types + that implement `getindex` or `setindex!` methods must also extend those + methods to support arguments of type `Colon` ([#10331]). + Command line option changes --------------------------- @@ -1422,6 +1427,7 @@ Too numerous to mention. [#10180]: https://github.com/JuliaLang/julia/issues/10180 [#10228]: https://github.com/JuliaLang/julia/issues/10228 [#10328]: https://github.com/JuliaLang/julia/issues/10328 +[#10331]: https://github.com/JuliaLang/julia/issues/10331 [#10332]: https://github.com/JuliaLang/julia/issues/10332 [#10333]: https://github.com/JuliaLang/julia/issues/10333 [#10380]: https://github.com/JuliaLang/julia/issues/10380 diff --git a/base/array.jl b/base/array.jl index c7fbb35f46150..ea1770ea82235 100644 --- a/base/array.jl +++ b/base/array.jl @@ -347,6 +347,20 @@ function setindex!(A::Array, X::AbstractArray, I::AbstractVector{Int}) end return A end +function setindex!(A::Array, x, ::Colon) + for i in 1:length(A) + @inbounds A[i] = x + end + return A +end +function setindex!(A::Array, X::AbstractArray, ::Colon) + setindex_shape_check(X, length(A)) + i = 0 + for x in X + @inbounds A[i+=1] = x + end + return A +end # Faster contiguous setindex! with copy! setindex!{T}(A::Array{T}, X::Array{T}, I::UnitRange{Int}) = (checkbounds(A, I); unsafe_setindex!(A, X, I)) @@ -368,7 +382,6 @@ function unsafe_setindex!{T}(A::Array{T}, X::Array{T}, ::Colon) return A end - # efficiently grow an array function _growat!(a::Vector, i::Integer, delta::Integer) diff --git a/doc/manual/arrays.rst b/doc/manual/arrays.rst index 5a0c79d1a1487..2c571e7df46ee 100644 --- a/doc/manual/arrays.rst +++ b/doc/manual/arrays.rst @@ -222,9 +222,10 @@ The general syntax for indexing into an n-dimensional array A is:: where each ``I_k`` may be: 1. A scalar integer -2. A ``Range`` of the form ``:``, ``a:b``, or ``a:b:c`` -3. An arbitrary integer vector, including the empty vector ``[]`` -4. A boolean vector +2. A ``Range`` of the form ``a:b``, or ``a:b:c`` +3. A ``:`` or ``Colon()`` to select entire dimensions +4. An arbitrary integer vector, including the empty vector ``[]`` +5. A boolean vector The result ``X`` generally has dimensions ``(length(I_1), length(I_2), ..., length(I_n))``, with location @@ -286,10 +287,11 @@ The general syntax for assigning values in an n-dimensional array A is:: where each ``I_k`` may be: -1. A scalar value -2. A ``Range`` of the form ``:``, ``a:b``, or ``a:b:c`` -3. An arbitrary integer vector, including the empty vector ``[]`` -4. A boolean vector +1. A scalar integer +2. A ``Range`` of the form ``a:b``, or ``a:b:c`` +3. A ``:`` or ``Colon()`` to select entire dimensions +4. An arbitrary integer vector, including the empty vector ``[]`` +5. A boolean vector If ``X`` is an array, its size must be ``(length(I_1), length(I_2), ..., length(I_n))``, and the value in location ``i_1, i_2, ..., i_n`` of ``A`` is overwritten with diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 87536bf7f69f9..5d72708c3af0f 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -301,18 +301,17 @@ (define (expand-compare-chain e) (car (expand-vector-compare e))) -;; last = is this last index? +;; return the appropriate computation for an `end` symbol for indexing +;; the array `a` in the `n`th index. +;; `tuples` are a list of the splatted arguments that precede index `n` +;; `last` = is this last index? +;; returns a call to endof(a), trailingsize(a,n), or size(a,n) (define (end-val a n tuples last) (if (null? tuples) (if last (if (= n 1) `(call (top endof) ,a) `(call (top trailingsize) ,a ,n)) - #;`(call (top div) - (call (top length) ,a) - (call (top *) - ,@(map (lambda (d) `(call (top size) ,a ,(1+ d))) - (iota (- n 1))))) `(call (top size) ,a ,n)) (let ((dimno `(call (top +) ,(- n (length tuples)) ,.(map (lambda (t) `(call (top length) ,t)) @@ -321,8 +320,7 @@ `(call (top trailingsize) ,a ,dimno) `(call (top size) ,a ,dimno))))) -; replace end inside ex with (call (top size) a n) -; affects only the closest ref expression, so doesn't go inside nested refs +; replace `end` for the closest ref expression, so doesn't go inside nested refs (define (replace-end ex a n tuples last) (cond ((eq? ex 'end) (end-val a n tuples last)) ((or (atom? ex) (quoted? ex)) ex) @@ -335,29 +333,7 @@ (map (lambda (x) (replace-end x a n tuples last)) (cdr ex)))))) -; translate index x from colons to ranges -(define (expand-index-colon x) - (cond ((eq? x ':) `(call colon 1 end)) - ((and (pair? x) - (eq? (car x) ':)) - (cond ((length= x 3) - (if (eq? (caddr x) ':) - ;; (: a :) a: - `(call colon ,(cadr x) end) - ;; (: a b) - `(call colon ,(cadr x) ,(caddr x)))) - ((length= x 4) - (if (eq? (cadddr x) ':) - ;; (: a b :) a:b: - `(call colon ,(cadr x) ,(caddr x) end) - ;; (: a b c) - `(call colon ,@(cdr x)))) - (else x))) - (else x))) - -;; : inside indexing means 1:end -;; expand end to size(a,n), -;; or div(length(a), prod(size(a)[1:(n-1)])) for the last index +;; go through indices and replace the `end` symbol ;; a = array being indexed, i = list of indexes ;; returns (values index-list stmts) where stmts are statements that need ;; to execute first. @@ -386,8 +362,7 @@ (cons `(... ,g) ret)))) (loop (cdr lst) (+ n 1) stmts tuples - (cons (replace-end (expand-index-colon idx) a n tuples last) - ret))))))) + (cons (replace-end idx a n tuples last) ret))))))) (define (make-decl n t) `(|::| ,n ,t))