Skip to content

Commit afcb9d1

Browse files
committed
format: retain multiline string formatting
1 parent 601efae commit afcb9d1

File tree

9 files changed

+67
-14
lines changed

9 files changed

+67
-14
lines changed

compiler/src/AST/Source.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ type Expr = A.Located Expr_
6161

6262
data Expr_
6363
= Chr ES.String
64-
| Str ES.String
64+
| Str ES.String ES.StringFormat
6565
| Int Int GI.IntFormat
6666
| Float EF.Float
6767
| Var VarType Name

compiler/src/Canonicalize/Expression.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ canonicalize :: Env.Env -> Src.Expr -> Result FreeLocals [W.Warning] Can.Expr
5050
canonicalize env (A.At region expression) =
5151
A.At region
5252
<$> case expression of
53-
Src.Str string ->
53+
Src.Str string _ ->
5454
Result.ok (Can.Str string)
5555
Src.Chr char ->
5656
Result.ok (Can.Chr char)

compiler/src/Data/Utf8.hs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ module Data.Utf8
2323
putVeryLong,
2424
--
2525
toChars,
26+
toText,
2627
toBuilder,
2728
toEscapedBuilder,
2829
--
@@ -46,6 +47,7 @@ import Data.ByteString.Builder.Internal qualified as B
4647
import Data.ByteString.Internal qualified as B
4748
import Data.Char qualified as Char
4849
import Data.List qualified as List
50+
import Data.Text qualified as Text
4951
import Foreign.ForeignPtr (touchForeignPtr)
5052
import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
5153
import Foreign.Ptr (minusPtr, plusPtr)
@@ -330,6 +332,13 @@ word8ToInt# :: Word8# -> Int#
330332
word8ToInt# word8 =
331333
int8ToInt# (word8ToInt8# word8)
332334

335+
-- TO TEXT
336+
337+
toText :: Utf8 t -> Text.Text
338+
toText =
339+
-- This could most certainly be optimized for better performance
340+
Text.pack . toChars
341+
333342
-- TO BUILDER
334343

335344
toBuilder :: Utf8 t -> B.Builder

