gracelang / minigrace

Self-hosting compiler for the Grace programming language
39 stars 22 forks source link

Parsing ambiguity with blocks #262

Closed apblack closed 6 years ago

apblack commented 6 years ago

I've just spent the best part of a day trying to figure out why this won't compile:

    test "local type has method W" by {    
        type Local = interface {
            type W = T
            x -> Number
        }
        def rubbish = 7
        assert (Local.methodNames) shouldBe (set.withAll ["x", "W"])
    }

The error that one gets is

t020_typeInInterface_test.grace[45:14]: Syntax error: type literals must open with a brace.
  xx+0:     test "local type has method W" by {    
  xx+1:         type Local = interface {
---------------------^

The parser thinks that the type keyword is introducing a literal, and not a type declaration.

I've finally figured out that it's right! When the parser sees the {, it starts looking for a parameter. But we have a special rule that allows the name of a parameter (and the colon that follows it) to be omitted if the parameter is a pattern expression. That is, this is a legal block:

{ interface { a ; b } -> ...

which will match an object with a and b methods.

Since we allow the keyword type in place of interface, disambiguating these cases would require nested lookahead — once for trying to determine whether there are parameters, and once for trying to determine whether the type keyword introduces a declaration or a pattern expression.

The obvious fix is to stop allowing the use of type as a synonym for interface. That will remove the ambiguity. I plan to implement this asap.

KimBruce commented 6 years ago

Just to clarify, you are intending to continue to allow

type T = interface {...}

but not allow

type T = type {...}

Is that correct? If you disallow the first that would break virtually all of my 100's of programs.

Kim

kjx commented 6 years ago

Isn't that what the spec's said for ages?

I thought keeping both was purely a minigrace stopgap.

apblack commented 6 years ago

Yes to both. What I’m doing (have now done) is removing the stopgap. This was long overdue. I’ve fixed objectdraw, and the compiler itself, to use “interface” everywhere is is appropriate.