Skip to content

Commit

Permalink
Add destructure pattern parser
Browse files Browse the repository at this point in the history
  • Loading branch information
jfmengels committed Sep 12, 2024
1 parent 6a07f48 commit cc1b570
Show file tree
Hide file tree
Showing 4 changed files with 328 additions and 7 deletions.
4 changes: 2 additions & 2 deletions src/Elm/Parser/Declarations.elm
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module Elm.Parser.Declarations exposing (declaration)

import Elm.Parser.Comments as Comments
import Elm.Parser.DestructurePatterns as DestructurePatterns
import Elm.Parser.Expression exposing (expression)
import Elm.Parser.Layout as Layout
import Elm.Parser.Patterns as Patterns
import Elm.Parser.Tokens as Tokens
import Elm.Parser.TypeAnnotation as TypeAnnotation exposing (typeAnnotation, typeAnnotationNoFnExcludingTypedWithArguments)
import Elm.Syntax.Declaration as Declaration exposing (Declaration)
Expand Down Expand Up @@ -426,7 +426,7 @@ parameterPatternsEqual =
, syntax = patternResult.syntax
}
)
Patterns.patternNotDirectlyComposing
DestructurePatterns.patternNotDirectlyComposing
Layout.maybeLayout
)

Expand Down
320 changes: 320 additions & 0 deletions src/Elm/Parser/DestructurePatterns.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,320 @@
module Elm.Parser.DestructurePatterns exposing (patternNotDirectlyComposing)

import Elm.Parser.Layout as Layout
import Elm.Parser.Tokens as Tokens
import Elm.Syntax.Node as Node exposing (Node(..))
import Elm.Syntax.Pattern exposing (Pattern(..), QualifiedNameRef)
import Elm.Syntax.Range exposing (Range)
import ParserFast exposing (Parser)
import ParserWithComments exposing (WithComments)
import Rope


type PatternComposedWith
= PatternComposedWithNothing ()
| PatternComposedWithAs (Node String)


destructurePattern : Parser (WithComments (Node Pattern))
destructurePattern =
ParserFast.lazy (\() -> composablePatternTryToCompose)


composablePatternTryToCompose : Parser (WithComments (Node Pattern))
composablePatternTryToCompose =
ParserFast.map3
(\x commentsAfterLeft maybeComposedWithResult ->
{ comments =
x.comments
|> Rope.prependTo commentsAfterLeft
|> Rope.prependTo maybeComposedWithResult.comments
, syntax =
case maybeComposedWithResult.syntax of
PatternComposedWithNothing () ->
x.syntax

PatternComposedWithAs anotherName ->
Node.combine AsPattern x.syntax anotherName
}
)
composablePattern
Layout.maybeLayout
maybeComposedWith


maybeComposedWith : Parser { comments : ParserWithComments.Comments, syntax : PatternComposedWith }
maybeComposedWith =
ParserFast.orSucceed
(ParserFast.keywordFollowedBy "as"
(ParserFast.map2
(\commentsAfterAs name ->
{ comments = commentsAfterAs
, syntax = PatternComposedWithAs name
}
)
Layout.maybeLayout
Tokens.functionNameNode
)
)
{ comments = Rope.empty, syntax = PatternComposedWithNothing () }