compiler/src/Gren/Format.hs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{-# LANGUAGE LambdaCase #-}
22
{-# LANGUAGE OverloadedLists #-}
3+
{-# LANGUAGE OverloadedStrings #-}
34
{-# LANGUAGE TypeApplications #-}
45
{-# OPTIONS_GHC -Werror=incomplete-patterns #-}
56
{-# OPTIONS_GHC -Wno-error=unused-matches #-}
@@ -21,8 +22,11 @@ import Data.Maybe (catMaybes, maybeToList)
2122
import Data.Maybe qualified as Maybe
2223
import Data.Name (Name)
2324
import Data.Semigroup (sconcat)
25+
import Data.Text qualified as Text
26+
import Data.Text.Encoding (encodeUtf8Builder)
2427
import Data.Utf8 qualified as Utf8
2528
import Gren.Int qualified as GI
29+
import Gren.String qualified as GS
2630
import Parse.Primitives qualified as P
2731
import Reporting.Annotation qualified as A
2832
import Text.PrettyPrint.Avh4.Block (Block)
@@ -556,9 +560,12 @@ formatExpr = \case
556560
Src.Chr char ->
557561
NoExpressionParens $
558562
formatString StringStyleChar char
559-
Src.Str string ->
563+
Src.Str string GS.SingleLineString ->
560564
NoExpressionParens $
561565
formatString StringStyleSingleQuoted string
566+
Src.Str string GS.MultilineString ->
567+
NoExpressionParens $
568+
formatString StringStyleTripleQuoted string
562569
Src.Int int intFormat ->
563570
NoExpressionParens $ formatInt intFormat int
564571
Src.Float float ->
@@ -1054,7 +1061,13 @@ formatString style str =
10541061
StringStyleSingleQuoted ->
10551062
stringBox (Block.char7 '"')
10561063
StringStyleTripleQuoted ->
1057-
stringBox (Block.string7 "\"\"\"")
1064+
Block.stack $
1065+
NonEmpty.fromList $
1066+
mconcat
1067+
[ [Block.line (Block.string7 "\"\"\"")],
1068+
fmap (Block.line . Block.lineFromBuilder . encodeUtf8Builder) $ Text.splitOn "\\n" $ (Utf8.toText str),
1069+
[Block.line (Block.string7 "\"\"\"")]
1070+
]
10581071
where
10591072
stringBox :: Block.Line -> Block
10601073
stringBox quotes =

compiler/src/Gren/String.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
module Gren.String
77
( String,
8+
StringFormat (..),
89
toChars,
910
fromChars,
1011
toBuilder,
@@ -31,6 +32,11 @@ type String =
3132

3233
data GREN_STRING
3334

35+
data StringFormat
36+
= SingleLineString
37+
| MultilineString
38+
deriving (Show)
39+
3440
-- HELPERS
3541

3642
toChars :: String -> [Char]

compiler/src/Parse/Expression.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ term =
4444
string :: A.Position -> Parser E.Expr Src.Expr
4545
string start =
4646
do
47-
str <- String.string E.Start E.String
48-
addEnd start (Src.Str str)
47+
(str, stringFormat) <- String.string E.Start E.String
48+
addEnd start (Src.Str str stringFormat)
4949

5050
character :: A.Position -> Parser E.Expr Src.Expr
5151
character start =

compiler/src/Parse/Pattern.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ termHelp start =
7373
let width = fromIntegral (Utf8.size float)
7474
in cerr row (col - width) (E.PFloat width),
7575
do
76-
str <- String.string E.PStart E.PString
76+
(str, _) <- String.string E.PStart E.PString
7777
addEnd start (Src.PStr str),
7878
do
7979
chr <- String.character E.PStart E.PChar

compiler/src/Parse/String.hs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ chompChar pos end row col numChars mostRecent =
7575

7676
-- STRINGS
7777

78-
string :: (Row -> Col -> x) -> (E.String -> Row -> Col -> x) -> Parser x ES.String
78+
string :: (Row -> Col -> x) -> (E.String -> Row -> Col -> x) -> Parser x (ES.String, ES.StringFormat)
7979
string toExpectation toError =
8080
P.Parser $ \(P.State src pos end indent row col) cok _ cerr eerr ->
8181
if isDoubleQuote pos end
@@ -89,12 +89,12 @@ string toExpectation toError =
8989
let !pos3 = plusPtr pos 3
9090
!col3 = col + 3
9191
in multiString pos3 end row col3 pos3 row col
92-
else Ok pos2 row (col + 2) Utf8.empty
92+
else Ok pos2 row (col + 2) ES.SingleLineString Utf8.empty
9393
else singleString pos1 end row (col + 1) pos1 mempty of
94-
Ok newPos newRow newCol utf8 ->
94+
Ok newPos newRow newCol stringFormat utf8 ->
9595
let !newState =
9696
P.State src newPos end indent newRow newCol
97-
in cok utf8 newState
97+
in cok (utf8, stringFormat) newState
9898
Err r c x ->
9999
cerr r c (toError x)
100100
else eerr row col toExpectation
@@ -104,7 +104,7 @@ isDoubleQuote pos end =
104104
pos < end && P.unsafeIndex pos == 0x22 {- " -}
105105

106106
data StringResult
107-
= Ok (Ptr Word8) Row Col !ES.String
107+
= Ok (Ptr Word8) Row Col ES.StringFormat !ES.String
108108
| Err Row Col E.String
109109

110110
finalize :: Ptr Word8 -> Ptr Word8 -> [ES.Chunk] -> ES.String
@@ -139,7 +139,7 @@ singleString pos end row col initialPos revChunks =
139139
let !word = P.unsafeIndex pos
140140
in if word == 0x22 {- " -}
141141
then
142-
Ok (plusPtr pos 1) row (col + 1) $
142+
Ok (plusPtr pos 1) row (col + 1) ES.SingleLineString $
143143
finalize initialPos pos revChunks
144144
else
145145
if word == 0x0A {- \n -}
@@ -213,7 +213,7 @@ multiStringBody leadingWhitespace pos end row col initialPos sr sc revChunks =
213213
let !word = P.unsafeIndex pos
214214
in if word == 0x22 {- " -} && isDoubleQuote (plusPtr pos 1) end && isDoubleQuote (plusPtr pos 2) end
215215
then
216-
Ok (plusPtr pos 3) row (col + 3) $
216+
Ok (plusPtr pos 3) row (col + 3) ES.MultilineString $
217217
finalize initialPos pos $
218218
dropMultiStringEndingNewline revChunks
219219
else

tests/Integration/FormatSpec.hs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,31 @@ spec = do
347347
]
348348

349349
describe "expressions" $ do
350+
describe "string literals" $ do
351+
it "formats strings" $
352+
assertFormattedExpression
353+
["a"]
354+
it "formats multiline strings with trimmed whitespace" $
355+
assertFormattedModuleBody
356+
[ "str =",
357+
" \"\"\"",
358+
" # String",
359+
" - indented more",
360+
" \"\"\""
361+
]
362+
it "formats multiline strings" $
363+
[ "str = \"\"\"",
364+
" 1",
365+
" 2",
366+
"\"\"\""
367+
]
368+
`shouldFormatModuleBodyAs` [ "str =",
369+
" \"\"\"",
370+
" 1",
371+
" 2",
372+
" \"\"\""
373+
]
374+
350375
describe "int literals" $ do
351376
it "formats decimal integers" $
352377
["234"] `shouldFormatExpressionAs` ["234"]

0 commit comments

Comments
 (0)