I can honestly say I wasn’t motivated by how wrong I felt you were, but by how I have been fiddling with declaration syntaxes like this over the last several months :)
Which actually led me to make an error here. The starting point was C syntax so I thought assuming a lexer hack was fair game, but the grammar above doesn’t actually need it! It doesn’t need one even if you add parameterized types with the same syntax as function calls. It only needs it if you want to write function calls as juxtaposition without parens ML style, use infix syntax for type application, or (and that is what I have been fiddling with) drop the semicolons.
(D'oh, I knew I was forgetting something! It was parenthesized expressions. And apparently I also screwed up optional comma termination. And curried calls.)
So, for example, you can add these productions to the grammar above and it still stays LR(1):
# Remove lexer hack, add parameterized types
type -> name | type ( ) | type ( type ) | type ( targ ) | type ( targ type ) .
targ -> type , | targ type , .
# Fix the stupid
dfun -> ambi ( darg decl ) | dfun ( decl ) | dfun ( darg ) | dfun ( darg decl ) .
efun -> ambi ( earg expr ) | efun ( expr ) | efun ( earg ) | efun ( earg expr ) | ( expr ) .
I’m not really a fan of this variant of “declaration mirrors use”, mind you. Type ascription usually requires some other syntax (both C and Go suffer from this); custom types that don’t have special punctuation are awkward and even tuples will be kind of forced. Typing the occasional colon does not seem like a bad tradeoff in comparison. I’d love to see these problems solved, though.