File size: 9,207 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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}

{-|
Module      : Assertica.Backend.CodeGen
Description : Main code generation engine for Assertica → Haskell compilation
Copyright   : (c) 2026 Ahmad Ali Parr
License     : BSL-1.0

This module is the primary interface for translating verified Assertica Core AST
to executable Haskell code. It orchestrates the compilation pipeline:

1. **TermCompiler**: Translates computational terms to Haskell expressions
2. **TypeCompiler**: Maps type universe to Haskell type signatures
3. **ProofCompiler**: Converts proof terms to Haskell evidence
4. **Emit**: Renders the result as syntactically valid Haskell source

DESIGN PRINCIPLES:

1. **Deterministic Generation**: Same AST input always produces identical output
2. **Type Safety**: Generated code must typecheck under GHC 9.2+
3. **No Unsafe Code**: Forbidden to use unsafeCoerce or similar
4. **Fail-Closed**: Malformed input generates an error, not silent code
5. **Module-Aware**: Qualified names preserve module structure

INTERFACE CONTRACT:

- compileModule: Module → Either String HaskellModule
  Takes a Module (from Core.Module), returns Haskell source or error

- compileDefinition: Definition → Either String HaskellDefinition
  Compiles a single definition (term, type, assertion, etc.)

- compileExpression: Term → Either String HaskellExpr
  Compiles a single term expression to Haskell

ASSUMPTIONS:

- All input has been verified by Agent 3B (TypeChecker)
- All proofs are valid (checked by Agent 2B)
- All module dependencies are resolved
- No circular references in type definitions
-}

module Assertica.Backend.CodeGen
  ( -- * Main compilation interface
    compileModule
  , compileDefinition
  , compileExpression
  , compileType
  , compileProof

    -- * Compiled output types
  , HaskellModule(..)
  , HaskellDefinition(..)
  , HaskellExpr(..)

    -- * Error handling
  , CodeGenError(..)
  , formatCodeGenError

    -- * Configuration
  , CodeGenConfig(..)
  , defaultConfig
  ) where

import Data.Text (Text)
import qualified Data.Text as T
import Data.List (intercalate)
import Data.Maybe (mapMaybe, catMaybes)
import qualified Data.Set as Set
import qualified Data.Map.Strict as Map
import GHC.Generics (Generic)

import Assertica.Core.AST
import Assertica.Core.Module (Module(..), Definition(..), ModuleMetadata(..))
import qualified Assertica.Backend.TermCompiler as TC
import qualified Assertica.Backend.TypeCompiler as TyC
import qualified Assertica.Backend.ProofCompiler as PC
import qualified Assertica.Backend.Emit as Emit

-- ============================================================================
-- TYPES
-- ============================================================================

{-| Configuration for code generation -}
data CodeGenConfig = CodeGenConfig
  { cgcAddComments :: Bool        -- ^ Include source location comments
  , cgcAddTypeSignatures :: Bool  -- ^ Include type signatures for all definitions
  , cgcModulePrefix :: [Text]    -- ^ Module path prefix for qualification
  , cgcTargetVersion :: (Int, Int)  -- ^ GHC version target (e.g., (9, 2))
  }
  deriving (Show, Generic)

{-| Default code generation configuration -}
defaultConfig :: CodeGenConfig
defaultConfig = CodeGenConfig
  { cgcAddComments = True
  , cgcAddTypeSignatures = True
  , cgcModulePrefix = []
  , cgcTargetVersion = (9, 2)
  }

{-| A compiled Haskell module (abstract representation) -}
data HaskellModule = HaskellModule
  { hmName :: [Text]                    -- ^ Module name path
  , hmImports :: [Text]                 -- ^ Import statements (one per line)
  , hmDefinitions :: [HaskellDefinition] -- ^ All definitions in module
  , hmComments :: [Text]                -- ^ Header comments
  }
  deriving (Show, Generic)

{-| A single compiled Haskell definition -}
data HaskellDefinition = HaskellDefinition
  { hdName :: Text                      -- ^ Definition name
  , hdTypeSignature :: Maybe Text       -- ^ Type signature (e.g., "x :: Int")
  , hdBody :: Text                      -- ^ Definition body
  , hdSourceLocation :: Maybe Text      -- ^ Source location comment
  }
  deriving (Show, Generic)

{-| A compiled Haskell expression -}
data HaskellExpr = HaskellExpr
  { heExpr :: Text                      -- ^ The Haskell expression
  , heType :: Maybe Text                -- ^ Inferred type annotation
  }
  deriving (Show, Generic)

