From b6c1fcf508a30ceeb3633fc352e35a6477867e46 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 20 Oct 2017 16:06:56 -0400 Subject: [PATCH] fix #24153, make `<|` right associative --- NEWS.md | 2 ++ base/show.jl | 3 ++- doc/src/manual/mathematical-operations.md | 4 +++- src/julia-parser.scm | 18 ++++++++++-------- test/parse.jl | 4 ++++ 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/NEWS.md b/NEWS.md index c374310c8d3b0..f19be669efa98 100644 --- a/NEWS.md +++ b/NEWS.md @@ -44,6 +44,8 @@ Language changes * The parsing of `1<<2*3` as `1<<(2*3)` is deprecated, and will change to `(1<<2)*3` in a future version ([#13079]). + * The parsing of `<|` is now right associative. `|>` remains left associative ([#24153]). + * `{ }` 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/show.jl b/base/show.jl index 130b5f992f8cc..da6c84e11fa4f 100644 --- a/base/show.jl +++ b/base/show.jl @@ -654,7 +654,8 @@ julia> Base.operator_associativity(:⊗), Base.operator_associativity(:sin), Bas ``` """ function operator_associativity(s::Symbol) - if operator_precedence(s) in (prec_arrow, prec_assignment, prec_control_flow, prec_power) || isunaryoperator(s) && !is_unary_and_binary_operator(s) + if operator_precedence(s) in (prec_arrow, prec_assignment, prec_control_flow, prec_power) || + (isunaryoperator(s) && !is_unary_and_binary_operator(s)) || s === :<| return :right elseif operator_precedence(s) in (0, prec_comparison) || s in (:+, :++, :*) return :none diff --git a/doc/src/manual/mathematical-operations.md b/doc/src/manual/mathematical-operations.md index 91a429338182d..559cc6108d8a7 100644 --- a/doc/src/manual/mathematical-operations.md +++ b/doc/src/manual/mathematical-operations.md @@ -360,7 +360,9 @@ Julia applies the following order and associativity of operations, from highest | Multiplication | `* / % & \` | Left[^2] | | Bitshifts | `<< >> >>>` | Left | | Addition | `+ - \| ⊻` | Left[^2] | -| Syntax | `: ..` followed by `\|>` | Left | +| Syntax | `: ..` | Left | +| Syntax | `\|>` | Left | +| Syntax | `<\|` | Right | | Comparisons | `> < >= <= == === != !== <:` | Non-associative | | Control flow | `&&` followed by `\|\|` followed by `?` | Right | | Assignments | `= += -= *= /= //= \= ^= ÷= %= \|= &= ⊻= <<= >>= >>>=` | Right | diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 742b2387c9ded..02474c88f9d39 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -18,7 +18,8 @@ (define prec-comparison (append! '(|<:| |>:| in isa) (add-dots '(> < >= ≥ <= ≤ == === ≡ != ≠ !== ≢ ∈ ∉ ∋ ∌ ⊆ ⊈ ⊂ ⊄ ⊊ ∝ ∊ ∍ ∥ ∦ ∷ ∺ ∻ ∽ ∾ ≁ ≃ ≄ ≅ ≆ ≇ ≈ ≉ ≊ ≋ ≌ ≍ ≎ ≐ ≑ ≒ ≓ ≔ ≕ ≖ ≗ ≘ ≙ ≚ ≛ ≜ ≝ ≞ ≟ ≣ ≦ ≧ ≨ ≩ ≪ ≫ ≬ ≭ ≮ ≯ ≰ ≱ ≲ ≳ ≴ ≵ ≶ ≷ ≸ ≹ ≺ ≻ ≼ ≽ ≾ ≿ ⊀ ⊁ ⊃ ⊅ ⊇ ⊉ ⊋ ⊏ ⊐ ⊑ ⊒ ⊜ ⊩ ⊬ ⊮ ⊰ ⊱ ⊲ ⊳ ⊴ ⊵ ⊶ ⊷ ⋍ ⋐ ⋑ ⋕ ⋖ ⋗ ⋘ ⋙ ⋚ ⋛ ⋜ ⋝ ⋞ ⋟ ⋠ ⋡ ⋢ ⋣ ⋤ ⋥ ⋦ ⋧ ⋨ ⋩ ⋪ ⋫ ⋬ ⋭ ⋲ ⋳ ⋴ ⋵ ⋶ ⋷ ⋸ ⋹ ⋺ ⋻ ⋼ ⋽ ⋾ ⋿ ⟈ ⟉ ⟒ ⦷ ⧀ ⧁ ⧡ ⧣ ⧤ ⧥ ⩦ ⩧ ⩪ ⩫ ⩬ ⩭ ⩮ ⩯ ⩰ ⩱ ⩲ ⩳ ⩴ ⩵ ⩶ ⩷ ⩸ ⩹ ⩺ ⩻ ⩼ ⩽ ⩾ ⩿ ⪀ ⪁ ⪂ ⪃ ⪄ ⪅ ⪆ ⪇ ⪈ ⪉ ⪊ ⪋ ⪌ ⪍ ⪎ ⪏ ⪐ ⪑ ⪒ ⪓ ⪔ ⪕ ⪖ ⪗ ⪘ ⪙ ⪚ ⪛ ⪜ ⪝ ⪞ ⪟ ⪠ ⪡ ⪢ ⪣ ⪤ ⪥ ⪦ ⪧ ⪨ ⪩ ⪪ ⪫ ⪬ ⪭ ⪮ ⪯ ⪰ ⪱ ⪲ ⪳ ⪴ ⪵ ⪶ ⪷ ⪸ ⪹ ⪺ ⪻ ⪼ ⪽ ⪾ ⪿ ⫀ ⫁ ⫂ ⫃ ⫄ ⫅ ⫆ ⫇ ⫈ ⫉ ⫊ ⫋ ⫌ ⫍ ⫎ ⫏ ⫐ ⫑ ⫒ ⫓ ⫔ ⫕ ⫖ ⫗ ⫘ ⫙ ⫷ ⫸ ⫹ ⫺ ⊢ ⊣)))) -(define prec-pipe (add-dots '(|\|>| |<\||))) +(define prec-pipe< '(|.<\|| |<\||)) +(define prec-pipe> '(|.\|>| |\|>|)) (define prec-colon '(: |..|)) (define prec-plus (append! '($) (add-dots '(+ - |\|| ⊕ ⊖ ⊞ ⊟ |++| ∪ ∨ ⊔ ± ∓ ∔ ∸ ≂ ≏ ⊎ ⊻ ⊽ ⋎ ⋓ ⧺ ⧻ ⨈ ⨢ ⨣ ⨤ ⨥ ⨦ ⨧ ⨨ ⨩ ⨪ ⨫ ⨬ ⨭ ⨮ ⨹ ⨺ ⩁ ⩂ ⩅ ⩊ ⩌ ⩏ ⩐ ⩒ ⩔ ⩖ ⩗ ⩛ ⩝ ⩡ ⩢ ⩣)))) @@ -34,7 +35,7 @@ (define prec-names '(prec-assignment prec-conditional prec-lazy-or prec-lazy-and prec-arrow prec-comparison - prec-pipe prec-colon prec-plus prec-bitshift prec-times prec-rational + prec-pipe< prec-pipe> prec-colon prec-plus prec-bitshift prec-times prec-rational prec-power prec-decl prec-dot)) (define trans-op (string->symbol ".'")) @@ -802,14 +803,14 @@ (define (parse-and s) (parse-RtoL s parse-comparison is-prec-lazy-and? #t parse-and)) (define (parse-comparison s) - (let loop ((ex (parse-pipes s)) + (let loop ((ex (parse-pipe< s)) (first #t)) (let ((t (peek-token s))) (cond ((is-prec-comparison? t) (begin (take-token s) (if first - (loop (list 'comparison ex t (parse-pipes s)) #f) - (loop (append ex (list t (parse-pipes s))) #f)))) + (loop (list 'comparison ex t (parse-pipe< s)) #f) + (loop (append ex (list t (parse-pipe< s))) #f)))) (first ex) ((length= ex 4) ;; only a single comparison; special chained syntax not required @@ -821,7 +822,8 @@ `(call ,op ,arg1 ,arg2)))) (else ex))))) -(define (parse-pipes s) (parse-LtoR s parse-range is-prec-pipe?)) +(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: @@ -1664,11 +1666,11 @@ #f) #t))) #f)) - (lhs (parse-pipes s)) + (lhs (parse-pipe< s)) (t (peek-token s))) (cond ((memq t '(= in ∈)) (take-token s) - (let* ((rhs (parse-pipes s)) + (let* ((rhs (parse-pipe< s)) (t (peek-token s))) #;(if (not (or (closing-token? t) (newline? t))) ;; should be: (error "invalid iteration specification") diff --git a/test/parse.jl b/test/parse.jl index 997c0343a0c8f..91cb09af425b7 100644 --- a/test/parse.jl +++ b/test/parse.jl @@ -384,6 +384,10 @@ end @test parse("1 == 2|>3") == Expr(:call, :(==), 1, Expr(:call, :(|>), 2, 3)) +# issue #24153 +@test parse("a|>b|>c|>d") == parse("((a|>b)|>c)|>d") +@test parse("a<|b<|c<|d") == parse("a<|(b<|(c<|d))") + # issue #12501 and pr #12502 parse(""" baremodule A