Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect result when using nested case expressions #67

Closed
jfmengels opened this issue Jun 18, 2017 · 2 comments
Closed

Incorrect result when using nested case expressions #67

jfmengels opened this issue Jun 18, 2017 · 2 comments

Comments

@jfmengels
Copy link

Hi! I noticed an incorrect AST when parsing something along the likes of

foo =
    case pattern of
        A -> 1
        B ->
            case variable of
                C -> 2
                _ -> 3

        _ ->
            4

Which results in an AST like the following

ast =
    Case (Variable [ "pattern" ])
        ([ ( Variable [ "A" ]
           , Integer 1
           )
         , ( Variable [ "B" ]
           , Case
                (Variable [ "variable" ])
                ([ ( Variable [ "C" ]
                   , Integer 2
                   )
                 , ( Variable [ "_" ], Integer 3 )
                 , ( Variable [ "_" ], Integer 4 )
                 ]
                )
           )
         ]
        )

I expect the first case expression to have 3 patterns (A, B and _ ) and the nested one under B to have 2 (C and _ ), but they respectively have 2 ((A, B) and (C, _ and _ ).

@wende
Copy link
Collaborator

wende commented Jun 19, 2017

Good find.
That's because of #1 fix being whitespace agnostic.
It's going to be quite hard to fix it though, but it seems we can't avoid whitespace sensitivity after all

@tunguski
Copy link

In my fork I wrote some code that seems to work fine in this situation.

caseExpression : OpTable -> Parser s Expression
caseExpression ops =
  let
    binding =
      lazy <| \() ->
        (,)
          <$> (wsAndComments *> expression ops)
          <*> (symbol "->" *> expression ops)
  in
    lazy <| \() ->
        withLocation (\location ->
            Case <$> (symbol "case" *> expression ops) <* symbol "of" <*> many
                ( lookAhead (wsAndComments *>
                    (primitive (\state inputStream ->
                        (state, inputStream, Ok (location.column <= (currentLocation inputStream).column))
                    )))
                    |> andThen (\isIndented ->
                        case isIndented of
                            True -> wsAndComments *> binding
                            False -> spaces_ *> binding
                    )
                )
        )

results in

FunctionDeclaration 
     (Function "foo" [] 
         (Case (Variable ["pattern"]) 
             ([ (Variable ["A"], Integer 1)
              , (Variable ["B"], Case (Variable ["variable"]) 
                                     ([ (Variable ["C"],Integer 2)
                                      , (Variable ["_"],Integer 3)
                                      ]
                                     )
                )
              , (Variable ["_"],Integer 4)])))

You would need to fit it into your code as it uses wsAndComments which is something unique for my fork.

The idea is to remember what was the first column of case word and parse only relatively indented code. Checking is next line indented "enough" is done by lookAhead parser that finds next non whitespace (or comment) token and checks it's indentation relatively to "base" token.

It won't work with tabs and spaces mixed!

Still it is enough for the scope of core code I test on.

Hope it helps!

@wende wende closed this as completed in #93 Jan 31, 2018
wende added a commit that referenced this issue Jan 31, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants