diff --git a/src/Yaml/Parser/Util.elm b/src/Yaml/Parser/Util.elm index 6493e05..140e768 100644 --- a/src/Yaml/Parser/Util.elm +++ b/src/Yaml/Parser/Util.elm @@ -16,6 +16,7 @@ module Yaml.Parser.Util exposing , multiline , neither , neither3 + , postProcessLiteralString , postProcessString , remaining , singleQuotes @@ -196,11 +197,14 @@ multilineStep indent lines = let multilineString : List String -> String multilineString lines_ = - String.join " " (List.reverse lines_) + String.join "\n" (List.reverse lines_) - conclusion line indent_ = + conclusion line emptyLineCount indent_ = if indent_ > indent then - P.Loop (line :: lines) + P.Loop + ((line ++ String.repeat emptyLineCount "\n") + :: lines + ) else P.Done (multilineString (line :: lines)) @@ -210,11 +214,27 @@ multilineStep indent lines = |= characters (not << isNewLine) |. P.chompIf isNewLine |. spaces + |= emptyLines |= P.getCol , P.succeed (P.Done <| multilineString lines) ] +emptyLines : P.Parser Int +emptyLines = + P.loop 0 emptyLinesStep + + +emptyLinesStep : Int -> P.Parser (P.Step Int Int) +emptyLinesStep count = + P.oneOf + [ P.succeed (P.Loop (count + 1)) + |. P.chompIf isNewLine + |. spaces + , P.succeed (P.Done count) + ] + + {-| -} characters : (Char -> Bool) -> P.Parser String characters isOk = @@ -282,12 +302,22 @@ remaining = postProcessString : String -> String postProcessString str = + if isLiteralString str then + postProcessLiteralString str + + else + postProcessFoldedString str + + +postProcessFoldedString : String -> String +postProcessFoldedString str = let regexFromString : String -> Regex regexFromString = Regex.fromString >> Maybe.withDefault Regex.never in str + |> String.replace "\n" " " |> Regex.replace (regexFromString "\\s\\s+") (\match -> if String.contains "\n\n" match.match then @@ -298,6 +328,62 @@ postProcessString str = ) +isLiteralString : String -> Bool +isLiteralString str = + str + |> String.split "\n" + |> List.head + |> (==) (Just "|") + + +postProcessLiteralString : String -> String +postProcessLiteralString str = + case String.left 2 str of + "|\n" -> + let + content = + String.dropLeft 2 str + in + content + |> countLeadingSpacesInMultiline + |> removeLeadingSpaces content + + _ -> + str + + +removeLeadingSpaces : String -> Int -> String +removeLeadingSpaces str count = + str + |> String.split "\n" + |> List.map (String.dropLeft count) + |> String.join "\n" + + +countLeadingSpacesInMultiline : String -> Int +countLeadingSpacesInMultiline str = + str + |> String.split "\n" + |> List.head + |> Maybe.withDefault "" + |> countLeadingSpacesInString + + +countLeadingSpacesInString : String -> Int +countLeadingSpacesInString str = + let + countHelper : String -> Int -> Int + countHelper s count = + case String.uncons s of + Just ( ' ', rest ) -> + countHelper rest (count + 1) + + _ -> + count + in + countHelper str 0 + + -- INDENT diff --git a/tests/TestParser.elm b/tests/TestParser.elm index 2cd2e5f..e1eefd9 100644 --- a/tests/TestParser.elm +++ b/tests/TestParser.elm @@ -59,20 +59,18 @@ suite = Ast.Float_ x , Test.test "a single-quoted string" <| \_ -> - -- TODO is this right? expectValue """'hey - i am a - - parser'""" <| - Ast.String_ "hey i am a\nparser" + i am a + parser'""" <| + Ast.String_ "hey i am a parser" , Test.test "a single quoted string with no closing quote" <| \_ -> expectErr "'hello" , Test.test "a double-quoted string" <| \_ -> expectValue """"hey - i am a - parser" """ <| + i am a + parser" """ <| Ast.String_ "hey i am a parser" , Test.test "a double-quoted string with no closing quote" <| \_ -> @@ -91,24 +89,51 @@ suite = \_ -> expectValue """how does one teach self-respect? - how does one teach curiousity? - if you have the answers, call me - """ + how does one teach curiousity? + if you have the answers, call me + """ <| Ast.String_ "how does one teach self-respect? how does one teach curiousity? if you have the answers, call me" , Test.test "a multi-line string with three dot ending" <| \_ -> expectValue """how does one teach self-respect? - how does one teach curiousity? - if you have the answers, call me + how does one teach curiousity? + if you have the answers, call me ... - """ + """ <| Ast.String_ "how does one teach self-respect? how does one teach curiousity? if you have the answers, call me" + , Test.test + "a literal multi-line string" + <| + \_ -> + expectValue "|\n literal\n \ttext" <| + Ast.String_ "literal\n\ttext" + , Test.test "a record with literal string" <| + \_ -> + expectValue + """ + aaa: | + hello + world + """ + <| + Ast.Record_ (Dict.fromList [ ( "aaa", Ast.String_ "hello\nworld" ) ]) + , Test.test "a record with literal string with empty lines" <| + \_ -> + expectValue + """ + aaa: | + hello + + world + """ + <| + Ast.Record_ (Dict.fromList [ ( "aaa", Ast.String_ "hello\n\nworld" ) ]) , Test.test "a empty inline list" <| \_ -> expectValue "[]" <| @@ -151,26 +176,26 @@ suite = , Test.test "an inline list with strings and with new lines" <| \_ -> expectValue """[ - aaa, - bbb, - ccc - ]""" <| + aaa, + bbb, + ccc + ]""" <| Ast.List_ [ Ast.String_ "aaa", Ast.String_ "bbb", Ast.String_ "ccc" ] , Test.test "an inline list with strings and with new lines and comments" <| \_ -> expectValue """[ aaa,# A comment - bbb, # a dumb comment - ccc - ]""" <| + bbb, # a dumb comment + ccc + ]""" <| Ast.List_ [ Ast.String_ "aaa", Ast.String_ "bbb", Ast.String_ "ccc" ] , Test.test "an inline list with strings, with new lines, and multi-line strings" <| \_ -> expectValue """[ aaa, - bbb, - ccc ccc - ccc - ]""" <| - Ast.List_ [ Ast.String_ "aaa", Ast.String_ "bbb", Ast.String_ "ccc ccc\n ccc" ] + bbb, + ccc ccc + ccc + ]""" <| + Ast.List_ [ Ast.String_ "aaa", Ast.String_ "bbb", Ast.String_ "ccc ccc\n ccc" ] , Test.test "an inline list with an inline list inside" <| \_ -> expectValue "[ aaa, [ bbb, aaa, ccc ], ccc ]" <| @@ -199,10 +224,10 @@ suite = \_ -> expectValue """ - {bbb: - bbb , aaa: aaa - , ccc: ccc} - """ + {bbb: + bbb , aaa: aaa + , ccc: ccc} + """ <| Ast.Record_ (Dict.fromList [ ( "bbb", Ast.String_ "bbb" ), ( "aaa", Ast.String_ "aaa" ), ( "ccc", Ast.String_ "ccc" ) ]) , Test.test "an inline record with an inline record inside" <| @@ -213,87 +238,87 @@ suite = \_ -> expectValue """ - - aaa - - bbb - - ccc - """ + - aaa + - bbb + - ccc + """ <| Ast.List_ [ Ast.String_ "aaa", Ast.String_ "bbb", Ast.String_ "ccc" ] , Test.test "a list with null" <| \_ -> expectValue """ - - - - bbb - - ccc - """ + - + - bbb + - ccc + """ <| Ast.List_ [ Ast.Null_, Ast.String_ "bbb", Ast.String_ "ccc" ] , Test.test "a list with multi-line string" <| \_ -> expectValue """ - - - - bbb - bbb bbb - bbb - - ccc - """ + - + - bbb + bbb bbb + bbb + - ccc + """ <| Ast.List_ [ Ast.Null_, Ast.String_ "bbb bbb bbb bbb", Ast.String_ "ccc" ] , Test.test "a list with a list inside" <| \_ -> expectValue """ - - aaa - - - - aaa - - bbb - - ccc - - ccc - """ <| + - aaa + - + - aaa + - bbb + - ccc + - ccc + """ <| Ast.List_ [ Ast.String_ "aaa", Ast.List_ [ Ast.String_ "aaa", Ast.String_ "bbb", Ast.String_ "ccc" ], Ast.String_ "ccc" ] , Test.test "a list with a list inside on same line" <| \_ -> expectValue """ - - aaa - - - aaa - - bbb - - ccc - - ccc - """ <| + - aaa + - - aaa + - bbb + - ccc + - ccc + """ <| Ast.List_ [ Ast.String_ "aaa", Ast.List_ [ Ast.String_ "aaa", Ast.String_ "bbb", Ast.String_ "ccc" ], Ast.String_ "ccc" ] , Test.test "a list with smaller trailing indentation" <| \_ -> expectValue """ - - aaa - - bbb - """ <| + - aaa + - bbb + """ <| Ast.List_ [ Ast.String_ "aaa", Ast.String_ "bbb" ] , Test.test "a list with larger trailing indentation" <| \_ -> expectValue """ - - aaa - - bbb - """ <| + - aaa + - bbb + """ <| Ast.List_ [ Ast.String_ "aaa", Ast.String_ "bbb" ] , Test.test "a record" <| \_ -> expectValue """ - aaa: aaa - bbb: bbb - ccc: ccc - """ + aaa: aaa + bbb: bbb + ccc: ccc + """ <| Ast.Record_ (Dict.fromList [ ( "aaa", Ast.String_ "aaa" ), ( "bbb", Ast.String_ "bbb" ), ( "ccc", Ast.String_ "ccc" ) ]) , Test.test "a record with quoted property names and values" <| \_ -> expectValue """ - 'aaa': aaa - "bbb": "bbb" - 'ccc': 'ccc' - """ + 'aaa': aaa + "bbb": "bbb" + 'ccc': 'ccc' + """ <| Ast.Record_ (Dict.fromList [ ( "aaa", Ast.String_ "aaa" ), ( "bbb", Ast.String_ "bbb" ), ( "ccc", Ast.String_ "ccc" ) ]) , Test.test "a record with a quoted property name and a space before the colon" <| @@ -318,71 +343,71 @@ suite = \_ -> expectValue """ - aaa: aaa - bbb: - aaa: aaa - bbb: bbb - ccc: ccc - ccc: ccc - """ + aaa: aaa + bbb: + aaa: aaa + bbb: bbb + ccc: ccc + ccc: ccc + """ <| Ast.Record_ (Dict.fromList [ ( "aaa", Ast.String_ "aaa" ), ( "bbb", Ast.Record_ (Dict.fromList [ ( "aaa", Ast.String_ "aaa" ), ( "bbb", Ast.String_ "bbb" ), ( "ccc", Ast.String_ "ccc" ) ]) ), ( "ccc", Ast.String_ "ccc" ) ]) , Test.test "a record with a list inside" <| \_ -> expectValue """ - aaa: aaa - bbb: - - aaa - - bbb - - ccc - ccc: ccc - """ + aaa: aaa + bbb: + - aaa + - bbb + - ccc + ccc: ccc + """ <| Ast.Record_ (Dict.fromList [ ( "aaa", Ast.String_ "aaa" ), ( "bbb", Ast.List_ [ Ast.String_ "aaa", Ast.String_ "bbb", Ast.String_ "ccc" ] ), ( "ccc", Ast.String_ "ccc" ) ]) , Test.test "a record with a list inside on the same level" <| \_ -> expectValue """ - aaa: aaa - bbb: - - aaa - - bbb - - ccc - ccc: ccc - """ + aaa: aaa + bbb: + - aaa + - bbb + - ccc + ccc: ccc + """ <| Ast.Record_ (Dict.fromList [ ( "aaa", Ast.String_ "aaa" ), ( "bbb", Ast.List_ [ Ast.String_ "aaa", Ast.String_ "bbb", Ast.String_ "ccc" ] ), ( "ccc", Ast.String_ "ccc" ) ]) , Test.test "a record with strings comments" <| \_ -> expectValue """ - aaa: aaa# hey - bbb: bbb # hey - ccc: ccc # hey - ddd: ddd # hey - """ + aaa: aaa# hey + bbb: bbb # hey + ccc: ccc # hey + ddd: ddd # hey + """ <| Ast.Record_ (Dict.fromList [ ( "aaa", Ast.String_ "aaa" ), ( "bbb", Ast.String_ "bbb" ), ( "ccc", Ast.String_ "ccc" ), ( "ddd", Ast.String_ "ddd" ) ]) , Test.test "a record with mixed values" <| \_ -> expectValue """ - aaa: 1 - bbb: bbb - ccc: 1.0 - """ + aaa: 1 + bbb: bbb + ccc: 1.0 + """ <| Ast.Record_ (Dict.fromList [ ( "aaa", Ast.Int_ 1 ), ( "bbb", Ast.String_ "bbb" ), ( "ccc", Ast.Float_ 1.0 ) ]) , Test.test "a record with numbers and comments" <| \_ -> expectValue """ - aaa: 1# First - bbb: 2.0 # A comment - ccc: 3 # Another comment - ddd: 4.5 # - """ + aaa: 1# First + bbb: 2.0 # A comment + ccc: 3 # Another comment + ddd: 4.5 # + """ <| Ast.Record_ (Dict.fromList [ ( "aaa", Ast.Int_ 1 ), ( "bbb", Ast.Float_ 2.0 ), ( "ccc", Ast.Int_ 3 ), ( "ddd", Ast.Float_ 4.5 ) ]) , Test.test "a record on a single line" <| @@ -407,9 +432,9 @@ suite = \_ -> expectValue """ - aaa: '# a string' - bbb:# a comment - """ + aaa: '# a string' + bbb:# a comment + """ <| Ast.Record_ (Dict.fromList [ ( "aaa", Ast.String_ "# a string" ), ( "bbb", Ast.Null_ ) ]) , Test.test "trailing spaces after record values" <| @@ -542,21 +567,21 @@ suite = \_ -> expectErr """aaa: aaa -aaa: bbb""" + aaa: bbb""" , Test.test "a record with 2 duplicated keys" <| \_ -> expectErr """ - aaa: - key1: value1 - key1: value2 - """ + aaa: + key1: value1 + key1: value2 + """ , Test.test "an inline record with 2 duplicated keys, version 2" <| \_ -> expectErr """ - aaa: { key1: value1, key1: value2 } - """ + aaa: { key1: value1, key1: value2 } + """ -- TODO: This is temporarily removed because it is a valid test case that should pass -- , Test.test "weird colon record" <|