parensPattern : Parser (WithComments (Node Pattern))
parensPattern =
ParserFast.symbolFollowedBy "("
(ParserFast.map2WithRange
(\range commentsBeforeHead contentResult ->
{ comments =
commentsBeforeHead
|> Rope.prependTo contentResult.comments
, syntax =
Node { start = { row = range.start.row, column = range.start.column - 1 }, end = range.end }
contentResult.syntax
}
)
Layout.maybeLayout
-- yes, ( ) is a valid pattern but not a valid type or expression
(ParserFast.oneOf2
(ParserFast.symbol ")" { comments = Rope.empty, syntax = UnitPattern })
(ParserFast.map3
(\headResult commentsAfterHead tailResult ->
{ comments =
headResult.comments
|> Rope.prependTo commentsAfterHead
|> Rope.prependTo tailResult.comments
, syntax =
case tailResult.syntax of
Nothing ->
ParenthesizedPattern headResult.syntax

Just secondAndMaybeThirdPart ->
case secondAndMaybeThirdPart.maybeThirdPart of
Nothing ->
TuplePattern [ headResult.syntax, secondAndMaybeThirdPart.secondPart ]

Just thirdPart ->
TuplePattern [ headResult.syntax, secondAndMaybeThirdPart.secondPart, thirdPart ]
}
)
destructurePattern
Layout.maybeLayout
(ParserFast.oneOf2
(ParserFast.symbol ")" { comments = Rope.empty, syntax = Nothing })
(ParserFast.symbolFollowedBy ","
(ParserFast.map4
(\commentsBefore secondPart commentsAfter maybeThirdPart ->
{ comments =
commentsBefore
|> Rope.prependTo secondPart.comments
|> Rope.prependTo commentsAfter
|> Rope.prependTo maybeThirdPart.comments
, syntax = Just { maybeThirdPart = maybeThirdPart.syntax, secondPart = secondPart.syntax }
}
)
Layout.maybeLayout
destructurePattern
Layout.maybeLayout
(ParserFast.oneOf2
(ParserFast.symbol ")" { comments = Rope.empty, syntax = Nothing })
(ParserFast.symbolFollowedBy ","
(ParserFast.map3
(\commentsBefore thirdPart commentsAfter ->
{ comments =
commentsBefore
|> Rope.prependTo thirdPart.comments
|> Rope.prependTo commentsAfter
, syntax = Just thirdPart.syntax
}
)
Layout.maybeLayout
destructurePattern
Layout.maybeLayout
|> ParserFast.followedBySymbol ")"
)
)
)
)
)
)
)
)
)


varPattern : Parser (WithComments (Node Pattern))
varPattern =
Tokens.functionNameMapWithRange
(\range var ->
{ comments = Rope.empty
, syntax = Node range (VarPattern var)
}
)


composablePattern : Parser (WithComments (Node Pattern))
composablePattern =
ParserFast.oneOf5
varPattern
qualifiedPatternWithConsumeArgs
allPattern
parensPattern
recordPattern


patternNotDirectlyComposing : Parser (WithComments (Node Pattern))
patternNotDirectlyComposing =
ParserFast.oneOf5
varPattern
qualifiedPatternWithoutConsumeArgs
allPattern
parensPattern
recordPattern


allPattern : Parser (WithComments (Node Pattern))
allPattern =
ParserFast.symbolWithRange "_"
(\range ->
{ comments = Rope.empty
, syntax = Node range AllPattern
}
)


maybeDotTypeNamesTuple : ParserFast.Parser (Maybe ( List String, String ))
maybeDotTypeNamesTuple =
ParserFast.orSucceed
(ParserFast.map2
(\startName afterStartName ->
case afterStartName of
Nothing ->
Just ( [], startName )

Just ( qualificationAfter, unqualified ) ->
Just ( startName :: qualificationAfter, unqualified )
)
(ParserFast.symbolFollowedBy "." Tokens.typeName)
(ParserFast.lazy (\() -> maybeDotTypeNamesTuple))
)
Nothing


qualifiedPatternWithConsumeArgs : Parser (WithComments (Node Pattern))
qualifiedPatternWithConsumeArgs =
ParserFast.map3
(\(Node nameRange name) afterStartName argsReverse ->
let
range : Range
range =
case argsReverse.syntax of
[] ->
nameRange

(Node lastArgRange _) :: _ ->
{ start = nameRange.start, end = lastArgRange.end }
in
{ comments = afterStartName |> Rope.prependTo argsReverse.comments
, syntax =
Node range
(NamedPattern
name
(List.reverse argsReverse.syntax)
)
}
)
qualifiedNameRefNode
Layout.optimisticLayout
(ParserWithComments.manyWithoutReverse
(Layout.positivelyIndentedFollowedBy
(ParserFast.map2
(\arg commentsAfterArg ->
{ comments = arg.comments |> Rope.prependTo commentsAfterArg
, syntax = arg.syntax
}
)
patternNotDirectlyComposing
Layout.optimisticLayout
)
)
)