{-| Code generation errors -}
data CodeGenError
  = UnhandledConstruct String
  | InvalidQName QName
  | TypeCompilationFailed String
  | ProofCompilationFailed String
  | TermCompilationFailed String
  | ModuleCompilationFailed String
  | UnsupportedFeature String
  deriving (Show, Generic)

{-| Human-readable error formatting -}
formatCodeGenError :: CodeGenError -> String
formatCodeGenError = \case
  UnhandledConstruct desc ->
    "Code generation: unhandled construct: " ++ desc
  InvalidQName (QName mod name) ->
    "Code generation: invalid qualified name: " ++ intercalate "." (map T.unpack mod) ++ "." ++ T.unpack name
  TypeCompilationFailed desc ->
    "Code generation: type compilation failed: " ++ desc
  ProofCompilationFailed desc ->
    "Code generation: proof compilation failed: " ++ desc
  TermCompilationFailed desc ->
    "Code generation: term compilation failed: " ++ desc
  ModuleCompilationFailed desc ->
    "Code generation: module compilation failed: " ++ desc
  UnsupportedFeature desc ->
    "Code generation: unsupported feature: " ++ desc

-- ============================================================================
-- MAIN COMPILATION INTERFACE
-- ============================================================================

{-| Compile an entire Assertica module to Haskell code.

The module must be fully elaborated and type-checked before reaching this stage.
This is the primary entry point for the backend.
-}
compileModule :: CodeGenConfig -> Module -> Either String HaskellModule
compileModule config (Module _modQName _imports _exports defMap _metadata) = do
  -- Compile all definitions from the definition map
  compiledDefs <- mapM (compileDefinitionValue config) (Map.elems defMap)

  -- Generate module header
  let imports = generateImports config
  let comments = ["-- Generated by Assertica Backend", "-- Do not edit manually"]

  return $ HaskellModule
    { hmName = []  -- Could extract from modQName if needed
    , hmImports = imports
    , hmDefinitions = compiledDefs
    , hmComments = comments
    }

{-| Compile a single definition from Module's Definition type -}
compileDefinitionValue :: CodeGenConfig -> Definition -> Either String HaskellDefinition
compileDefinitionValue config defn = case defn of
  DefTerm term -> do
    compiled <- compileExpression config term
    return $ HaskellDefinition
      { hdName = "value"  -- Anonymous term
      , hdTypeSignature = Nothing
      , hdBody = heExpr compiled
      , hdSourceLocation = if cgcAddComments config then Just "term" else Nothing
      }

  DefType ty -> do
    compiled <- compileType config ty
    return $ HaskellDefinition
      { hdName = "type_def"  -- Anonymous type
      , hdTypeSignature = Just "Type"
      , hdBody = heExpr compiled
      , hdSourceLocation = if cgcAddComments config then Just "type" else Nothing
      }

  DefAssertion _assertion -> do
    -- For now, compile assertion as a unit
    return $ HaskellDefinition
      { hdName = "assertion"
      , hdTypeSignature = Nothing
      , hdBody = "()"
      , hdSourceLocation = if cgcAddComments config then Just "assertion" else Nothing
      }

  DefOpaque desc ->
    return $ HaskellDefinition
      { hdName = "opaque"
      , hdTypeSignature = Nothing
      , hdBody = T.pack desc
      , hdSourceLocation = if cgcAddComments config then Just "opaque" else Nothing
      }

{-| Compile a single definition (can be a term, type, assertion, etc.) -}
compileDefinition :: CodeGenConfig -> Definition -> Either String HaskellDefinition
compileDefinition = compileDefinitionValue

{-| Compile a single term expression to Haskell -}
compileExpression :: CodeGenConfig -> Term -> Either String HaskellExpr
compileExpression config term = do
  expr <- TC.compileTerm config term
  return $ HaskellExpr
    { heExpr = expr
    , heType = Nothing
    }

{-| Compile a type to Haskell -}
compileType :: CodeGenConfig -> Type -> Either String HaskellExpr
compileType config ty = do
  expr <- TyC.compileType config ty
  return $ HaskellExpr
    { heExpr = expr
    , heType = Just "Type"  -- All types have kind Type
    }

{-| Compile a proof to Haskell -}
compileProof :: CodeGenConfig -> Proof -> Either String HaskellExpr
compileProof config proof = do
  expr <- PC.compileProof config proof
  return $ HaskellExpr
    { heExpr = expr
    , heType = Nothing
    }

-- ============================================================================
-- HELPER FUNCTIONS
-- ============================================================================

{-| Generate standard Haskell imports for a module -}
generateImports :: CodeGenConfig -> [Text]
generateImports _config =
  [ "import Prelude"
  , "import qualified Data.Typeable as Typeable"
  , "import GHC.Generics (Generic)"
  ]