diff --git a/base/broadcast.jl b/base/broadcast.jl index 4d5ca6b92fe19..0f00a21af71ba 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -11,7 +11,7 @@ using .Base.Cartesian using .Base: Indices, OneTo, tail, to_shape, isoperator, promote_typejoin, _msk_end, unsafe_bitgetindex, bitcache_chunks, bitcache_size, dumpbitcache, unalias import .Base: copy, copyto!, axes -export broadcast, broadcast!, BroadcastStyle, broadcast_axes, broadcastable, dotview, @__dot__ +export broadcast, broadcast!, BroadcastStyle, broadcast_axes, broadcastable, dotview, @__dot__, @: ## Computing the result's axes: deprecated name const broadcast_axes = axes @@ -1217,4 +1217,29 @@ end end @inline broadcasted(::S, f, args...) where S<:BroadcastStyle = Broadcasted{S}(f, args) +function _lazy end # only used in `@:` macro; does not have to be callable +# wrap the Broadcasted object in a tuple to avoid materializing +@inline broadcasted(::typeof(_lazy), x) = (x,) + +""" + @: broadcasting_expression + +Construct a non-materialized broadcasted object from a `broadcasting_expression` +and [`instantiate`](@ref) it. + +# Examples +```jldoctest +julia> bc = @: (1:3).^2; + +julia> bc isa Broadcast.Broadcasted # it's not an `Array` +true + +julia> sum(bc) # summation without allocating an array +14 +``` +""" +macro (:)(ex) + return esc(:($instantiate(($_lazy.($ex))[1]))) +end + end # module diff --git a/base/exports.jl b/base/exports.jl index 23b4141a06c5e..c924563f92039 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -974,6 +974,7 @@ export @assert, @__dot__, + @:, @enum, @label, @goto, diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 7c8a36d21f141..dcbf926bb0f99 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -2331,9 +2331,10 @@ (disallowed-space '@ nxt))) (with-space-sensitive (let ((startloc (line-number-node s)) - (head (if (eq? (peek-token s) '|.|) - (begin (take-token s) '__dot__) - (parse-atom s #f)))) + (head (case (peek-token s) + ((|.|) (begin (take-token s) '__dot__)) + ((:) (take-token s)) + (else (parse-atom s #f))))) (peek-token s) (if (ts:space? s) (maybe-docstring diff --git a/test/syntax.jl b/test/syntax.jl index 85951185f4a57..6e446bf6b2d14 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -1833,6 +1833,11 @@ end @test allocs == 0 end +@test Meta.parse("@: a b c") == Expr(:macrocall, + Symbol("@:"), + LineNumberNode(1, :none), + :a, :b, :c) + @test_throws UndefVarError eval(Symbol("")) @test_throws UndefVarError eval(:(1+$(Symbol(""))))