qualifiedNameRefNode : Parser (Node QualifiedNameRef)
qualifiedNameRefNode =
ParserFast.map2WithRange
(\range firstName after ->
Node range
(case after of
Nothing ->
{ moduleName = [], name = firstName }

Just ( qualificationAfter, unqualified ) ->
{ moduleName = firstName :: qualificationAfter, name = unqualified }
)
)
Tokens.typeName
maybeDotTypeNamesTuple


qualifiedPatternWithoutConsumeArgs : Parser (WithComments (Node Pattern))
qualifiedPatternWithoutConsumeArgs =
ParserFast.map2WithRange
(\range firstName after ->
{ comments = Rope.empty
, syntax =
Node range
(NamedPattern
(case after of
Nothing ->
{ moduleName = [], name = firstName }

Just ( qualificationAfter, unqualified ) ->
{ moduleName = firstName :: qualificationAfter, name = unqualified }
)
[]
)
}
)
Tokens.typeName
maybeDotTypeNamesTuple


recordPattern : Parser (WithComments (Node Pattern))
recordPattern =
ParserFast.map2WithRange
(\range commentsBeforeElements elements ->
{ comments = commentsBeforeElements |> Rope.prependTo elements.comments
, syntax =
Node range (RecordPattern elements.syntax)
}
)
(ParserFast.symbolFollowedBy "{" Layout.maybeLayout)
(ParserFast.oneOf2
(ParserFast.map3
(\head commentsAfterHead tail ->
{ comments =
commentsAfterHead
|> Rope.prependTo tail.comments
, syntax = head :: tail.syntax
}
)
Tokens.functionNameNode
Layout.maybeLayout
(ParserWithComments.many
(ParserFast.symbolFollowedBy ","
(ParserFast.map3
(\beforeName name afterName ->
{ comments = beforeName |> Rope.prependTo afterName
, syntax = name
}
)
Layout.maybeLayout
Tokens.functionNameNode
Layout.maybeLayout
)
)
)
|> ParserFast.followedBySymbol "}"
)
(ParserFast.symbol "}" { comments = Rope.empty, syntax = [] })
)
9 changes: 5 additions & 4 deletions src/Elm/Parser/Expression.elm
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module Elm.Parser.Expression exposing (expression)

import Elm.Parser.DestructurePatterns as DestructurePatterns
import Elm.Parser.Layout as Layout
import Elm.Parser.Patterns as Patterns
import Elm.Parser.Tokens as Tokens
Expand Down Expand Up @@ -498,7 +499,7 @@ lambdaExpression =
}
)
Layout.maybeLayout
Patterns.patternNotDirectlyComposing
DestructurePatterns.patternNotDirectlyComposing
Layout.maybeLayout
(ParserWithComments.until
(ParserFast.symbol "->" ())
Expand All @@ -510,7 +511,7 @@ lambdaExpression =
, syntax = patternResult.syntax
}
)
Patterns.patternNotDirectlyComposing
DestructurePatterns.patternNotDirectlyComposing
Layout.maybeLayout
)
)
Expand Down Expand Up @@ -720,7 +721,7 @@ letDestructuringDeclaration =
(LetDestructuring pattern.syntax expressionResult.syntax)
}
)
Patterns.patternNotDirectlyComposing
DestructurePatterns.patternNotDirectlyComposing
Layout.maybeLayout
(ParserFast.symbolFollowedBy "=" Layout.maybeLayout)
expression
Expand Down Expand Up @@ -855,7 +856,7 @@ parameterPatternsEqual =
, syntax = patternResult.syntax
}
)
Patterns.patternNotDirectlyComposing
DestructurePatterns.patternNotDirectlyComposing
Layout.maybeLayout
)

Expand Down
2 changes: 1 addition & 1 deletion src/Elm/Parser/Patterns.elm
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module Elm.Parser.Patterns exposing (pattern, patternNotDirectlyComposing)
module Elm.Parser.Patterns exposing (pattern)

import Elm.Parser.Layout as Layout
import Elm.Parser.Tokens as Tokens
Expand Down

0 comments on commit cc1b570

Please sign in to comment.