Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] new brackets: angle, Brack, Brace #8892

Closed
wants to merge 1 commit into from
Closed
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
68 changes: 68 additions & 0 deletions base/brackets.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# all enclose styles work the same way

@doc "`⟪ args... ⟫` becomes `enclose_Angle( args... )`" ->
macro enclose_Angle(args...)
esc( Expr( :call, :enclose_Angle, args... ) )
end

@doc "`{| args... |}` becomes `enclose_Brace( args... )`" ->
macro enclose_Brace(args...)
esc( Expr( :call, :enclose_Brace, args... ) )
end

@doc "`[| args... |]` becomes `enclose_Brack( args... )`" ->
macro enclose_Brack(args...)
esc( Expr( :call, :enclose_Brack, args... ) )
end

@doc """
`foobar⟪ args... ⟫` becomes `call_Angle( foobar, args... )`

`foo.bar⟪ args... ⟫` becomes `call_Angle( foo.bar, args... )`

In practice, the type of foobar usually drives the dispatch.
"""->
macro call_Angle(sym, args...)
esc( Expr( :call, :call_Angle, sym, args... ) )
end

@doc """
`foobar{| args... |}` becomes `call_Brace( :foobar, args... )`

Note that `foobar` does not need to exist at all! It is
up to the remaining argument type signature to drive dispatch.

This behavior is different from Angle and Brack brackets.
This is to accommodate the situation where we want to pass the
called function as a symbol instead of an existing value.
See `@doc @call_Angle` and `@doc @call_Brack`.

In practice, packages that employ `foobar{| args... |}` are expected to use at least one
custom type in the function signature `args...`.

Also, we can pass an Expr as the 1st argument as well:

`foo.bar{| args... |}` becomes `call_Brace( :(foo.bar), args... )`

""" ->
macro call_Brace(sym, args...)
esc( Expr( :call, :call_Brace, Expr( :quote, sym ), args... ) )
end

@doc """
`foobar[| args...|]` becomes `call_Brack( foobar, args... )`

`foo.bar[| args...|]` becomes `call_Brack( foo.bar, args... )`

In practice, the type of foobar usually drives the dispatch.
"""->
macro call_Brack(sym, args...)
esc( Expr( :call, :call_Brack, sym, args... ) )
end

enclose_Angle( args... ) = throw(ArgumentError( "Undefined enclose_Angle for " * string(args) ) )
enclose_Brace( args... ) = throw(ArgumentError( "Undefined enclose_Brace for " * string(args) ) )
enclose_Brack( args... ) = throw(ArgumentError( "Undefined enclose_Brack for " * string(args) ) )
call_Angle( args... ) = throw(ArgumentError( "Undefined call_Angle for " * string(args) ) )
call_Brace( args... ) = throw(ArgumentError( "Undefined call_Brace for " * string(args) ) )
call_Brack( args... ) = throw(ArgumentError( "Undefined call_Brack for " * string(args) ) )
14 changes: 14 additions & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,20 @@ export
# nullable types
isnull,

# customizable special brackets ⟨⟩⟦⟧⦃⦄
@enclose_Angle,
@enclose_Brack,
@enclose_Brace,
@call_Angle,
@call_Brack,
@call_Brace,
enclose_Angle,
enclose_Brack,
enclose_Brace,
call_Angle,
call_Brack,
call_Brace,

