diff --git a/src/Elm/Parser/Declarations.elm b/src/Elm/Parser/Declarations.elm index 3164f4b4..aa552012 100644 --- a/src/Elm/Parser/Declarations.elm +++ b/src/Elm/Parser/Declarations.elm @@ -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) @@ -426,7 +426,7 @@ parameterPatternsEqual = , syntax = patternResult.syntax } ) - Patterns.patternNotDirectlyComposing + DestructurePatterns.patternNotDirectlyComposing Layout.maybeLayout ) diff --git a/src/Elm/Parser/DestructurePatterns.elm b/src/Elm/Parser/DestructurePatterns.elm new file mode 100644 index 00000000..8d456ec4 --- /dev/null +++ b/src/Elm/Parser/DestructurePatterns.elm @@ -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 = [] }) + ) diff --git a/src/Elm/Parser/Expression.elm b/src/Elm/Parser/Expression.elm index 46e61720..264d6c9d 100644 --- a/src/Elm/Parser/Expression.elm +++ b/src/Elm/Parser/Expression.elm @@ -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 @@ -498,7 +499,7 @@ lambdaExpression = } ) Layout.maybeLayout - Patterns.patternNotDirectlyComposing + DestructurePatterns.patternNotDirectlyComposing Layout.maybeLayout (ParserWithComments.until (ParserFast.symbol "->" ()) @@ -510,7 +511,7 @@ lambdaExpression = , syntax = patternResult.syntax } ) - Patterns.patternNotDirectlyComposing + DestructurePatterns.patternNotDirectlyComposing Layout.maybeLayout ) ) @@ -720,7 +721,7 @@ letDestructuringDeclaration = (LetDestructuring pattern.syntax expressionResult.syntax) } ) - Patterns.patternNotDirectlyComposing + DestructurePatterns.patternNotDirectlyComposing Layout.maybeLayout (ParserFast.symbolFollowedBy "=" Layout.maybeLayout) expression @@ -855,7 +856,7 @@ parameterPatternsEqual = , syntax = patternResult.syntax } ) - Patterns.patternNotDirectlyComposing + DestructurePatterns.patternNotDirectlyComposing Layout.maybeLayout ) diff --git a/src/Elm/Parser/Patterns.elm b/src/Elm/Parser/Patterns.elm index 892381e1..198bbadc 100644 --- a/src/Elm/Parser/Patterns.elm +++ b/src/Elm/Parser/Patterns.elm @@ -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