Note that this would make the syntax a < b < c ill-formed. It also doesn’t handle the comma-separated expression pattern:
[a<b, c>(d)];
Will this be parsed as
[ (a<b, c>(d)) ];
(one item a generic function call)? Or will it be parsed as
[ (a < b), (c > (d)) ];
(two items, comparison expressions)?
Option 2
Require parentheses inside of angle brackets. I.e., tokenize <( and )> as delimiters. Thus x<Y>(z) would be unambiguously parsed as a comparison expression, and a<b, c>(d) as two comma-separated comparison expressions. To make them generic function calls you would need to write x<(Y)>(z) and a<(b, c)>(d) respectively. Nice and symmetrical, but a little heavy to read.
x<y>(z); % parsed as `(x < y) > (z);` (chained comparison expressions)
x<(y)>(z); % parsed as `(x<(y)>(z));` (generic function call)
[a<b, c>(d)]; % parsed as `[ (a < b), (c > (d)) ];` (two comparison expression items)
[a<(b, c)>(d)]; % parsed as `[ (a<(b, c)>(d)) ];` (one generic function call item)
If applying to all type arguments:
[NS.map<T, Array<T>>(d)]; % tried to parse as `[ (NS.map < T), (Array < T), >>(d) ]`, but `>>(d)` is not well-formed
[NS.map<T, Array<(T)>>(d)]; % tried to parse as `[ (NS.map < T), (Array<(T)> > (d)) ]`, but `Array<(T)>` is not a well-formed expression
[NS.map<(T, Array<(T)>)>(d)]; % parsed as expected
Option 3
Require a trailing comma in the generic argument list: x<Y,>(z) cannot possibly be interpreted as a comparison expression, nor a<b, c,>(d) as three expressions (>(w) is not a well-formed expression). Not particularly pretty, but the most readable and easiest to implement.
x<y>(z); % parsed as `(x < y) > (z);` (chained comparison expressions)
x<y,>(z); % parsed as `(x<y,>(z));` (generic function call)
[a<b, c>(d)]; % parsed as `[ (a < b), (c > (d)) ];` (two comparison expression items)
[a<b, c,>(d)]; % parsed as `[ (a<b, c,>(d)) ];` (one generic function call item)
Update: Option 3 will not work since the shift-reduce parser always shifts as many tokens as possible. E.g., parsing x < Y > (z) will reduce x to ExpressionCompound, and then shift <, on track for a generic argument, and then see an unexpected >. It will never get a chance to reduce x to ExpressionComparative.
Option 4
Call all functions with a dot . before all arguments. x < Y > (z) is always a comparative expression while x.<Y>(z) is always a function call.
Ideas for resolving ambiguity between chained relational expressions
a < B > (c)
and generic function calls:a<B>(c)
. Inspired by #38, #39, and #21.Option 1Disallow chaining of relational expressions altogether.Then, in v0.7.0:
Note that this would make the syntax
a < b < c
ill-formed. It also doesn’t handle the comma-separated expression pattern:Will this be parsed as
(one item a generic function call)? Or will it be parsed as
(two items, comparison expressions)?
Option 2
Require parentheses inside of angle brackets. I.e., tokenize
<(
and)>
as delimiters. Thusx<Y>(z)
would be unambiguously parsed as a comparison expression, anda<b, c>(d)
as two comma-separated comparison expressions. To make them generic function calls you would need to writex<(Y)>(z)
anda<(b, c)>(d)
respectively. Nice and symmetrical, but a little heavy to read.If applying to all type arguments:
Option 3Require a trailing comma in the generic argument list:x<Y,>(z)
cannot possibly be interpreted as a comparison expression, nora<b, c,>(d)
as three expressions (>(w)
is not a well-formed expression). Not particularly pretty, but the most readable and easiest to implement.Update: Option 3 will not work since the shift-reduce parser always shifts as many tokens as possible. E.g., parsing
x < Y > (z)
will reducex
toExpressionCompound
, and then shift<
, on track for a generic argument, and then see an unexpected>
. It will never get a chance to reducex
toExpressionComparative
.Option 4
Call all functions with a dot
.
before all arguments.x < Y > (z)
is always a comparative expression whilex.<Y>(z)
is always a function call.We already see this pattern with member access:
a.b
andc.[d]
. Might as well be consistent with function calls:e.(f)
,g.<H>(i)
.Dot is only needed for function calls, so not needed for type arguments in general.