Skip to content

Commit a00d5bd

Browse files
authored
Distinguish :x from quote x end with a flag (#245)
This is also distinguishable based on the presence of a child `block` as the only argument, but having the flag is convenient and also allows to distinguish cases like `x.:y` from `x.y`.
1 parent bd4ae55 commit a00d5bd

File tree

3 files changed

+45
-41
lines changed

3 files changed

+45
-41
lines changed

src/parse_stream.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ const RAW_STRING_FLAG = RawFlags(1<<6)
3131

3232
# Set for K"tuple", K"block" or K"macrocall" which are delimited by parentheses
3333
const PARENS_FLAG = RawFlags(1<<5)
34+
# Set for K"quote" for the short form `:x` as oppsed to long form `quote x end`
35+
const COLON_QUOTE = RawFlags(1<<5)
3436

3537
# Set for K"struct" when mutable
3638
const MUTABLE_FLAG = RawFlags(1<<5)
@@ -95,6 +97,8 @@ function untokenize(head::SyntaxHead; unique=true, include_flag_suff=true)
9597
has_flags(head, RAW_STRING_FLAG) && (str = str*"-r")
9698
elseif kind(head) in KSet"tuple block macrocall"
9799
has_flags(head, PARENS_FLAG) && (str = str*"-p")
100+
elseif kind(head) == K"quote"
101+
has_flags(head, COLON_QUOTE) && (str = str*"-:")
98102
elseif kind(head) == K"struct"
99103
has_flags(head, MUTABLE_FLAG) && (str = str*"-mut")
100104
elseif kind(head) == K"module"

src/parser.jl

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -844,8 +844,8 @@ function parse_range(ps::ParseState)
844844
preceding_whitespace(peek_token(ps)) &&
845845
!preceding_whitespace(peek_token(ps, 2))
846846
# Tricky cases in space sensitive mode
847-
# [1 :a] ==> (hcat 1 (quote a))
848-
# [1 2:3 :a] ==> (hcat 1 (call-i 2 : 3) (quote a))
847+
# [1 :a] ==> (hcat 1 (quote-: a))
848+
# [1 2:3 :a] ==> (hcat 1 (call-i 2 : 3) (quote-: a))
849849
break
850850
end
851851
t2 = peek_token(ps,2)
@@ -1159,7 +1159,7 @@ function parse_unary(ps::ParseState)
11591159
is_syntactic_operator(op_k)
11601160
)
11611161
# `op_t` is not an initial operator
1162-
# :T ==> (quote T)
1162+
# :T ==> (quote-: T)
11631163
# in::T ==> (:: in T)
11641164
# isa::T ==> (:: isa T)
11651165
parse_factor(ps)
@@ -1609,13 +1609,13 @@ function parse_call_chain(ps::ParseState, mark, is_macrocall=false)
16091609
parse_call_arglist(ps, K")")
16101610
emit(ps, mark, K"dotcall")
16111611
elseif k == K":"
1612-
# A.:+ ==> (. A (quote +))
1613-
# A.: + ==> (. A (error-t) (quote +))
1612+
# A.:+ ==> (. A (quote-: +))
1613+
# A.: + ==> (. A (error-t) (quote-: +))
16141614
m = position(ps)
16151615
bump(ps, TRIVIA_FLAG)
16161616
bump_disallowed_space(ps)
16171617
parse_atom(ps, false)
1618-
emit(ps, m, K"quote")
1618+
emit(ps, m, K"quote", COLON_QUOTE)
16191619
emit(ps, mark, K".")
16201620
elseif k == K"$"
16211621
# f.$x ==> (. f (inert ($ x)))
@@ -2374,21 +2374,21 @@ function parse_atsym(ps::ParseState, allow_quotes=true)
23742374
# export ($f) ==> (export ($ f))
23752375
mark = position(ps)
23762376
if allow_quotes && peek(ps) == K":"
2377-
# import A.:+ ==> (import (importpath A (quote +)))
2377+
# import A.:+ ==> (import (importpath A (quote-: +)))
23782378
emit_diagnostic(ps, warning="quoting with `:` is not required here")
23792379
end
23802380
parse_unary_prefix(ps)
23812381
pos = position(ps)
23822382
warn_parens = false
23832383
if peek_behind(ps, pos).kind == K"parens"
2384-
# import A.(:+) ==> (import (importpath A (parens (quote +))))
2384+
# import A.(:+) ==> (import (importpath A (parens (quote-: +))))
23852385
pos = first_child_position(ps, pos)
23862386
warn_parens = true
23872387
end
23882388
if allow_quotes && peek_behind(ps, pos).kind == K"quote"
23892389
pos = first_child_position(ps, pos)
23902390
if peek_behind(ps, pos).kind == K"parens"
2391-
# import A.:(+) ==> (import (importpath A (quote (parens +))))
2391+
# import A.:(+) ==> (import (importpath A (quote-: (parens +))))
23922392
pos = first_child_position(ps, pos)
23932393
warn_parens = true
23942394
end
@@ -3015,14 +3015,14 @@ function parse_paren(ps::ParseState, check_identifiers=true)
30153015
emit(ps, mark, K"tuple", PARENS_FLAG)
30163016
elseif is_syntactic_operator(k)
30173017
# allow :(=) etc in unchecked contexts, eg quotes
3018-
# :(=) ==> (quote (parens =))
3018+
# :(=) ==> (quote-: (parens =))
30193019
parse_atom(ps, check_identifiers)
30203020
bump_closing_token(ps, K")")
30213021
emit(ps, mark, K"parens")
30223022
elseif !check_identifiers && k == K"::" &&
30233023
peek(ps, 2, skip_newlines=true) == K")"
30243024
# allow :(::) as a special case
3025-
# :(::) ==> (quote (parens ::))
3025+
# :(::) ==> (quote-: (parens ::))
30263026
bump(ps)
30273027
bump(ps, TRIVIA_FLAG, skip_newlines=true)
30283028
emit(ps, mark, K"parens")
@@ -3415,7 +3415,7 @@ function parse_atom(ps::ParseState, check_identifiers=true)
34153415
emit(ps, mark, K"char")
34163416
elseif leading_kind == K":"
34173417
# symbol/expression quote
3418-
# :foo ==> (quote foo)
3418+
# :foo ==> (quote-: foo)
34193419
t = peek_token(ps, 2)
34203420
k = kind(t)
34213421
if is_closing_token(ps, k) && (!is_keyword(k) || preceding_whitespace(t))
@@ -3427,19 +3427,19 @@ function parse_atom(ps::ParseState, check_identifiers=true)
34273427
end
34283428
bump(ps, TRIVIA_FLAG) # K":"
34293429
if preceding_whitespace(t)
3430-
# : foo ==> (quote (error-t) foo)
3431-
# :\nfoo ==> (quote (error-t) foo)
3430+
# : foo ==> (quote-: (error-t) foo)
3431+
# :\nfoo ==> (quote-: (error-t) foo)
34323432
bump_trivia(ps, TRIVIA_FLAG, skip_newlines=true,
34333433
error="whitespace not allowed after `:` used for quoting")
34343434
end
34353435
# Being inside quote makes keywords into identifiers at the
34363436
# first level of nesting
3437-
# :end ==> (quote end)
3438-
# :(end) ==> (quote (parens (error-t)))
3437+
# :end ==> (quote-: end)
3438+
# :(end) ==> (quote-: (parens (error-t)))
34393439
# Being inside quote makes end non-special again (issue #27690)
3440-
# a[:(end)] ==> (ref a (quote (error-t end)))
3440+
# a[:(end)] ==> (ref a (quote-: (error-t end)))
34413441
parse_atom(ParseState(ps, end_symbol=false), false)
3442-
emit(ps, mark, K"quote")
3442+
emit(ps, mark, K"quote", COLON_QUOTE)
34433443
elseif check_identifiers && leading_kind == K"=" && is_plain_equals(peek_token(ps))
34443444
# = ==> (error =)
34453445
bump(ps, error="unexpected `=`")
@@ -3505,12 +3505,12 @@ function parse_atom(ps::ParseState, check_identifiers=true)
35053505
end
35063506
emit(ps, mark, K"var")
35073507
elseif check_identifiers && is_closing_token(ps, leading_kind)
3508-
# :(end) ==> (quote (error end))
3508+
# :(end) ==> (quote-: (error end))
35093509
bump(ps, error="invalid identifier")
35103510
else
35113511
# Remap keywords to identifiers.
3512-
# :end ==> (quote end)
3513-
# :<: ==> (quote <:)
3512+
# :end ==> (quote-: end)
3513+
# :<: ==> (quote-: <:)
35143514
bump(ps, remap_kind=K"Identifier")
35153515
end
35163516
elseif leading_kind == K"(" # parens or tuple

