From e13ac1f9aa42e13614d4f302bab1c0b9d2914f17 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 31 Jul 2017 10:53:02 -0400 Subject: [PATCH] preserve `elseif` syntax in parser part of #21774 --- NEWS.md | 3 +++ base/show.jl | 22 +++++++++++++++------- doc/src/devdocs/ast.md | 9 ++++----- src/julia-parser.scm | 20 +++++++++++--------- src/julia-syntax.scm | 20 ++++++++++---------- test/show.jl | 39 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 82 insertions(+), 31 deletions(-) diff --git a/NEWS.md b/NEWS.md index 1c15124b166a1..2382ea9d9ec8d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -32,6 +32,9 @@ Language changes * `{ }` expressions now use `braces` and `bracescat` as expression heads instead of `cell1d` and `cell2d`, and parse similarly to `vect` and `vcat` ([#8470]). + * Nested `if` expressions that arise from the keyword `elseif` now use `elseif` + as their expression head instead of `if` ([#21774]). + Breaking changes ---------------- diff --git a/base/show.jl b/base/show.jl index 38d624d957e34..b8d05c131a5ed 100644 --- a/base/show.jl +++ b/base/show.jl @@ -557,7 +557,11 @@ function show_block(io::IO, head, args::Vector, body, indent::Int) print(io, head) if !isempty(args) print(io, ' ') - show_list(io, args, ", ", indent) + if head === :elseif + show_list(io, args, " ", indent) + else + show_list(io, args, ", ", indent) + end end ind = head === :module || head === :baremodule ? indent : indent + indent_width @@ -880,10 +884,19 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) print(io, "function ", args[1], " end") # block with argument - elseif head in (:for,:while,:function,:if) && nargs==2 + elseif head in (:for,:while,:function,:if,:elseif) && nargs==2 show_block(io, head, args[1], args[2], indent) print(io, "end") + elseif (head === :if || head === :elseif) && nargs == 3 + show_block(io, head, args[1], args[2], indent) + if isa(args[3],Expr) && args[3].head == :elseif + show_unquoted(io, args[3], indent, prec) + else + show_block(io, "else", args[3], indent) + print(io, "end") + end + elseif head === :module && nargs==3 && isa(args[1],Bool) show_block(io, args[1] ? :module : :baremodule, args[2], args[3], indent) print(io, "end") @@ -945,11 +958,6 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) elseif head === :line && 1 <= nargs <= 2 show_linenumber(io, args...) - elseif head === :if && nargs == 3 # if/else - show_block(io, "if", args[1], args[2], indent) - show_block(io, "else", args[3], indent) - print(io, "end") - elseif head === :try && 3 <= nargs <= 4 show_block(io, "try", args[1], indent) if is_expr(args[3], :block) diff --git a/doc/src/devdocs/ast.md b/doc/src/devdocs/ast.md index 16724c3154954..f2968fe91088d 100644 --- a/doc/src/devdocs/ast.md +++ b/doc/src/devdocs/ast.md @@ -466,8 +466,8 @@ if a b elseif c d -else e - f +else + e end ``` @@ -475,9 +475,8 @@ parses as: ``` (if a (block (line 2) b) - (block (line 3) (if c (block (line 4) d) - (block (line 5) e - (line 6) f)))) + (elseif (block (line 3) c) (block (line 4) d) + (block (line 5 e)))) ``` A `while` loop parses as `(while condition body)`. diff --git a/src/julia-parser.scm b/src/julia-parser.scm index b192147daeaa2..53d5e5c366e4e 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -1296,31 +1296,33 @@ `(for ,(if (length= ranges 1) (car ranges) (cons 'block ranges)) ,body))) - ((if) + ((if elseif) (if (newline? (peek-token s)) (error (string "missing condition in \"if\" at " current-filename ":" (- (input-port-line (ts:port s)) 1)))) - (let* ((test (parse-cond s)) + (let* ((lno (line-number-node s)) ;; line number for elseif condition + (test (parse-cond s)) + (test (if (eq? word 'elseif) + `(block ,lno ,test) + test)) (then (if (memq (require-token s) '(else elseif)) '(block) (parse-block s))) (nxt (require-token s))) (take-token s) (case nxt - ((end) (list 'if test then)) + ((end) (list word test then)) ((elseif) (if (newline? (peek-token s)) (error (string "missing condition in \"elseif\" at " current-filename ":" (- (input-port-line (ts:port s)) 1)))) - `(if ,test ,then - ;; line number for elseif condition - (block ,(line-number-node s) - ,(parse-resword s 'if)))) + `(,word ,test ,then + ,(parse-resword s 'elseif))) ((else) (if (eq? (peek-token s) 'if) (error "use \"elseif\" instead of \"else if\"")) - (begin0 (list 'if test then (parse-block s)) - (expect-end s word))) + (begin0 (list word test then (parse-block s)) + (expect-end s 'if))) (else (error (string "unexpected \"" nxt "\"")))))) ((let) (let ((binds (if (memv (peek-token s) '(#\newline #\;)) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 0e02d9e4eedfb..f5760776f2fb8 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1656,15 +1656,6 @@ (if ,g ,g ,(loop (cdr tail))))))))))) -(define (expand-forms e) - (if (or (atom? e) (memq (car e) '(quote inert top core globalref outerref line module toplevel ssavalue null meta))) - e - (let ((ex (get expand-table (car e) #f))) - (if ex - (ex e) - (cons (car e) - (map expand-forms (cdr e))))))) - (define (expand-for while lhs X body) ;; (for (= lhs X) body) (let ((coll (make-ssavalue)) @@ -1871,6 +1862,15 @@ (extract (cdr params) (cons p newparams) whereparams))))) (extract (cddr e) '() '())) +(define (expand-forms e) + (if (or (atom? e) (memq (car e) '(quote inert top core globalref outerref line module toplevel ssavalue null meta))) + e + (let ((ex (get expand-table (car e) #f))) + (if ex + (ex e) + (cons (car e) + (map expand-forms (cdr e))))))) + ;; table mapping expression head to a function expanding that form (define expand-table (table @@ -3493,7 +3493,7 @@ f(x) = yt(x) (if value (compile (cadr e) break-labels value tail) #f)) - ((if) + ((if elseif) (let ((test `(gotoifnot ,(compile-cond (cadr e) break-labels) _)) (end-jump `(goto _)) (val (if (and value (not tail)) (new-mutable-var) #f))) diff --git a/test/show.jl b/test/show.jl index db6f39b4849a1..6fcaba1c32ae5 100644 --- a/test/show.jl +++ b/test/show.jl @@ -236,6 +236,45 @@ end""" return end""" +@test_repr """if a +# line meta +b +end +""" + +@test_repr """if a +# line meta +b +elseif c +# line meta +d +end +""" + +@test_repr """if a +# line meta +b +elseif c +# line meta +d +else +# line meta +e +end +""" + +@test_repr """if a +# line meta +b +elseif c +# line meta +d +elseif e +# line meta +f +end +""" + # issue #7188 @test sprint(show, :foo) == ":foo" @test sprint(show, Symbol("foo bar")) == "Symbol(\"foo bar\")"