I'm having a go at implementing C# spec 7.16.2 "Query expression translation" in Roslyn. However, I've run into a problem in 7.16.2.5 "Select clauses".
It reads
A query expression of the form
from x in e select v
is translated into
( e ) . Select ( x => v )
except when v is the identifier x, the translation is simply
( e )
For example
from c in customers.Where(c => c.City == "London") select c
is simply translated into
customers.Where(c => c.City == "London")
My code does not produce a result matching the example, because (as per the "except when" line) I translate from x in e select x
into ( e )
, rather than just e
. Thus my code translates the example into
( customers.Where(c => c.City == "London") )
Is the example in the spec wrong, or do I need to be doing processing to recognise whether the enclosing parentheses are necessary? If so, is this in the spec somewhere?
Similarly, 7.16.2.6 (Groupby clauses) says
A query expression of the form
from x in e group v by k
is translated into
( e ) . GroupBy ( x => k , x => v )
except when v is the identifier x, the translation is
( e ) . GroupBy ( x => k )
The example
from c in customers group c.Name by c.Country
is translated into
customers. GroupBy(c => c.Country, c => c.Name)
where again the example result is missing the parentheses suggested by the spec.
In the example the construct 'e' is an expression and the construct '( e )' represents a primary. That is, there is a production in the C# grammar that allows '( e )' to be used anywhere a primary is expected. There is also a production that allows a primary to be used wherever an expression is expected.
In the 'from' code fragment an expression 'e' is required (as per the C# grammar), and in the 'Select()' fragment a primary is required, represented here as '( e )'.
The author of the example (perhaps unwisely) chose a primary 'customers' rather than an expression to illustrate the point. If the example had used an expression instead then the translation would have contained the parentheses. The example is correct, but borderline misleading.
In answer to your question, you can recognise whether the parentheses are necessary by recognising whether you are dealing with a primary or an expression. For a primary, they are not.
Disclosure: my expertise is compiler technology, C# syntax and Reflection.Emit but not (yet) Roslyn. I couldn't find any online docs, so I can't tell you how to do that in Roslyn.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With