test/parser.jl

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,8 @@ tests = [
142142
"a..b" => "(call-i a .. b)"
143143
"a … b" => "(call-i a … b)"
144144
"a .… b" => "(dotcall-i a … b)"
145-
"[1 :a]" => "(hcat 1 (quote a))"
146-
"[1 2:3 :a]" => "(hcat 1 (call-i 2 : 3) (quote a))"
145+
"[1 :a]" => "(hcat 1 (quote-: a))"
146+
"[1 2:3 :a]" => "(hcat 1 (call-i 2 : 3) (quote-: a))"
147147
"x..." => "(... x)"
148148
"x:y..." => "(... (call-i x : y))"
149149
"x..y..." => "(... (call-i x .. y))"
@@ -195,7 +195,7 @@ tests = [
195195
"x 'y" => "x"
196196
],
197197
JuliaSyntax.parse_unary => [
198-
":T" => "(quote T)"
198+
":T" => "(quote-: T)"
199199
"in::T" => "(::-i in T)"
200200
"isa::T" => "(::-i isa T)"
201201
"-2^x" => "(call-pre - (call-i 2 ^ x))"
@@ -374,7 +374,7 @@ tests = [
374374
"(a=1)[]" => "(ref (parens (= a 1)))" => Expr(:ref, Expr(:(=), :a, 1))
375375
"a[end]" => "(ref a end)"
376376
"a[begin]" => "(ref a begin)"
377-
"a[:(end)]" => "(typed_hcat a (quote (parens (error-t))) (error-t))"
377+
"a[:(end)]" => "(typed_hcat a (quote-: (parens (error-t))) (error-t))"
378378
"T[x y]" => "(typed_hcat T x y)"
379379
"T[x ; y]" => "(typed_vcat T x y)"
380380
"T[a b; c d]" => "(typed_vcat T (row a b) (row c d))"
@@ -393,8 +393,8 @@ tests = [
393393
"(a=1).()" => "(dotcall (parens (= a 1)))" => Expr(:., Expr(:(=), :a, 1), Expr(:tuple))
394394
"f. (x)" => "(dotcall f (error-t) x)"
395395
# Other dotted syntax
396-
"A.:+" => "(. A (quote +))"
397-
"A.: +" => "(. A (quote (error-t) +))"
396+
"A.:+" => "(. A (quote-: +))"
397+
"A.: +" => "(. A (quote-: (error-t) +))"
398398
"f.\$x" => "(. f (inert (\$ x)))"
399399
"f.\$(x+y)" => "(. f (inert (\$ (parens (call-i x + y)))))"
400400
"A.\$B.@x" => "(macrocall (. (. A (inert (\$ B))) (quote @x)))"
@@ -648,9 +648,9 @@ tests = [
648648
"import \$A.@x" => "(import (importpath (\$ A) @x))"
649649
"import A.B" => "(import (importpath A B))"
650650
"import A.B.C" => "(import (importpath A B C))"
651-
"import A.:+" => "(import (importpath A (quote +)))"
652-
"import A.(:+)" => "(import (importpath A (parens (quote +))))"
653-
"import A.:(+)" => "(import (importpath A (quote (parens +))))"
651+
"import A.:+" => "(import (importpath A (quote-: +)))"
652+
"import A.(:+)" => "(import (importpath A (parens (quote-: +))))"
653+
"import A.:(+)" => "(import (importpath A (quote-: (parens +))))"
654654
"import A.==" => "(import (importpath A ==))"
655655
"import A.⋆.f" => "(import (importpath A ⋆ f))"
656656
"import A..." => "(import (importpath A ..))"
@@ -712,13 +712,13 @@ tests = [
712712
"''" => "(char (error))"
713713
"'" => "(char (error))"
714714
# symbol/expression quote
715-
":foo" => "(quote foo)"
715+
":foo" => "(quote-: foo)"
716716
# Literal colons
717717
":)" => ":"
718718
": end" => ":"
719719
# Whitespace after quoting colon
720-
": foo" => "(quote (error-t) foo)"
721-
":\nfoo" => "(quote (error-t) foo)"
720+
": foo" => "(quote-: (error-t) foo)"
721+
":\nfoo" => "(quote-: (error-t) foo)"
722722
# plain equals
723723
"=" => "(error =)"
724724
# Identifiers
@@ -745,12 +745,12 @@ tests = [
745745
"+" => "+"
746746
"~" => "~"
747747
# Quoted syntactic operators allowed
748-
":+=" => "(quote +=)"
749-
":.=" => "(quote .=)"
748+
":+=" => "(quote-: +=)"
749+
":.=" => "(quote-: .=)"
750750
# Special symbols quoted
751-
":end" => "(quote end)"
752-
":(end)" => "(quote (parens (error-t)))"
753-
":<:" => "(quote <:)"
751+
":end" => "(quote-: end)"
752+
":(end)" => "(quote-: (parens (error-t)))"
753+
":<:" => "(quote-: <:)"
754754
# unexpect =
755755
"=" => "(error =)"
756756
# parse_cat
@@ -782,9 +782,9 @@ tests = [
782782
"[x=1, y=2]" => "(vect (= x 1) (= y 2))"
783783
"[x=1, ; y=2]" => "(vect (= x 1) (parameters (= y 2)))"
784784
# parse_paren
785-
":(=)" => "(quote (parens =))"
786-
":(::)" => "(quote (parens ::))"
787-
":(::\n)" => "(quote (parens ::))"
785+
":(=)" => "(quote-: (parens =))"
786+
":(::)" => "(quote-: (parens ::))"
787+
":(::\n)" => "(quote-: (parens ::))"
788788
"(function f \n end)" => "(parens (function f))"
789789
# braces
790790
"{x y}" => "(bracescat (row x y))"

0 commit comments

Comments
 (0)