# Macros
@__FILE__,
@b_str,
Expand Down
8 changes: 6 additions & 2 deletions base/latex_symbols.jl
Original file line number Diff line number Diff line change
Expand Up @@ -703,8 +703,12 @@ const latex_symbols = Dict(
"\\lrcorner" => "⌟",
"\\frown" => "⌢",
"\\smile" => "⌣",
"\\langle" => "⟨",
"\\rangle" => "⟩",
"\\lAngle" => "⟪", #U27ea
"\\rAngle" => "⟫", #U27eb
"\\lBrack" => "⟦", #U27e6
"\\rBrack" => "⟧", #U27e7
"\\lBrace" => "⦃", #U2983
"\\rBrace" => "⦄", #U2984
"\\obar" => "⌽",
"\\Elzdlcorn" => "⎣",
"\\lmoustache" => "⎰",
Expand Down
3 changes: 3 additions & 0 deletions base/sysimg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,9 @@ end

include("precompile.jl")

# handling special brackets, ⟨⟩⟦⟧⦃⦄
include( "brackets.jl")

include = include_from_node1

end # baremodule Base
Expand Down
6 changes: 6 additions & 0 deletions doc/manual/unicode-input-table.rst
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,12 @@ U+0231E ⌞ \\llcorner BOTTOM LEFT CORNER
U+0231F ⌟ \\lrcorner BOTTOM RIGHT CORNER
U+02322 ⌢ \\frown FROWN
U+02323 ⌣ \\smile SMILE
U+027EA ⟪ \\lAngle MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
U+027EB ⟫ \\rAngle MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
U+027E6 ⟦ \\lBrack MATHEMATICAL LEFT WHITE SQUARE BRACKET
U+027E7 ⟧ \\rBrack MATHEMATICAL RIGHT WHITE SQUARE BRACKET
U+02983 ⦃ \\lBrace LEFT WHITE CURLY BRACKET
U+02984 ⦄ \\rBrace RIGHT WHITE CURLY BRACKET
U+0232C ⌬ \\varhexagonlrbonds BENZENE RING
U+02332 ⌲ \\conictaper CONICAL TAPER
U+02336 ⌶ \\topbot APL FUNCTIONAL SYMBOL I-BEAM
Expand Down
128 changes: 123 additions & 5 deletions src/julia-parser.scm
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@

(define unary-ops '(+ - ! ¬ ~ |<:| |>:| √ ∛ ∜))

; We have to use tuples to disambiguate compound brackets from normal symbol operators
(define closing-brackets '(#\) #\] #\} #\❯ #\❱ #\⟫ #\⟧ #\⦄ (close-bracket |\|]|) (close-bracket |\|\}|)))
(define closing-brackets? (Set closing-brackets))

; operators that are both unary and binary
(define unary-and-binary-ops '(+ - $ & ~))

Expand Down Expand Up @@ -155,7 +159,7 @@
;; --- lexer ---

(define special-char?
(let ((chrs (string->list "()[]{},;\"`@")))
(let ((chrs (string->list "()[]{}❮❯❰❱⟪⟫⟦⟧⦃⦄,;\"`@")))
(lambda (c) (memv c chrs))))
(define (newline? c) (eqv? c #\newline))

Expand Down Expand Up @@ -431,6 +435,45 @@
(let ((c (peek-char port)))
(cond ((or (eof-object? c) (newline? c)) (read-char port))

;; it could be a normal curly brace or a compound brace {|
((eqv? c #\{)
(let ((c (read-char port))
(nextc (peek-char port)))
(if (eqv? nextc #\|)
( begin ( read-char port )
(string->symbol "{|") )
#\{ )))

;; it could be a normal square bracket or a compound [|
((eqv? c #\[)
(let ((c (read-char port))
(nextc (peek-char port)))
(if (eqv? nextc #\|)
( begin ( read-char port )
(string->symbol "[|") )
#\[ )))

;; it could be a closer |], |}, or operators |>, |=, ||, or just |
((eqv? c #\|)
(let ((c (read-char port))
(nextc (peek-char port)))
(cond ((eqv? nextc #\>)
(begin ( read-char port )
(string->symbol "|>" )))
((eqv? nextc #\=)
(begin ( read-char port )
(string->symbol "|=" )))
((eqv? nextc #\|)
(begin ( read-char port )
(string->symbol "||" )))
((eqv? nextc #\] )
(begin ( read-char port )
'(close-bracket |\|\]| ) ))
((eqv? nextc #\} )
(begin ( read-char port )
'(close-bracket |\|\}| ) ))
(else '|\|| ))))

((special-char? c) (read-char port))

((char-numeric? c) (read-number port #f #f))
Expand Down Expand Up @@ -572,7 +615,8 @@

(define (invalid-initial-token? tok)
(or (eof-object? tok)
(memv tok '(#\) #\] #\} else elseif catch finally =))))
(closing-brackets? tok)
(memv tok '(else elseif catch finally =))))

(define (line-number-node s)
`(line ,(input-port-line (ts:port s))))
Expand Down Expand Up @@ -780,7 +824,8 @@
(define (closing-token? tok)
(or (eof-object? tok)
(and (eq? tok 'end) (not end-symbol))
(memv tok '(#\, #\) #\] #\} #\; else elseif catch finally))))
(closing-brackets? tok)
(memv tok '(#\, #\; else elseif catch finally))))

(define (maybe-negate op num)
(if (eq? op '-)
Expand All @@ -804,7 +849,7 @@
(not (and (pair? expr) (eq? (car expr) '...)))
(or (number? expr)
(large-number? expr)
(not (memv t '(#\( #\[ #\{))))))
(not (memv t '(#\( #\[ #\{ #\❮ #\❰ #\⟪ #\⟦ #\⦃))))))

(define (parse-juxtapose ex s)
(let ((next (peek-token s)))
Expand Down Expand Up @@ -985,6 +1030,20 @@
((#\{ ) (take-token s)
(loop (list* 'curly ex
(map subtype-syntax (parse-arglist s #\} )))))
((#\❮ ) (take-token s)
(loop (list* 'macrocall '@call_Angle ex (parse-special-bracket s #\❯ ))))
((#\❰ ) (take-token s)
(loop (list* 'macrocall '@call_Angle ex (parse-special-bracket s #\❱ ))))
((#\⟪ ) (take-token s)
(loop (list* 'macrocall '@call_Angle ex (parse-special-bracket s #\⟫ ))))
((#\⟦ ) (take-token s)
(loop (list* 'macrocall '@call_Brack ex (parse-special-bracket s #\⟧ ))))
(( |\[\|| ) (take-token s)
(loop (list* 'macrocall '@call_Brack ex (parse-special-bracket s '(close-bracket |\|\]|) ))))
((#\⦃ ) (take-token s)
(loop (list* 'macrocall '@call_Brace ex (parse-special-bracket s #\⦄ ))))
(( |\{\|| ) (take-token s)
(loop (list* 'macrocall '@call_Brace ex (parse-special-bracket s '(close-bracket |\|\}| )))))
((#\")
(if (and (symbol? ex) (not (operator? ex))
(not (ts:space? s)))
Expand Down Expand Up @@ -1400,7 +1459,7 @@
;; newline character isn't detectable here
#;((eqv? c #\newline)
(error "unexpected line break in argument list"))
((memv c '(#\] #\}))
((closing-brackets? c )
(error (string "unexpected \"" c "\" in argument list")))
(else
(error (string "missing comma or " closer
Expand Down Expand Up @@ -1521,6 +1580,25 @@
(else
(parse-matrix s first closer)))))))))

(define ( parse-special-bracket s closer )
(with-normal-ops
(with-whitespace-newline
(parse-special-bracket- s closer ))))
(define (parse-special-bracket- s closer)
(let loop ((lst `()))
(let ((t (require-token s)))
(if (equal? t closer)
(begin (take-token s) (reverse lst ))
(let* ((nxt (parse-eq* s))
(c (require-token s)))
(cond ((eqv? c #\,)
(begin (take-token s) (loop (cons nxt lst))))
((equal? c closer) (loop (cons nxt lst)))
((closing-brackets? c)
(error (string "unexpected " c " in bracket. Close with " closer )))
(else
(error (string "unexpected " c ". Expect separator , or " closer )))))))))

; for sequenced evaluation inside expressions: e.g. (a;b, c;d)
(define (parse-stmts-within-expr s)
(parse-Nary s parse-eq* '(#\;) 'block '(#\, #\) ) #t))
Expand Down Expand Up @@ -1725,6 +1803,46 @@
;; misplaced =
((eq? t '=) (error "unexpected \"=\""))

;; \lBrack \rBrack expression
((equal? t '|\[\|| )
(take-token s)
(let ((vex (parse-special-bracket s '(close-bracket |\|\]| ) )))
(list* 'macrocall '@enclose_Brack vex )))

;; \lBrace \rBrace expression
((equal? t '|\{\|| )
(take-token s)
(let ((vex (parse-special-bracket s '(close-bracket |\|\}| ) )))
(list* 'macrocall '@enclose_Brace vex )))

;; \lBrack \rBrack expression
((eqv? t #\⟦ )
(take-token s)
(let ((vex (parse-special-bracket s #\⟧ )))
(list* 'macrocall '@enclose_Brack vex )))

;; \lBrace \rBrace expression
((eqv? t #\⦃ )
(take-token s)
(let ((vex (parse-special-bracket s #\⦄ )))
(list* 'macrocall '@enclose_Brace vex )))

;; \ldAngle \rdAngle expression
((eqv? t #\❰ )
(take-token s)
(let ((vex (parse-special-bracket s #\❱ )))
(list* 'macrocall '@enclose_Angle vex )))

((eqv? t #\❮ )
(take-token s)
(let ((vex (parse-special-bracket s #\❯ )))
(list* 'macrocall '@enclose_Angle vex )))

((eqv? t #\⟪ )
(take-token s)
(let ((vex (parse-special-bracket s #\⟫ )))
(list* 'macrocall '@enclose_Angle vex )))

;; identifier
((symbol? t) (take-token s))

Expand Down
Loading