Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ New language features
* Mutable struct fields may now be annotated as `const` to prevent changing
them after construction, providing for greater clarity and optimization
ability of these objects ([#43305]).
* Empty n-dimensional arrays can now be created using multiple semicolons inside square brackets, i.e. `[;;;]` creates a 0×0×0 `Array`. ([#41618])

Language changes
----------------
Expand Down
2 changes: 1 addition & 1 deletion src/ast.scm
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@
((typed_hcat) (string (deparse (cadr e))
(deparse (cons 'hcat (cddr e)))))
((ncat) (string #\[ (deparse-arglist (cddr e) (string (deparse-semicolons (cadr e)) " "))
(if (= (length (cddr e)) 1)
(if (<= (length (cddr e)) 1)
(deparse-semicolons (cadr e))
"") #\]))
((typed_ncat) (string (deparse (cadr e))
Expand Down
50 changes: 33 additions & 17 deletions src/julia-parser.scm
Original file line number Diff line number Diff line change
Expand Up @@ -2016,24 +2016,40 @@
(where-enabled #t)
(whitespace-newline #f)
(for-generator #t))
(if (eqv? (require-token s) closer)
(begin (take-token s)
'())
(let* ((first (parse-eq* s))
(t (peek-token s)))
(cond ((or (eqv? t #\,) (eqv? t closer))
(parse-vect s first closer))
((eq? t 'for)
(expect-space-before s 'for)
(take-token s)
(parse-comprehension s first closer))
((eqv? t #\newline)
(let ((t (require-token s)))
(cond ((eqv? t closer)
(take-token s)
'())
((eqv? t #\;)
(take-token s)
(define (loop (n 1))
(let ((t (with-whitespace-newline (require-token s))))
(take-token s)
(if (memv (peek-token s) (list #\, closer))
(parse-vect s first closer)
(parse-array s first closer #t last-end-symbol)))
(else
(parse-array s first closer #f last-end-symbol)))))))
(cond ((eqv? t #\;)
(if (ts:space? s)
(error (string "unexpected space inside "
(deparse `(ncat ,n)) " expression")))
(loop (+ n 1)))
((eqv? t closer) `(ncat ,n))
(else (error (string "unexpected \"" t "\" inside "
(deparse `(ncat ,n)) " expression"))))))
(loop))
(else
(let* ((first (parse-eq* s))
(t (peek-token s)))
(cond ((or (eqv? t #\,) (eqv? t closer))
(parse-vect s first closer))
((eq? t 'for)
(expect-space-before s 'for)
(take-token s)
(parse-comprehension s first closer))
((eqv? t #\newline)
(take-token s)
(if (memv (peek-token s) (list #\, closer))
(parse-vect s first closer)
(parse-array s first closer #t last-end-symbol)))
(else
(parse-array s first closer #f last-end-symbol)))))))))

(define (kw-to-= e) (if (kwarg? e) (cons '= (cdr e)) e))
(define (=-to-kw e) (if (assignment? e) (cons 'kw (cdr e)) e))
Expand Down
34 changes: 34 additions & 0 deletions test/syntax.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3088,3 +3088,37 @@ function checkUserAccess(u::User)
return false
end
""")

@testset "empty nd arrays" begin
@test :([]) == Expr(:vect)
@test :([;]) == Expr(:ncat, 1)
@test :([;;]) == Expr(:ncat, 2)
@test :([;;;]) == Expr(:ncat, 3)

@test [] == Array{Any}(undef, 0)
@test [;] == Array{Any}(undef, 0)
@test [;;] == Array{Any}(undef, 0, 0)
@test [;;;] == Array{Any}(undef, 0, 0, 0)

@test :(T[]) == Expr(:ref, :T)
@test :(T[;]) == Expr(:typed_ncat, :T, 1)
@test :(T[;;]) == Expr(:typed_ncat, :T, 2)
@test :(T[;;;]) == Expr(:typed_ncat, :T, 3)

@test Int[] == Array{Int}(undef, 0)
@test Int[;] == Array{Int}(undef, 0)
@test Int[;;] == Array{Int}(undef, 0, 0)
@test Int[;;;] == Array{Int}(undef, 0, 0, 0)

@test :([ ]) == Expr(:vect)
@test :([
]) == Expr(:vect)
@test :([ ;; ]) == Expr(:ncat, 2)
@test :([
;;
]) == Expr(:ncat, 2)

@test_throws ParseError Meta.parse("[; ;]")
@test_throws ParseError Meta.parse("[;; ;]")
@test_throws ParseError Meta.parse("[;\n;]")
end