@@ -1151,7 +1151,7 @@ function parse_unary(ps::ParseState)
1151
1151
bump_trivia (ps)
1152
1152
op_t = peek_token (ps)
1153
1153
op_k = kind (op_t)
1154
- if (
1154
+ if (
1155
1155
! is_operator (op_k) ||
1156
1156
is_word_operator (op_k) ||
1157
1157
(op_k in KSet " : ' .'" ) ||
@@ -1194,19 +1194,13 @@ function parse_unary(ps::ParseState)
1194
1194
end
1195
1195
end
1196
1196
if is_closing_token (ps, k2) || k2 in KSet " NewlineWs ="
1197
- if is_dotted (op_t)
1198
- # Standalone dotted operators are parsed as (|.| op)
1199
- # .+ ==> (. +)
1200
- # .+\n ==> (. +)
1201
- # .+ = ==> (. +)
1202
- # .+) ==> (. +)
1203
- # .& ==> (. &)
1204
- bump_dotsplit (ps, emit_dot_node= true )
1205
- else
1206
- # Standalone non-dotted operators
1207
- # +) ==> +
1208
- bump (ps)
1209
- end
1197
+ # Standalone operators parsed as `op` or `(. op)`
1198
+ # +) ==> +
1199
+ # +\n ==> +
1200
+ # + = ==> +
1201
+ # .+ ==> (. +)
1202
+ # .& ==> (. &)
1203
+ parse_atom (ps)
1210
1204
elseif k2 == K " {" || (! is_unary_op (op_t) && k2 == K " (" )
1211
1205
# Call with type parameters or non-unary prefix call
1212
1206
# +{T}(x::T) ==> (call (curly + T) (:: x T))
@@ -1267,28 +1261,13 @@ function parse_unary(ps::ParseState)
1267
1261
emit (ps, mark, op_k)
1268
1262
reset_node! (ps, op_pos, flags= TRIVIA_FLAG)
1269
1263
else
1270
- if is_dotted (op_t)
1271
- # Ugly hack to undo the split in bump_dotsplit
1272
- # .+(a,) ==> (call .+ a)
1273
- reset_node! (ps, op_pos, kind= K " TOMBSTONE" )
1274
- tb1 = ps. stream. tokens[op_pos. token_index- 1 ]
1275
- ps. stream. tokens[op_pos. token_index- 1 ] =
1276
- SyntaxToken (SyntaxHead (K " TOMBSTONE" , EMPTY_FLAGS),
1277
- K " TOMBSTONE" , tb1. preceding_whitespace,
1278
- tb1. next_byte- 1 )
1279
- tb0 = ps. stream. tokens[op_pos. token_index]
1280
- ps. stream. tokens[op_pos. token_index] =
1281
- SyntaxToken (SyntaxHead (kind (tb0), flags (tb0)),
1282
- tb0. orig_kind, tb0. preceding_whitespace,
1283
- tb0. next_byte)
1284
- end
1285
1264
emit (ps, mark, K " call" )
1286
1265
end
1287
1266
parse_call_chain (ps, mark)
1288
1267
parse_factor_with_initial_ex (ps, mark)
1289
1268
else
1290
1269
# Unary function calls with brackets as grouping, not an arglist
1291
- # .+(a) ==> (dotcall-pre (. +) (parens a))
1270
+ # .+(a) ==> (dotcall-pre + (parens a))
1292
1271
if opts. is_block
1293
1272
# +(a;b) ==> (call-pre + (block-p a b))
1294
1273
emit (ps, mark_before_paren, K " block" , PARENS_FLAG)
@@ -1627,6 +1606,10 @@ function parse_call_chain(ps::ParseState, mark, is_macrocall=false)
1627
1606
parse_atom (ps)
1628
1607
emit (ps, m, K " $" )
1629
1608
macro_name_position = position (ps)
1609
+ # We need `inert` rather than `quote` here for subtle reasons:
1610
+ # We need the expression expander to "see through" the quote
1611
+ # around the `$x` in `:(f.$x)`, so that the `$x` is expanded
1612
+ # even though it's double quoted.
1630
1613
emit (ps, m, K " inert" )
1631
1614
emit (ps, mark, K " ." )
1632
1615
elseif k == K " @"
@@ -2307,6 +2290,10 @@ function parse_do(ps::ParseState, mark)
2307
2290
emit (ps, mark, K " do" )
2308
2291
end
2309
2292
2293
+ function _is_valid_macro_name (peektok)
2294
+ return ! is_error (peektok. kind) && (peektok. is_leaf || peektok. kind == K " var" )
2295
+ end
2296
+
2310
2297
function fix_macro_name_kind! (ps:: ParseState , macro_name_position, name_kind= nothing )
2311
2298
k = peek_behind (ps, macro_name_position). kind
2312
2299
if k == K " var"
@@ -2321,7 +2308,8 @@ function fix_macro_name_kind!(ps::ParseState, macro_name_position, name_kind=not
2321
2308
return
2322
2309
end
2323
2310
if isnothing (name_kind)
2324
- name_kind = (k == K " Identifier" ) ? K " MacroName" : K " error"
2311
+ name_kind = _is_valid_macro_name (peek_behind (ps, macro_name_position)) ?
2312
+ K " MacroName" : K " error"
2325
2313
if name_kind == K " error"
2326
2314
# TODO : This isn't quite accurate
2327
2315
emit_diagnostic (ps, macro_name_position, macro_name_position,
@@ -2343,11 +2331,11 @@ function parse_macro_name(ps::ParseState)
2343
2331
bump_disallowed_space (ps)
2344
2332
mark = position (ps)
2345
2333
parse_atom (ps, false )
2346
- kb = peek_behind (ps, position (ps)). kind
2347
- if kb == K " parens"
2334
+ b = peek_behind (ps, position (ps))
2335
+ if b . kind == K " parens"
2348
2336
emit_diagnostic (ps, mark,
2349
2337
warning= " parenthesizing macro names is unnecessary" )
2350
- elseif ! (kb in KSet " Identifier var " )
2338
+ elseif ! _is_valid_macro_name (b )
2351
2339
# @[x] y z ==> (macrocall (error (vect x)) y z)
2352
2340
emit (ps, mark, K " error" , error= " invalid macro name" )
2353
2341
end
@@ -3448,20 +3436,18 @@ function parse_atom(ps::ParseState, check_identifiers=true)
3448
3436
# x₁ ==> x₁
3449
3437
bump (ps)
3450
3438
elseif is_operator (leading_kind)
3439
+ # + ==> +
3440
+ # .+ ==> (. +)
3441
+ # .= ==> (. =)
3442
+ bump_dotsplit (ps, emit_dot_node= true )
3451
3443
if check_identifiers && ! is_valid_identifier (leading_kind)
3452
3444
# += ==> (error +=)
3453
- # .+= ==> (error .+=)
3454
- bump (ps, error= " invalid identifier" )
3445
+ # ? ==> (error ?)
3446
+ # .+= ==> (error (. +=))
3447
+ emit (ps, mark, K " error" , error= " invalid identifier" )
3455
3448
else
3456
- # + ==> +
3457
- # ~ ==> ~
3458
3449
# Quoted syntactic operators allowed
3459
- # :+= ==> (quote +=)
3460
- # :.= ==> (quote .=)
3461
- # Remap the kind here to K"Identifier", as operators parsed in this
3462
- # branch should be in "identifier-like" positions (I guess this is
3463
- # correct? is it convenient?)
3464
- bump (ps, remap_kind= K " Identifier" )
3450
+ # :+= ==> (quote-: +=)
3465
3451
end
3466
3452
elseif is_keyword (leading_kind)
3467
3453
if leading_kind == K " var" && (t = peek_token (ps,2 );
0 commit comments