Skip to content

Commit 05edc9b

Browse files
committed
Implement string parser. Unicode values with surrogate pairs seems to cause it to fail
1 parent 6e419cc commit 05edc9b

File tree

2 files changed

+89
-53
lines changed

2 files changed

+89
-53
lines changed

src/Parse/String.gren

Lines changed: 81 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module Parse.String exposing
22
( Error (..)
33
, char
4+
, string
45
)
56

67

@@ -21,67 +22,94 @@ char : Parser c Error Char
2122
char =
2223
Parser.succeed identity
2324
|> Parser.skip (Parser.symbol charQuote)
24-
|> Parser.keep
25-
(Parser.oneOf
26-
[ Parser.chompIf (\c -> c == '\\') ExpectedChar
27-
|> Parser.andThen
28-
(\_ ->
29-
Parser.oneOf
30-
[ Parser.chompIf (\c -> c == 'n') ExpectedChar
31-
|> Parser.map (\_ -> '\n')
32-
, Parser.chompIf (\c -> c == 'r') ExpectedChar
33-
|> Parser.map (\_ -> '\r')
34-
, Parser.chompIf (\c -> c == 't') ExpectedChar
35-
|> Parser.map (\_ -> '\t')
36-
, Parser.chompIf (\c -> c == '\\') ExpectedChar
37-
|> Parser.map (\_ -> '\\')
38-
, Parser.chompIf (\c -> c == '\'') ExpectedChar
39-
|> Parser.map (\_ -> '\'')
40-
, Parser.chompIf (\c -> c == '\"') ExpectedChar
41-
|> Parser.map (\_ -> '\"')
42-
, Parser.succeed identity
43-
|> Parser.skip (Parser.symbol unicodeOpening)
44-
|> Parser.keep (Number.hexParser ExpectedValidUnicode)
45-
|> Parser.skip (Parser.chompIf (\c -> c == '}') ExpectedUnicodeClosing)
46-
|> Parser.andThen
47-
(\num ->
48-
let
49-
character =
50-
Char.fromCode num
51-
in
52-
-- Check if char is valid (replacement character)
53-
if character == '\u{FFFD}' then
54-
Parser.problem ExpectedValidUnicode
55-
56-
else
57-
Parser.succeed character
58-
)
59-
, Parser.chompIf (\_ -> True) ExpectedChar
60-
|> Parser.getChompedString
61-
|> Parser.andThen (Parser.problem << ExpectedEscapeChar)
62-
]
63-
)
64-
, Parser.chompIf (\_ -> True) ExpectedChar
65-
|> Parser.getChompedString
66-
|> Parser.andThen
67-
(\str ->
68-
when String.popFirst str is
69-
Nothing ->
70-
Parser.problem ExpectedChar
71-
72-
Just { first = c } ->
73-
Parser.succeed c
74-
)
75-
]
76-
)
25+
|> Parser.keep coreParser
7726
|> Parser.skip (Parser.symbol charQuote)
7827

7928

29+
coreParser : Parser c Error Char
30+
coreParser =
31+
Parser.oneOf
32+
[ Parser.chompIf (\c -> c == '\\') ExpectedChar
33+
|> Parser.andThen
34+
(\_ ->
35+
Parser.oneOf
36+
[ Parser.chompIf (\c -> c == 'n') ExpectedChar
37+
|> Parser.map (\_ -> '\n')
38+
, Parser.chompIf (\c -> c == 'r') ExpectedChar
39+
|> Parser.map (\_ -> '\r')
40+
, Parser.chompIf (\c -> c == 't') ExpectedChar
41+
|> Parser.map (\_ -> '\t')
42+
, Parser.chompIf (\c -> c == '\\') ExpectedChar
43+
|> Parser.map (\_ -> '\\')
44+
, Parser.chompIf (\c -> c == '\'') ExpectedChar
45+
|> Parser.map (\_ -> '\'')
46+
, Parser.chompIf (\c -> c == '\"') ExpectedChar
47+
|> Parser.map (\_ -> '\"')
48+
, Parser.succeed identity
49+
|> Parser.skip (Parser.symbol unicodeOpening)
50+
|> Parser.keep (Number.hexParser ExpectedValidUnicode)
51+
|> Parser.skip (Parser.chompIf (\c -> c == '}') ExpectedUnicodeClosing)
52+
|> Parser.andThen
53+
(\num ->
54+
let
55+
character =
56+
Char.fromCode num
57+
in
58+
-- Check if char is valid (replacement character)
59+
if character == '\u{FFFD}' then
60+
Parser.problem ExpectedValidUnicode
61+
62+
else
63+
Parser.succeed character
64+
)
65+
, Parser.chompIf (\_ -> True) ExpectedChar
66+
|> Parser.getChompedString
67+
|> Parser.andThen (Parser.problem << ExpectedEscapeChar)
68+
]
69+
)
70+
, Parser.chompIf (\_ -> True) ExpectedChar
71+
|> Parser.getChompedString
72+
|> Parser.andThen
73+
(\str ->
74+
when String.popFirst str is
75+
Nothing ->
76+
Parser.problem ExpectedChar
77+
78+
Just { first = c } ->
79+
Parser.succeed c
80+
)
81+
]
82+
83+
8084
charQuote : Parser.Token Error
8185
charQuote =
8286
Parser.Token { str = "\'", expecting = ExpectedQuote }
8387

8488

89+
strQuote : Parser.Token Error
90+
strQuote =
91+
Parser.Token { str = "\"", expecting = ExpectedQuote }
92+
93+
8594
unicodeOpening : Parser.Token Error
8695
unicodeOpening =
8796
Parser.Token { str = "u{", expecting = ExpectedUnicodeOpening }
97+
98+
99+
100+
string : Parser c Error String
101+
string =
102+
Parser.succeed identity
103+
|> Parser.skip (Parser.symbol strQuote)
104+
|> Parser.keep (Parser.loop "" stringHelp)
105+
106+
107+
stringHelp : String -> Parser c Error (Parser.Step String String)
108+
stringHelp str =
109+
Parser.oneOf
110+
[ Parser.succeed {}
111+
|> Parser.skip (Parser.symbol strQuote)
112+
|> Parser.map (\_ -> Parser.Done str)
113+
, Parser.succeed (\chr -> Parser.Loop (String.pushLast chr str))
114+
|> Parser.keep coreParser
115+
]

tests/src/Test/Parse/String.gren

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ tests =
5656
Parser.run PS.char "\'\\a\'"
5757
|> expectCharErr (PS.ExpectedEscapeChar "a")
5858
]
59+
, describe "Strings"
60+
[ test "Example" <| \_ ->
61+
Parser.run PS.string "\"this is a \\\" Test -String_\""
62+
|> Expect.equal (Ok "this is a \" Test -String_")
63+
, test "Example with surrogate pair" <| \_ ->
64+
Parser.run PS.string "\"this is a \\\" Test 𤭢 -String_\""
65+
|> Expect.equal (Ok "this is a \" Test 𤭢 -String_")
66+
]
5967
]
6068

6169

0 commit comments

Comments
 (0)