-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace HsSrcExts
backend with own Preprocessor
backend
#231
Comments
It sounds like we will design our AST to use a type family to determine the types of annotations to different parts of the AST for different stages/passes of the translation, similar to the technique described in Trees that Grow. One generally writes a formatter that supports all stages/passes, so that it can be used to format error messages in intermediate stages as well as the final code. I am not yet sure what is best in our case, however, as I do not think we have a concrete plan for the translation passes (documented) yet. When we got to this, here are some things to consider:
|
We need to decide what to do about formatting rules ("style"). We could provide options that allows users to tweak the style according to their tastes, but doing so would make the formatting implementation more complicated. We could support different styles by name, which would allow users to select the style that they dislike least. How important is this? Perhaps we do not need to worry about style options so much? Perhaps users who use/prefer existing formatters can simply run their preferred formatter on the generated code? Based on what I know at this time, I think it might be preferable to create a single style with no options. That would be the easiest to maintain as we implement features during initial development. We can organize the code to allow for other styles (perhaps with options) that may be implemented in the future. If we do this, we need to pick a style. We could render the same style that we are writing |
Should we take character widths into account when formatting code? In particular, the widths of characters determine how code is formatted when using a maximum line length. With Unicode text, the maximum line length is generally specified in columns/cells, not characters. For example, identifiers in Chinese may result in lines that are well over 80 columns even when there are fewer than 80 characters per line. When comments are aligned alongside code, ignoring differences in character width often results in misalignment. We will not have to worry about this if we put all comments on separate lines. Note that character width is not specified as a Unicode property, as fonts have leeway. (For example, the reference mark ( Perhaps we do not want to worry about such details now but may revisit them in the future. In that case, we can use a function that gets the width of text with an initial implementation that just returns the number of characters, which can later be changed. The function should be used consistently, avoiding counting characters anywhere else in the code. |
I have been working on a pretty printer for a few days without communication, so I should probably post an update! The This library does not seem to provide enough flexibility to format code very well. In particular, it does not provide a way to specify different possible layouts that code may be written, depending on how it fits within the specified line length. For example, consider a function call with three arguments ( I have been working on an alternative that tries to keep the simplicity of Another issue that the alternative addresses is being able to format documentation. To format Haskell-style documentation, we need to know the current indentation and the maximum line length. The If interested, here is an overview of the current design: data Options = Options { ... }
defaultOptions :: Options
data Content = ... | ...
renderContent :: Options -> Content -> String
-- defined here so base is only dependency
newtype Reader ctx a = Reader { unReader :: ctx -> a }
data Context = Context { ... }
mkContext :: Options -> Context
newtype Doc = Doc { unDoc :: Reader Context Content }
... API for constructing and rendering 'Doc's
class Pretty a where
pretty :: a -> Doc
prettyPrec :: Int -> a -> Doc
render :: Pretty a => Options -> a -> String
render_ :: Pretty a => a -> String The I think that the idea is sound, but I have found that it is pretty difficult to debug, which could be frustrating as we change and add new things to our AST. I implemented some debug tracing that helps, though the huge amount of output can be difficult to grok. For example, I am currently debugging a strange issue where some code uses In the call on Thursday, I mentioned that I hope to implement a "lightweight" solution like |
Based on discussion in the chat, it sounds like an initial version does not need to have very pretty output. An initial simple solution can suffice, and we can implement a better pretty-printer in the future if it is needed. I implemented a wrapper around the -- | Create a document with rendered lines
--
-- The function is passed the maximum width of each line, computed as the
-- maximum line length minus the current indentation. It must return a list
-- of lines, using an empty string to represent a blank line. None of the
-- strings may contain newline characters.
--
-- The lines are /automatically/ indented according to the current indentation.
renderedLines :: (Int -> [String]) -> CtxDoc I implemented the If we would like to have better indentation, however, we should either switch to a different underlying library or write our own. Example 1File: module Demo where
data CS1 = CS1
instance Foreign.Storable.Storable CS1 where
Foreign.Storable.sizeOf = \_ -> 8
Foreign.Storable.alignment = \_ -> 4
Foreign.Storable.peek =
\x0 ->
pure MkCS1 <*> Foreign.Storable.peekByteOff x0 0
<*> Foreign.Storable.peekByteOff x0 32
Foreign.Storable.poke =
\x0 ->
\x1 ->
case x1 of
MkCS1 cS1_a2 cS1_b3 ->
Foreign.Storable.pokeByteOff x0 0 cS1_a2
>> Foreign.Storable.pokeByteOff x0 32 cS1_b3
data CS2 = CS2
instance Foreign.Storable.Storable CS2 where
Foreign.Storable.sizeOf = \_ -> 12
Foreign.Storable.alignment = \_ -> 4
Foreign.Storable.peek =
\x0 ->
pure MkCS2 <*> Foreign.Storable.peekByteOff x0 0
<*> Foreign.Storable.peekByteOff x0 32
<*> Foreign.Storable.peekByteOff x0 64
Foreign.Storable.poke =
\x0 ->
\x1 ->
case x1 of
MkCS2 cS2_a2 cS2_b3 cS2_c4 ->
Foreign.Storable.pokeByteOff x0 0 cS2_a2
>> Foreign.Storable.pokeByteOff x0 32 cS2_b3
>> Foreign.Storable.pokeByteOff x0 64 cS2_c4
data CX = CX
instance Foreign.Storable.Storable CX where
Foreign.Storable.sizeOf = \_ -> 1
Foreign.Storable.alignment = \_ -> 1
Foreign.Storable.peek =
\x0 ->
pure MkCX <*> Foreign.Storable.peekByteOff x0 0
Foreign.Storable.poke =
\x0 ->
\x1 ->
case x1 of
MkCX cX_a2 -> Foreign.Storable.pokeByteOff x0 0 cX_a2
data CS4 = CS4
instance Foreign.Storable.Storable CS4 where
Foreign.Storable.sizeOf = \_ -> 8
Foreign.Storable.alignment = \_ -> 4
Foreign.Storable.peek =
\x0 ->
pure MkCS4 <*> Foreign.Storable.peekByteOff x0 0
<*> Foreign.Storable.peekByteOff x0 32
Foreign.Storable.poke =
\x0 ->
\x1 ->
case x1 of
MkCS4 cS4_b2 cS4_a3 ->
Foreign.Storable.pokeByteOff x0 0 cS4_b2
>> Foreign.Storable.pokeByteOff x0 32 cS4_a3 Example 2File: module Demo where
data CPrimitive = CPrimitive
instance Foreign.Storable.Storable CPrimitive where
Foreign.Storable.sizeOf = \_ -> 176
Foreign.Storable.alignment = \_ -> 16
Foreign.Storable.peek =
\x0 ->
pure MkCPrimitive
<*> Foreign.Storable.peekByteOff x0 0
<*> Foreign.Storable.peekByteOff x0 8
<*> Foreign.Storable.peekByteOff x0 16
<*> Foreign.Storable.peekByteOff x0 32
<*> Foreign.Storable.peekByteOff x0 48
<*> Foreign.Storable.peekByteOff x0 64
<*> Foreign.Storable.peekByteOff x0 80
<*> Foreign.Storable.peekByteOff x0 96
<*> Foreign.Storable.peekByteOff x0 112
<*> Foreign.Storable.peekByteOff x0 128
<*> Foreign.Storable.peekByteOff x0 160
<*> Foreign.Storable.peekByteOff x0 192
<*> Foreign.Storable.peekByteOff x0 224
<*> Foreign.Storable.peekByteOff x0 256
<*> Foreign.Storable.peekByteOff x0 320
<*> Foreign.Storable.peekByteOff x0 384
<*> Foreign.Storable.peekByteOff x0 448
<*> Foreign.Storable.peekByteOff x0 512
<*> Foreign.Storable.peekByteOff x0 576
<*> Foreign.Storable.peekByteOff x0 640
<*> Foreign.Storable.peekByteOff x0 704
<*> Foreign.Storable.peekByteOff x0 768
<*> Foreign.Storable.peekByteOff x0 832
<*> Foreign.Storable.peekByteOff x0 896
<*> Foreign.Storable.peekByteOff x0 960
<*> Foreign.Storable.peekByteOff x0 1024
<*> Foreign.Storable.peekByteOff x0 1088
<*> Foreign.Storable.peekByteOff x0 1152
<*> Foreign.Storable.peekByteOff x0 1280
Foreign.Storable.poke =
\x0 ->
\x1 ->
case x1 of
MkCPrimitive cPrimitive_c2 cPrimitive_sc3 cPrimitive_uc4 cPrimitive_s5 cPrimitive_si6 cPrimitive_ss7 cPrimitive_ssi8 cPrimitive_us9 cPrimitive_usi10 cPrimitive_i11 cPrimitive_s212 cPrimitive_si213 cPrimitive_u14 cPrimitive_ui15 cPrimitive_l16 cPrimitive_li17 cPrimitive_sl18 cPrimitive_sli19 cPrimitive_ul20 cPrimitive_uli21 cPrimitive_ll22 cPrimitive_lli23 cPrimitive_sll24 cPrimitive_slli25 cPrimitive_ull26 cPrimitive_ulli27 cPrimitive_f28 cPrimitive_d29 cPrimitive_ld30 ->
Foreign.Storable.pokeByteOff x0 0 cPrimitive_c2
>> Foreign.Storable.pokeByteOff x0 8 cPrimitive_sc3
>> Foreign.Storable.pokeByteOff x0 16 cPrimitive_uc4
>> Foreign.Storable.pokeByteOff x0 32 cPrimitive_s5
>> Foreign.Storable.pokeByteOff x0 48 cPrimitive_si6
>> Foreign.Storable.pokeByteOff x0 64 cPrimitive_ss7
>> Foreign.Storable.pokeByteOff x0 80 cPrimitive_ssi8
>> Foreign.Storable.pokeByteOff x0 96 cPrimitive_us9
>> Foreign.Storable.pokeByteOff x0 112 cPrimitive_usi10
>> Foreign.Storable.pokeByteOff x0 128 cPrimitive_i11
>> Foreign.Storable.pokeByteOff x0 160 cPrimitive_s212
>> Foreign.Storable.pokeByteOff x0 192 cPrimitive_si213
>> Foreign.Storable.pokeByteOff x0 224 cPrimitive_u14
>> Foreign.Storable.pokeByteOff x0 256 cPrimitive_ui15
>> Foreign.Storable.pokeByteOff x0 320 cPrimitive_l16
>> Foreign.Storable.pokeByteOff x0 384 cPrimitive_li17
>> Foreign.Storable.pokeByteOff x0 448 cPrimitive_sl18
>> Foreign.Storable.pokeByteOff x0 512 cPrimitive_sli19
>> Foreign.Storable.pokeByteOff x0 576 cPrimitive_ul20
>> Foreign.Storable.pokeByteOff x0 640 cPrimitive_uli21
>> Foreign.Storable.pokeByteOff x0 704 cPrimitive_ll22
>> Foreign.Storable.pokeByteOff x0 768 cPrimitive_lli23
>> Foreign.Storable.pokeByteOff x0 832 cPrimitive_sll24
>> Foreign.Storable.pokeByteOff x0 896 cPrimitive_slli25
>> Foreign.Storable.pokeByteOff x0 960 cPrimitive_ull26
>> Foreign.Storable.pokeByteOff x0 1024 cPrimitive_ulli27
>> Foreign.Storable.pokeByteOff x0 1088 cPrimitive_f28
>> Foreign.Storable.pokeByteOff x0 1152 cPrimitive_d29
>> Foreign.Storable.pokeByteOff x0 1280 cPrimitive_ld30 Please note that I have not pushed yet. There are some tasks that I need to finish before pushing, such as cleaning up my test code and determining ( |
I improved the rendering of long Examplemodule Demo where
data CPrimitive = MkCPrimitive
{ cPrimitive_c :: Foreign.C.CChar
, cPrimitive_sc :: Foreign.C.CSChar
, cPrimitive_uc :: Foreign.C.CSChar
, cPrimitive_s :: Foreign.C.CShort
, cPrimitive_si :: Foreign.C.CShort
, cPrimitive_ss :: Foreign.C.CShort
, cPrimitive_ssi :: Foreign.C.CShort
, cPrimitive_us :: Foreign.C.CUShort
, cPrimitive_usi :: Foreign.C.CUShort
, cPrimitive_i :: Foreign.C.CInt
, cPrimitive_s2 :: Foreign.C.CInt
, cPrimitive_si2 :: Foreign.C.CInt
, cPrimitive_u :: Foreign.C.CUInt
, cPrimitive_ui :: Foreign.C.CUInt
, cPrimitive_l :: Foreign.C.CLong
, cPrimitive_li :: Foreign.C.CLong
, cPrimitive_sl :: Foreign.C.CLong
, cPrimitive_sli :: Foreign.C.CLong
, cPrimitive_ul :: Foreign.C.CULong
, cPrimitive_uli :: Foreign.C.CULong
, cPrimitive_ll :: Foreign.C.CLLong
, cPrimitive_lli :: Foreign.C.CLLong
, cPrimitive_sll :: Foreign.C.CLLong
, cPrimitive_slli :: Foreign.C.CLLong
, cPrimitive_ull :: Foreign.C.CULLong
, cPrimitive_ulli :: Foreign.C.CULLong
, cPrimitive_f :: Foreign.C.CFloat
, cPrimitive_d :: Foreign.C.CDouble
, cPrimitive_ld :: Foreign.C.CDouble
}
instance Foreign.Storable CPrimitive where
Foreign.sizeOf = \_ -> 176
Foreign.alignment = \_ -> 16
Foreign.peek =
\x0 ->
pure MkCPrimitive <*> Foreign.peekByteOff x0 0
<*> Foreign.peekByteOff x0 8
<*> Foreign.peekByteOff x0 16
<*> Foreign.peekByteOff x0 32
<*> Foreign.peekByteOff x0 48
<*> Foreign.peekByteOff x0 64
<*> Foreign.peekByteOff x0 80
<*> Foreign.peekByteOff x0 96
<*> Foreign.peekByteOff x0 112
<*> Foreign.peekByteOff x0 128
<*> Foreign.peekByteOff x0 160
<*> Foreign.peekByteOff x0 192
<*> Foreign.peekByteOff x0 224
<*> Foreign.peekByteOff x0 256
<*> Foreign.peekByteOff x0 320
<*> Foreign.peekByteOff x0 384
<*> Foreign.peekByteOff x0 448
<*> Foreign.peekByteOff x0 512
<*> Foreign.peekByteOff x0 576
<*> Foreign.peekByteOff x0 640
<*> Foreign.peekByteOff x0 704
<*> Foreign.peekByteOff x0 768
<*> Foreign.peekByteOff x0 832
<*> Foreign.peekByteOff x0 896
<*> Foreign.peekByteOff x0 960
<*> Foreign.peekByteOff x0 1024
<*> Foreign.peekByteOff x0 1088
<*> Foreign.peekByteOff x0 1152
<*> Foreign.peekByteOff x0 1280
Foreign.poke =
\x0 ->
\x1 ->
case x1 of
MkCPrimitive
cPrimitive_c2
cPrimitive_sc3
cPrimitive_uc4
cPrimitive_s5
cPrimitive_si6
cPrimitive_ss7
cPrimitive_ssi8
cPrimitive_us9
cPrimitive_usi10
cPrimitive_i11
cPrimitive_s212
cPrimitive_si213
cPrimitive_u14
cPrimitive_ui15
cPrimitive_l16
cPrimitive_li17
cPrimitive_sl18
cPrimitive_sli19
cPrimitive_ul20
cPrimitive_uli21
cPrimitive_ll22
cPrimitive_lli23
cPrimitive_sll24
cPrimitive_slli25
cPrimitive_ull26
cPrimitive_ulli27
cPrimitive_f28
cPrimitive_d29
cPrimitive_ld30 ->
Foreign.pokeByteOff x0 0 cPrimitive_c2
>> Foreign.pokeByteOff x0 8 cPrimitive_sc3
>> Foreign.pokeByteOff x0 16 cPrimitive_uc4
>> Foreign.pokeByteOff x0 32 cPrimitive_s5
>> Foreign.pokeByteOff x0 48 cPrimitive_si6
>> Foreign.pokeByteOff x0 64 cPrimitive_ss7
>> Foreign.pokeByteOff x0 80 cPrimitive_ssi8
>> Foreign.pokeByteOff x0 96 cPrimitive_us9
>> Foreign.pokeByteOff x0 112 cPrimitive_usi10
>> Foreign.pokeByteOff x0 128 cPrimitive_i11
>> Foreign.pokeByteOff x0 160 cPrimitive_s212
>> Foreign.pokeByteOff x0 192 cPrimitive_si213
>> Foreign.pokeByteOff x0 224 cPrimitive_u14
>> Foreign.pokeByteOff x0 256 cPrimitive_ui15
>> Foreign.pokeByteOff x0 320 cPrimitive_l16
>> Foreign.pokeByteOff x0 384 cPrimitive_li17
>> Foreign.pokeByteOff x0 448 cPrimitive_sl18
>> Foreign.pokeByteOff x0 512 cPrimitive_sli19
>> Foreign.pokeByteOff x0 576 cPrimitive_ul20
>> Foreign.pokeByteOff x0 640 cPrimitive_uli21
>> Foreign.pokeByteOff x0 704 cPrimitive_ll22
>> Foreign.pokeByteOff x0 768 cPrimitive_lli23
>> Foreign.pokeByteOff x0 832 cPrimitive_sll24
>> Foreign.pokeByteOff x0 896 cPrimitive_slli25
>> Foreign.pokeByteOff x0 960 cPrimitive_ull26
>> Foreign.pokeByteOff x0 1024 cPrimitive_ulli27
>> Foreign.pokeByteOff x0 1088 cPrimitive_f28
>> Foreign.pokeByteOff x0 1152 cPrimitive_d29
>> Foreign.pokeByteOff x0 1280 cPrimitive_ld30 Since I do not think it is a priority, I have not implemented proper length calculation that handles Unicode elegantly. I just count characters ( Note that I make use of |
Thank you @phadej for pointing out precedence issues with the preprocessor pretty-printer. The current pretty-printer implementation assumes that we create the AST with precedence in mind. Like using parentheses when writing code by hand, an Experimenting with this today, I changed the pretty-printer to aggressively parenthesize (infix) expressions. This should ensure that the code is parsed as desired, at the expense of readability. In the current state, long lines are back, and there are lots of parentheses. Examplemodule Demo where
data CPrimitive = MkCPrimitive
{ cPrimitive_c :: Foreign.C.CChar
, cPrimitive_sc :: Foreign.C.CSChar
, cPrimitive_uc :: Foreign.C.CSChar
, cPrimitive_s :: Foreign.C.CShort
, cPrimitive_si :: Foreign.C.CShort
, cPrimitive_ss :: Foreign.C.CShort
, cPrimitive_ssi :: Foreign.C.CShort
, cPrimitive_us :: Foreign.C.CUShort
, cPrimitive_usi :: Foreign.C.CUShort
, cPrimitive_i :: Foreign.C.CInt
, cPrimitive_s2 :: Foreign.C.CInt
, cPrimitive_si2 :: Foreign.C.CInt
, cPrimitive_u :: Foreign.C.CUInt
, cPrimitive_ui :: Foreign.C.CUInt
, cPrimitive_l :: Foreign.C.CLong
, cPrimitive_li :: Foreign.C.CLong
, cPrimitive_sl :: Foreign.C.CLong
, cPrimitive_sli :: Foreign.C.CLong
, cPrimitive_ul :: Foreign.C.CULong
, cPrimitive_uli :: Foreign.C.CULong
, cPrimitive_ll :: Foreign.C.CLLong
, cPrimitive_lli :: Foreign.C.CLLong
, cPrimitive_sll :: Foreign.C.CLLong
, cPrimitive_slli :: Foreign.C.CLLong
, cPrimitive_ull :: Foreign.C.CULLong
, cPrimitive_ulli :: Foreign.C.CULLong
, cPrimitive_f :: Foreign.C.CFloat
, cPrimitive_d :: Foreign.C.CDouble
, cPrimitive_ld :: Foreign.C.CDouble
}
instance Foreign.Storable CPrimitive where
Foreign.sizeOf = \_ -> 176
Foreign.alignment = \_ -> 16
Foreign.peek =
\x0 ->
((((((((((((((((((((((((((((pure MkCPrimitive <*> Foreign.peekByteOff x0 0) <*> Foreign.peekByteOff x0 8) <*> Foreign.peekByteOff x0 16) <*> Foreign.peekByteOff x0 32) <*> Foreign.peekByteOff x0 48) <*> Foreign.peekByteOff x0 64) <*> Foreign.peekByteOff x0 80) <*> Foreign.peekByteOff x0 96) <*> Foreign.peekByteOff x0 112) <*> Foreign.peekByteOff x0 128) <*> Foreign.peekByteOff x0 160) <*> Foreign.peekByteOff x0 192) <*> Foreign.peekByteOff x0 224) <*> Foreign.peekByteOff x0 256) <*> Foreign.peekByteOff x0 320) <*> Foreign.peekByteOff x0 384) <*> Foreign.peekByteOff x0 448) <*> Foreign.peekByteOff x0 512) <*> Foreign.peekByteOff x0 576) <*> Foreign.peekByteOff x0 640) <*> Foreign.peekByteOff x0 704) <*> Foreign.peekByteOff x0 768) <*> Foreign.peekByteOff x0 832) <*> Foreign.peekByteOff x0 896) <*> Foreign.peekByteOff x0 960) <*> Foreign.peekByteOff x0 1024) <*> Foreign.peekByteOff x0 1088) <*> Foreign.peekByteOff x0 1152) <*> Foreign.peekByteOff x0 1280
Foreign.poke =
\x0 ->
\x1 ->
case x1 of
MkCPrimitive
cPrimitive_c2
cPrimitive_sc3
cPrimitive_uc4
cPrimitive_s5
cPrimitive_si6
cPrimitive_ss7
cPrimitive_ssi8
cPrimitive_us9
cPrimitive_usi10
cPrimitive_i11
cPrimitive_s212
cPrimitive_si213
cPrimitive_u14
cPrimitive_ui15
cPrimitive_l16
cPrimitive_li17
cPrimitive_sl18
cPrimitive_sli19
cPrimitive_ul20
cPrimitive_uli21
cPrimitive_ll22
cPrimitive_lli23
cPrimitive_sll24
cPrimitive_slli25
cPrimitive_ull26
cPrimitive_ulli27
cPrimitive_f28
cPrimitive_d29
cPrimitive_ld30 ->
Foreign.pokeByteOff x0 0 cPrimitive_c2 >> (Foreign.pokeByteOff x0 8 cPrimitive_sc3 >> (Foreign.pokeByteOff x0 16 cPrimitive_uc4 >> (Foreign.pokeByteOff x0 32 cPrimitive_s5 >> (Foreign.pokeByteOff x0 48 cPrimitive_si6 >> (Foreign.pokeByteOff x0 64 cPrimitive_ss7 >> (Foreign.pokeByteOff x0 80 cPrimitive_ssi8 >> (Foreign.pokeByteOff x0 96 cPrimitive_us9 >> (Foreign.pokeByteOff x0 112 cPrimitive_usi10 >> (Foreign.pokeByteOff x0 128 cPrimitive_i11 >> (Foreign.pokeByteOff x0 160 cPrimitive_s212 >> (Foreign.pokeByteOff x0 192 cPrimitive_si213 >> (Foreign.pokeByteOff x0 224 cPrimitive_u14 >> (Foreign.pokeByteOff x0 256 cPrimitive_ui15 >> (Foreign.pokeByteOff x0 320 cPrimitive_l16 >> (Foreign.pokeByteOff x0 384 cPrimitive_li17 >> (Foreign.pokeByteOff x0 448 cPrimitive_sl18 >> (Foreign.pokeByteOff x0 512 cPrimitive_sli19 >> (Foreign.pokeByteOff x0 576 cPrimitive_ul20 >> (Foreign.pokeByteOff x0 640 cPrimitive_uli21 >> (Foreign.pokeByteOff x0 704 cPrimitive_ll22 >> (Foreign.pokeByteOff x0 768 cPrimitive_lli23 >> (Foreign.pokeByteOff x0 832 cPrimitive_sll24 >> (Foreign.pokeByteOff x0 896 cPrimitive_slli25 >> (Foreign.pokeByteOff x0 960 cPrimitive_ull26 >> (Foreign.pokeByteOff x0 1024 cPrimitive_ulli27 >> (Foreign.pokeByteOff x0 1088 cPrimitive_f28 >> (Foreign.pokeByteOff x0 1152 cPrimitive_d29 >> Foreign.pokeByteOff x0 1280 cPrimitive_ld30))))))))))))))))))))))))))) While ormolu is not the paragon of style, IMHO, I tried formatting the above example output with it. I was surprised that it does not change either of the long chains of infix operators, keeping the ~1,000 character lines. Our functions/operators are represented using For now, I decided to go ahead and commit the aggressive version, since even ormolu does not clean such chains. If we would like to produce readable code, then perhaps a better approach is to avoid long infix chains.
|
I went ahead and implemented imports in the new preprocessor, so that I can compile generated modules to test them. Note that I use On my first test, I got errors like the following: Demo.hs:43:3: error:
Qualified name in binding position: Foreign.sizeOf
|
43 | Foreign.sizeOf = \_ -> 176
| ^^^^^^^^^^^^^^ We need to qualify such function names in general, but we cannot qualify them in instance definitions. I will fix this next. |
With an improved version of |
I replaced the I tried the examples as follows:
Here are the current results. The basics such as
|
Replace `HsSrcExts` backend with `PP` backend (#231)
Closed in #255. |
We have decided to stop using the
haskell-src-exts
package. We have already started using our own AST representation, sincehaskell-src-exts
is missing some needed features. We currently usehaskell-src-exts
to render the source code when in preprocessor mode, but we found that we have little control over how the code is formatted. For example,Pretty
output does not support documentation, and whilehaskell-src-exts-sc
could work for us, it would require implementing our own pretty-printer (fork ofPretty
). (See #26 (comment) for details.) At that point, we may as well implement a pretty-printer for our own AST that supports documentation, as that would likely be much easier to maintain in the long run.Note that we only have to pretty-print the code that we generate (a subset of Haskell syntax), not develop a pretty-printer that handles all cases. We do not have to parse Haskell code.
Here are some other options that we considered:
ghc-exactprint
is an option. It uses GHC types, however, and supporting a range of GHC versions would require a lot of maintenance.Here are some code formatters for reference/inspiration/discouragement:
ormolu
andfourmolu
useghc-lib-parser
brittany
(unmaintained) usesghc-exactprint
hindent
usesghc-lib-parser
hfmt
(unmaintained) useshaskell-src-exts
haskell-formatter
(deprecated) useshaskell-src-exts
stylish-haskell
(which only formats some things, not the whole source) usesghc-lib-parser
orghc
types, depending on build flags and the GHC versionNote that the maintained code formatters avoid
haskell-src-exts
due to various issues.The text was updated successfully, but these errors were encountered: