From 371bfa89d44657e0a3d475bef78e973833789e41 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 4 Aug 2020 20:49:23 -0400 Subject: [PATCH] normalize parsing of `-->` (#36793) --- NEWS.md | 4 ++++ base/show.jl | 2 +- src/ast.scm | 2 +- src/julia-parser.scm | 19 +++++++++---------- src/julia-syntax.scm | 2 ++ test/syntax.jl | 7 +++++++ 6 files changed, 24 insertions(+), 12 deletions(-) diff --git a/NEWS.md b/NEWS.md index f0e2d072fbd50..33637dcda5c01 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,6 +12,10 @@ New language features Language changes ---------------- +* The `-->` operator now lowers to a `:call` expression, so it can be defined as + a function like other operators. The dotted version `.-->` is now parsed as well. + For backwards compatibility, `-->` still parses using its own expression head + instead of `:call`. Compiler/Runtime improvements ----------------------------- diff --git a/base/show.jl b/base/show.jl index 03392d56653a0..a9abdd5dfb89d 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1077,7 +1077,7 @@ const uni_ops = Set{Symbol}([:(+), :(-), :(!), :(¬), :(~), :(<:), :(>:), :(√) const expr_infix_wide = Set{Symbol}([ :(=), :(+=), :(-=), :(*=), :(/=), :(\=), :(^=), :(&=), :(|=), :(÷=), :(%=), :(>>>=), :(>>=), :(<<=), :(.=), :(.+=), :(.-=), :(.*=), :(./=), :(.\=), :(.^=), :(.&=), :(.|=), :(.÷=), :(.%=), :(.>>>=), :(.>>=), :(.<<=), - :(&&), :(||), :(<:), :($=), :(⊻=), :(>:)]) + :(&&), :(||), :(<:), :($=), :(⊻=), :(>:), :(-->)]) const expr_infix = Set{Symbol}([:(:), :(->), Symbol("::")]) const expr_infix_any = union(expr_infix, expr_infix_wide) const expr_calls = Dict(:call => ('(',')'), :calldecl => ('(',')'), diff --git a/src/ast.scm b/src/ast.scm index 7af2aab32024a..b505e0685e409 100644 --- a/src/ast.scm +++ b/src/ast.scm @@ -67,7 +67,7 @@ (string #\( (deparse (caddr e)) #\)))))) ((memq (car e) '(... |'|)) (string (deparse (cadr e)) (car e))) - ((or (syntactic-op? (car e)) (eq? (car e) '|<:|) (eq? (car e) '|>:|)) + ((or (syntactic-op? (car e)) (eq? (car e) '|<:|) (eq? (car e) '|>:|) (eq? (car e) '-->)) (if (length= e 2) (string (car e) (deparse (cadr e))) (string (deparse (cadr e)) " " (car e) " " (deparse (caddr e))))) diff --git a/src/julia-parser.scm b/src/julia-parser.scm index d10158db0158d..d4f83a3bfdbbc 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -3,9 +3,6 @@ ; for most operators X there is a .X "elementwise" equivalent (define (add-dots ops) (append! ops (map (lambda (op) (symbol (string "." op))) ops))) -;; note: there are some strange-looking things in here because -;; the way the lexer works, every prefix of an operator must also -;; be an operator. (define prec-assignment (append! (add-dots '(= += -= *= /= //= |\\=| ^= ÷= %= <<= >>= >>>= |\|=| &= ⊻= ≔ ⩴ ≕)) (add-dots '(~)) @@ -13,9 +10,7 @@ ;; comma - higher than assignment outside parentheses, lower when inside (define prec-pair (add-dots '(=>))) (define prec-conditional '(?)) -(define prec-arrow (append! - '(-- -->) - (add-dots '(← → ↔ ↚ ↛ ↞ ↠ ↢ ↣ ↦ ↤ ↮ ⇎ ⇍ ⇏ ⇐ ⇒ ⇔ ⇴ ⇶ ⇷ ⇸ ⇹ ⇺ ⇻ ⇼ ⇽ ⇾ ⇿ ⟵ ⟶ ⟷ ⟹ ⟺ ⟻ ⟼ ⟽ ⟾ ⟿ ⤀ ⤁ ⤂ ⤃ ⤄ ⤅ ⤆ ⤇ ⤌ ⤍ ⤎ ⤏ ⤐ ⤑ ⤔ ⤕ ⤖ ⤗ ⤘ ⤝ ⤞ ⤟ ⤠ ⥄ ⥅ ⥆ ⥇ ⥈ ⥊ ⥋ ⥎ ⥐ ⥒ ⥓ ⥖ ⥗ ⥚ ⥛ ⥞ ⥟ ⥢ ⥤ ⥦ ⥧ ⥨ ⥩ ⥪ ⥫ ⥬ ⥭ ⥰ ⧴ ⬱ ⬰ ⬲ ⬳ ⬴ ⬵ ⬶ ⬷ ⬸ ⬹ ⬺ ⬻ ⬼ ⬽ ⬾ ⬿ ⭀ ⭁ ⭂ ⭃ ⭄ ⭇ ⭈ ⭉ ⭊ ⭋ ⭌ ← → ⇜ ⇝ ↜ ↝ ↩ ↪ ↫ ↬ ↼ ↽ ⇀ ⇁ ⇄ ⇆ ⇇ ⇉ ⇋ ⇌ ⇚ ⇛ ⇠ ⇢ ↷ ↶ ↺ ↻ <-- <-->)))) +(define prec-arrow (add-dots '(← → ↔ ↚ ↛ ↞ ↠ ↢ ↣ ↦ ↤ ↮ ⇎ ⇍ ⇏ ⇐ ⇒ ⇔ ⇴ ⇶ ⇷ ⇸ ⇹ ⇺ ⇻ ⇼ ⇽ ⇾ ⇿ ⟵ ⟶ ⟷ ⟹ ⟺ ⟻ ⟼ ⟽ ⟾ ⟿ ⤀ ⤁ ⤂ ⤃ ⤄ ⤅ ⤆ ⤇ ⤌ ⤍ ⤎ ⤏ ⤐ ⤑ ⤔ ⤕ ⤖ ⤗ ⤘ ⤝ ⤞ ⤟ ⤠ ⥄ ⥅ ⥆ ⥇ ⥈ ⥊ ⥋ ⥎ ⥐ ⥒ ⥓ ⥖ ⥗ ⥚ ⥛ ⥞ ⥟ ⥢ ⥤ ⥦ ⥧ ⥨ ⥩ ⥪ ⥫ ⥬ ⥭ ⥰ ⧴ ⬱ ⬰ ⬲ ⬳ ⬴ ⬵ ⬶ ⬷ ⬸ ⬹ ⬺ ⬻ ⬼ ⬽ ⬾ ⬿ ⭀ ⭁ ⭂ ⭃ ⭄ ⭇ ⭈ ⭉ ⭊ ⭋ ⭌ ← → ⇜ ⇝ ↜ ↝ ↩ ↪ ↫ ↬ ↼ ↽ ⇀ ⇁ ⇄ ⇆ ⇇ ⇉ ⇋ ⇌ ⇚ ⇛ ⇠ ⇢ ↷ ↶ ↺ ↻ --> <-- <-->))) (define prec-lazy-or '(|\|\||)) (define prec-lazy-and '(&&)) (define prec-comparison @@ -66,7 +61,7 @@ ; only allow/strip suffixes for some operators (define no-suffix? (Set (append prec-assignment prec-conditional prec-lazy-or prec-lazy-and prec-colon prec-decl prec-dot - '(-- --> -> |<:| |>:| in isa $) + '(-> |<:| |>:| in isa $) (list ctrans-op trans-op vararg-op)))) (define (maybe-strip-op-suffix op) (if (symbol? op) @@ -115,7 +110,7 @@ ; operators that are special forms, not function names (define syntactic-operators (append! (add-dots '(= += -= *= /= //= |\\=| ^= ÷= %= <<= >>= >>>= |\|=| &= ⊻=)) - '(:= --> $= && |\|\|| |.| ... ->))) + '(:= $= && |\|\|| |.| ... ->))) (define syntactic-unary-operators '($ & |::|)) (define syntactic-op? (Set syntactic-operators)) @@ -252,6 +247,12 @@ (if (or (operator? opsym) (and (or (eq? opsym '<---) (eq? opsym '.<---)) (error (string "invalid operator \"" newop "\""))) + ;; -- is not an operator but --> is + (and (or (eq? opsym '--) (eq? opsym '.--)) + (read-char port) + (or (begin0 (eqv? (peek-char port) #\>) + (io.ungetc port #\-)) + (error (string "invalid operator \"" newop "\"")))) ;; <- is not an operator but <-- and <--> are (and (or (eq? opsym '<-) (eq? opsym '.<-)) (read-char port) @@ -261,8 +262,6 @@ (loop newop (peek-char port) sufchar?)) str)) str)))))) - (if (equal? str "--") - (error (string "invalid operator \"" str "\""))) (string->symbol str)))) (define (accum-digits c pred port _-digit-sep) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 2f02c09acedac..0d73ef4665a38 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1960,6 +1960,8 @@ (lambda (e) (expand-forms `(call |<:| ,@(cdr e)))) '|>:| (lambda (e) (expand-forms `(call |>:| ,@(cdr e)))) + '--> + (lambda (e) (expand-forms `(call --> ,@(cdr e)))) 'where (lambda (e) (expand-forms (expand-wheres (cadr e) (cddr e)))) diff --git a/test/syntax.jl b/test/syntax.jl index 68d2d090ad481..cf8ba1aa75a8e 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -2297,5 +2297,12 @@ end @test :(a .<-- b.<--c) == Expr(:call, :.<--, :a, Expr(:call, :.<--, :b, :c)) @test :(a<-->b<-->c) == Expr(:call, :<-->, :a, Expr(:call, :<-->, :b, :c)) @test :(a.<-->b .<--> c) == Expr(:call, :.<-->, :a, Expr(:call, :.<-->, :b, :c)) +@test :(a --> b --> c) == Expr(:-->, :a, Expr(:-->, :b, :c)) +@test :(a --> b.-->c) == Expr(:-->, :a, Expr(:call, :.-->, :b, :c)) +let (-->) = (+) + @test (40 --> 2) == 42 +end @test_throws ParseError("invalid operator \"<---\"") Meta.parse("1<---2") @test_throws ParseError("invalid operator \".<---\"") Meta.parse("1 .<--- 2") +@test_throws ParseError("invalid operator \"--\"") Meta.parse("a---b") +@test_throws ParseError("invalid operator \".--\"") Meta.parse("a.---b")