File size: 6,030 Bytes
a10b189
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}

{-|
Module      : Assertica.Backend.Emit
Description : Emit syntactically valid Haskell source code
Copyright   : (c) 2026 Ahmad Ali Parr
License     : BSL-1.0

Converts compiled intermediate representations (from CodeGen, TermCompiler, etc.)
into syntactically valid Haskell 2010 source code that can be processed by GHC.

RESPONSIBILITIES:

1. **Module Headers**: Generate correct module declaration with exports
2. **Imports**: Produce valid import statements with proper syntax
3. **Definitions**: Format term and type definitions with correct syntax
4. **Type Signatures**: Generate type declarations with proper indentation
5. **Comments**: Add source location hints and documentation
6. **Pretty-Printing**: Consistent, readable formatting

HASKELL SYNTAX REQUIREMENTS:

- Module header: "module Name (exports) where"
- Imports: "import [qualified] Module [(selective)]"
- Type signature: "name :: type"
- Definition: "name = body" or "name pattern = body"
- Indentation: 2 spaces (configurable)

PRINCIPLES:

1. **Determinism**: Same input produces identical Haskell source
2. **Validity**: All generated code must parse as Haskell 2010 + GHC extensions
3. **Readability**: Human-readable formatting for debugging
4. **Completeness**: All AST nodes properly formatted
-}

module Assertica.Backend.Emit
  ( -- * Main emission functions
    emitHaskellModule
  , emitHaskellDefinition
  , emitHaskellExpression

    -- * Formatting utilities
  , prettyPrint
  , formatModuleHeader
  , formatImports
  , formatDefinition
  , formatTypeSignature

    -- * Configuration
  , EmitConfig(..)
  , defaultEmitConfig
  ) where

import Data.Text (Text)
import qualified Data.Text as T
import Data.List (intercalate)
import GHC.Generics (Generic)

import Assertica.Backend.CodeGen
  ( HaskellModule(..)
  , HaskellDefinition(..)
  , HaskellExpr(..)
  )

-- ============================================================================
-- EMIT CONFIGURATION
-- ============================================================================

{-| Configuration for Haskell code emission -}
data EmitConfig = EmitConfig
  { ecIndentSize :: Int           -- ^ Spaces per indentation level (default: 2)
  , ecLineLength :: Int           -- ^ Target line length (default: 80)
  , ecAddComments :: Bool         -- ^ Include source comments (default: True)
  , ecPreludeImports :: Bool      -- ^ Auto-import Prelude (default: True)
  }
  deriving (Show, Generic)

{-| Default emission configuration -}
defaultEmitConfig :: EmitConfig
defaultEmitConfig = EmitConfig
  { ecIndentSize = 2
  , ecLineLength = 80
  , ecAddComments = True
  , ecPreludeImports = True
  }

-- ============================================================================
-- MAIN EMISSION FUNCTIONS
-- ============================================================================

{-| Emit a complete Haskell module as source code.

This is the primary interface for generating output .hs files.
Takes a HaskellModule and produces a complete, syntactically valid Haskell
program that can be compiled with GHC.
-}
emitHaskellModule :: EmitConfig -> HaskellModule -> Text
emitHaskellModule config (HaskellModule modName imports defs comments) =
  T.unlines $
    -- Comments
    map (T.cons '-') comments ++
    [""]

    -- Module header
    ++ [formatModuleHeader modName]

    -- Imports
    ++ (if null imports then [] else [""] ++ formatImports config imports)

    -- Definitions
    ++ (if null defs then [] else [""] ++ map (emitHaskellDefinition config) defs)

{-| Emit a single Haskell definition -}
emitHaskellDefinition :: EmitConfig -> HaskellDefinition -> Text
emitHaskellDefinition config (HaskellDefinition name typeSig body sourceLocation) =
  let
    -- Type signature (if present)
    sigLines = case typeSig of
      Nothing -> []
      Just sig -> [formatTypeSignature name sig]

    -- Definition line
    defLine = formatDefinition name body

    -- Source location comment
    commentLines = case sourceLocation of
      Nothing -> []
      Just loc | ecAddComments config -> ["-- Source: " <> loc]
      _ -> []
  in
    T.unlines $ commentLines ++ sigLines ++ [defLine]

{-| Emit a single Haskell expression -}
emitHaskellExpression :: EmitConfig -> HaskellExpr -> Text
emitHaskellExpression _config (HaskellExpr expr _mtype) =
  expr

-- ============================================================================
-- FORMATTING FUNCTIONS
-- ============================================================================

{-| Format module header -}
formatModuleHeader :: [Text] -> Text
formatModuleHeader modName =
  "module " <> T.intercalate "." modName <> " where"

{-| Format import statements -}
formatImports :: EmitConfig -> [Text] -> [Text]
formatImports _config imports =
  map ("import " <>) imports

{-| Format a type signature -}
formatTypeSignature :: Text -> Text -> Text
formatTypeSignature name typeSig =
  name <> " :: " <> typeSig

{-| Format a definition with name and body -}
formatDefinition :: Text -> Text -> Text
formatDefinition name body =
  name <> " = " <> body

-- ============================================================================
-- PRETTY-PRINTING
-- ============================================================================

{-| Pretty-print a piece of code with proper indentation and formatting.

This takes raw code (possibly from a compiler) and formats it nicely
for human consumption and debugging.
-}
prettyPrint :: EmitConfig -> Text -> Text
prettyPrint config code =
  -- Add proper indentation, line wrapping, etc.
  -- For now, return as-is
  code

{-| Indent a text block by n levels -}
indent :: Int -> Text -> Text
indent n txt =
  let spaces = T.replicate n " "
      lines_ = T.lines txt
  in T.unlines $ map (spaces <>) lines_

{-| Wrap text to specified line length -}
wrap :: Int -> Text -> Text
wrap _lineLen txt =
  -- Simple implementation: just return as-is
  -- A full implementation would break at spaces
  txt