Skip to content

Commit ea8668f

Browse files
authored
Fix parsing of chained unary and unary type operators (#249)
* Parsing `* <: A` doesn't crash the parser * `+ <: A` now parses correctly as `(call-pre + (<:-pre A))`.
1 parent e1d750f commit ea8668f

File tree

2 files changed

+17
-6
lines changed

2 files changed

+17
-6
lines changed

src/parser.jl

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,7 +1300,6 @@ function parse_unary(ps::ParseState)
13001300
end
13011301
end
13021302
else
1303-
@assert !is_type_operator(op_t) # `<:x` handled in parse_unary_subtype
13041303
if is_unary_op(op_t)
13051304
# Normal unary calls
13061305
# +x ==> (call-pre + x)
@@ -1310,15 +1309,21 @@ function parse_unary(ps::ParseState)
13101309
# -0x1 ==> (call-pre - 0x01)
13111310
# - 2 ==> (call-pre - 2)
13121311
# .-2 ==> (dotcall-pre - 2)
1313-
bump_dotsplit(ps, EMPTY_FLAGS)
1312+
op_pos = bump_dotsplit(ps, EMPTY_FLAGS)
13141313
else
13151314
# /x ==> (call-pre (error /) x)
13161315
# +₁ x ==> (call-pre (error +₁) x)
1317-
# .<: x ==> (dotcall-pre (error .<:) x)
1318-
bump(ps, error="not a unary operator")
1316+
# .<: x ==> (dotcall-pre (error (. <:)) x)
1317+
bump_dotsplit(ps, EMPTY_FLAGS, emit_dot_node=true)
1318+
op_pos = emit(ps, mark, K"error", error="not a unary operator")
13191319
end
13201320
parse_unary(ps)
1321-
emit(ps, mark, is_dotted(op_t) ? K"dotcall" : K"call", PREFIX_OP_FLAG)
1321+
if is_type_operator(op_t)
1322+
reset_node!(ps, op_pos, flags=TRIVIA_FLAG)
1323+
emit(ps, mark, op_k, PREFIX_OP_FLAG)
1324+
else
1325+
emit(ps, mark, is_dotted(op_t) ? K"dotcall" : K"call", PREFIX_OP_FLAG)
1326+
end
13221327
end
13231328
end
13241329

test/parser.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ tests = [
260260
# Not a unary operator
261261
"/x" => "(call-pre (error /) x)"
262262
"+₁ x" => "(call-pre (error +₁) x)"
263-
".<: x" => "(dotcall-pre (error .<:) x)"
263+
".<: x" => "(dotcall-pre (error (. <:)) x)"
264264
"?\"str\"" => """(call-pre (error ?) (string "str"))"""
265265
],
266266
JuliaSyntax.parse_factor => [
@@ -283,6 +283,9 @@ tests = [
283283
"<: x" => "(<:-pre x)"
284284
"<: <: x" => "(<:-pre (<:-pre x))"
285285
"<: A where B" => "(<:-pre (where A B))"
286+
# FIXME: The following bizarre precedence seems broken, but is
287+
# compatible with the reference parser (see #248)
288+
"+ <: A where B" => "(where (call-pre + (<:-pre A)) B)"
286289
# Really for parse_where
287290
"x where \n {T}" => "(where x T)"
288291
"x where {T,S}" => "(where x T S)"
@@ -291,6 +294,9 @@ tests = [
291294
"x where T" => "(where x T)"
292295
"x where \n T" => "(where x T)"
293296
"x where T<:S" => "(where x (<: T S))"
297+
# nested unary and unary-syntactic ops
298+
"<: + <: + A" => "(<:-pre (call-pre + (<:-pre (call-pre + A))))"
299+
"* <: A" => "(call-pre (error *) (<:-pre A))"
294300
],
295301
JuliaSyntax.parse_unary_prefix => [
296302
"&)" => "&"

0 commit comments

Comments
 (0)