File size: 7,441 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
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}

{-|
Module      : Assertica.Backend.TermCompiler
Description : Compile Assertica terms to Haskell expressions
Copyright   : (c) 2026 Ahmad Ali Parr
License     : BSL-1.0

Translates computational terms from the Core AST to Haskell expressions:

MAPPINGS:

- Var v                     β†’ v (variable reference)
- Const c                   β†’ haskellLiteral c (constant)
- Lam (x : T) . e           β†’ \x -> <compiled e> (lambda)
- App f x                   β†’ (<compiled f>) (<compiled x>) (application)
- Constr C [e1, ..., en]    β†’ C e1 ... en (constructor application)
- Case e [p1->b1, ...] def  β†’ case e of { p1 -> b1; ... } (case expression)
- Let x = e1 in e2          β†’ let x = <compiled e1> in <compiled e2>
- Ann e T                   β†’ (<compiled e> :: <compiled T>) (type ascription)
- Forall (x : T) . body     β†’ \(x :: <compiled T>) -> <compiled body> (dependent fn)
- ProofTerm p               β†’ <compiled p> (proof evidence)
- Prop prop                 β†’ proof-irrelevant <compiled p> (propositions as terms)

PRINCIPLES:

1. **Deterministic**: Always produces same output for same input
2. **Preserve Beta-Equivalence**: Compilation respects computational semantics
3. **Scope Preservation**: Free/bound variable distinction maintained
4. **No Code Simplification**: Generate direct translation (optimizer's job)
-}

module Assertica.Backend.TermCompiler
  ( -- * Main compilation function
    compileTerm
  , compilePattern
  , compileClause
  ) where

import Data.Text (Text)
import qualified Data.Text as T
import Data.List (intercalate, sortBy)
import Data.Ord (comparing)
import qualified Data.Set as Set
import qualified Data.Map.Strict as Map
import GHC.Generics (Generic)

import Assertica.Core.AST
import Assertica.Backend.CodeGen (CodeGenConfig)

-- ============================================================================
-- MAIN COMPILATION FUNCTION
-- ============================================================================

{-| Compile a term to Haskell source code.

This is the primary entry point for term compilation.
Returns either a Haskell expression string or an error.
-}
compileTerm :: CodeGenConfig -> Term -> Either String Text
compileTerm config term = compileTermWith config Set.empty term

{-| Compile a term with a given bound variable context.

The bound context tracks variables that are bound by enclosing lambdas,
let-bindings, or other binders, to ensure proper scoping.
-}
compileTermWith :: CodeGenConfig -> Set.Set Var -> Term -> Either String Text
compileTermWith config bound = \case
  Var (Var name _) ->
    Right $ name

  Const c -> Right $ compileConstant c

  Lam (Binder (Var name _) _mty) body ->
    let bound' = Set.insert (Var name 0) bound  -- Simplified: just track name
    in do
      compiledBody <- compileTermWith config bound' body
      Right $ "(\\(" <> name <> ") -> " <> compiledBody <> ")"

  App f x -> do
    cf <- compileTermWith config bound f
    cx <- compileTermWith config bound x
    Right $ "(" <> cf <> " " <> cx <> ")"

  Constr (QName mod name) args -> do
    compiledArgs <- mapM (compileTermWith config bound) args
    let qname = if null mod
                  then name
                  else T.intercalate "." mod <> "." <> name
    if null compiledArgs
      then Right qname
      else Right $ "(" <> qname <> " " <> T.intercalate " " compiledArgs <> ")"

  Case scrutinee clauses defaultClause -> do
    cs <- compileTermWith config bound scrutinee
    compiledClauses <- mapM (compileClause config bound) clauses

    let caseClauses = T.intercalate "; " compiledClauses
    let defaultPart = case defaultClause of
          Nothing -> ""
          Just d -> do
            cd <- compileTermWith config bound d
            "; _ -> " <> cd

    Right $ "(case " <> cs <> " of { " <> caseClauses <> defaultPart <> " })"

  Let (Binder (Var name _) _) bindExpr bodyExpr -> do
    cb <- compileTermWith config bound bindExpr
    let bound' = Set.insert (Var name 0) bound
    ce <- compileTermWith config bound' bodyExpr
    Right $ "(let " <> name <> " = " <> cb <> " in " <> ce <> ")"

  Ann term _ty -> do
    -- For now, ignore the type annotation in code gen
    -- In a full implementation, could preserve as Haskell type ascription
    compileTermWith config bound term

  Forall (Binder (Var name _) _) body -> do
    -- Dependent function: treat as lambda abstraction
    let bound' = Set.insert (Var name 0) bound
    cb <- compileTermWith config bound' body
    Right $ "(\\(" <> name <> ") -> " <> cb <> ")"

  ProofTerm p -> do
    -- Proofs compile to evidence terms
    compileProofTerm config bound p

  Prop prop -> do
    -- Propositions as terms become proof-irrelevant ()
    -- The proposition itself is erased (proof irrelevance)
    Right "()"

-- ============================================================================
-- PATTERN COMPILATION
-- ============================================================================

{-| Compile a pattern to Haskell pattern syntax -}
compilePattern :: Pattern -> Either String Text
compilePattern = \case
  PatVar (Var name _) -> Right name

  PatConstr (QName mod name) pats -> do
    compiledPats <- mapM compilePattern pats
    let qname = if null mod
                  then name
                  else T.intercalate "." mod <> "." <> name
    if null compiledPats
      then Right qname
      else Right $ "(" <> qname <> " " <> T.intercalate " " compiledPats <> ")"

  PatWildcard -> Right "_"

  PatLit lit -> Right $ T.pack lit

{-| Compile a single case clause -}
compileClause :: CodeGenConfig -> Set.Set Var -> Clause -> Either String Text
compileClause config bound (Clause pat body) = do
  cp <- compilePattern pat
  cb <- compileTermWith config bound body
  Right $ cp <> " -> " <> cb

-- ============================================================================
-- CONSTANT COMPILATION
-- ============================================================================

{-| Compile a constant value -}
compileConstant :: Constant -> Text
compileConstant = \case
  PrimOp op -> compilePrimOp op
  IntLit n -> T.pack $ show n
  BoolLit b -> T.pack $ show b
  StringLit s -> T.pack $ show s
  UnitConst -> "()"
  ProofConst (QName mod name) ->
    if null mod
      then name
      else T.intercalate "." mod <> "." <> name

{-| Compile a primitive operation to Haskell -}
compilePrimOp :: PrimitiveOp -> Text
compilePrimOp = \case
  OpAdd -> "(+)"
  OpSub -> "(-)"
  OpMul -> "(*)"
  OpDiv -> "div"
  OpEq -> "(==)"
  OpNeq -> "(/=)"
  OpLt -> "(<)"
  OpLe -> "(<=)"
  OpGt -> "(>)"
  OpGe -> "(>=)"
  OpAnd -> "(&&)"
  OpOr -> "(||)"
  OpNot -> "not"
  OpIfThenElse -> "if"  -- Special handling in caller

-- ============================================================================
-- PROOF TERM COMPILATION (provisional)
-- ============================================================================

{-| Compile a proof term to Haskell evidence.

This is a simplified version that handles basic proof terms.
Full proof term handling is delegated to ProofCompiler.
-}
compileProofTerm :: CodeGenConfig -> Set.Set Var -> Proof -> Either String Text
compileProofTerm _config _bound = \case
  Refl e -> Right "Refl"
  Symm _ -> Right "Symm"
  Trans _ _ -> Right "Trans"
  ProofVar (Var name _) -> Right name
  _ -> Right "()"  -- Default: unit for unhandled proofs