Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inconsistency in C# spec 7.16.2.5

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.

like image 676
Rawling Avatar asked Nov 09 '13 14:11

Rawling


1 Answers

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.

like image 60
david.pfx Avatar answered Sep 23 '22 14:09

david.pfx