packages feed

axel-0.0.13: src/Axel/Denormalize.hs

module Axel.Denormalize where

import Axel.Prelude

import Axel.AST
  ( Expression(ECaseBlock, EEmptySExpression, EFunctionApplication,
           EIdentifier, ELambda, ELetBlock, ELiteral, EPatternBinding,
           ERawExpression, ERecordDefinition, ERecordType)
  , Import(ImportItem, ImportType)
  , ImportSpecification(ImportAll, ImportOnly)
  , Literal(LChar, LFloat, LInt, LString)
  , SMExpression
  , SMStatement
  , Statement(SDataDeclaration, SFunctionDefinition, SMacroDefinition,
          SMacroImport, SModuleDeclaration, SNewtypeDeclaration, SPragma,
          SQualifiedImport, SRawStatement, SRestrictedImport, STopLevel,
          STypeSignature, STypeSynonym, STypeclassDefinition,
          STypeclassInstance)
  , TopLevel(TopLevel)
  , TypeDefinition(ProperType, TypeConstructor)
  , alias
  , arguments
  , bindings
  , body
  , constraints
  , constructors
  , definition
  , definitions
  , derivedConstraints
  , expr
  , fields
  , function
  , functionDefinition
  , getAnn'
  , imports
  , instanceName
  , matches
  , moduleName
  , name
  , pattern'
  , pragmaSpecification
  , signatures
  , typeDefinition
  , whereBindings
  , wrappedType
  )
import qualified Axel.Parse.AST as Parse
import qualified Axel.Sourcemap as SM
import Axel.Utils.List (unsafeHead)

import Control.Lens.Operators ((^.), (|>))

import qualified Data.Text as T

-- | Metadata is only approximately restored. Thus, `Axel.Normalize.normalizeExpression` and
-- | `denormalizeExpression` are only inverses if metadata information is
-- | ignored, although they should be pretty close either way.
denormalizeExpression :: SMExpression -> SM.Expression
denormalizeExpression (ECaseBlock caseBlock) =
  let ann' = getAnn' caseBlock
      denormalizedCases =
        map
          (\(pat, res) ->
             Parse.SExpression
               ann'
               [denormalizeExpression pat, denormalizeExpression res])
          (caseBlock ^. matches)
   in Parse.SExpression ann' $ Parse.Symbol ann' "case" :
      denormalizeExpression (caseBlock ^. expr) :
      denormalizedCases
denormalizeExpression expr'@(EEmptySExpression _) =
  Parse.SExpression (getAnn' expr') []
denormalizeExpression (EFunctionApplication functionApplication) =
  Parse.SExpression (getAnn' functionApplication) $
  denormalizeExpression (functionApplication ^. function) :
  map denormalizeExpression (functionApplication ^. arguments)
denormalizeExpression expr'@(EIdentifier _ x) =
  Parse.Symbol (getAnn' expr') (T.unpack x)
denormalizeExpression (ELambda lambda) =
  let ann' = getAnn' lambda
      denormalizedArguments =
        Parse.SExpression ann' $ Parse.Symbol ann' "list" :
        map denormalizeExpression (lambda ^. arguments)
   in Parse.SExpression
        ann'
        [ Parse.Symbol ann' "\\"
        , denormalizedArguments
        , denormalizeExpression (lambda ^. body)
        ]
denormalizeExpression (ELetBlock letBlock) =
  let ann' = getAnn' letBlock
      denormalizedBindings =
        Parse.SExpression ann' $ Parse.Symbol ann' "list" :
        map
          (\(var, val) ->
             Parse.SExpression
               ann'
               [denormalizeExpression var, denormalizeExpression val])
          (letBlock ^. bindings)
   in Parse.SExpression
        ann'
        [ Parse.Symbol ann' "let"
        , denormalizedBindings
        , denormalizeExpression (letBlock ^. body)
        ]
denormalizeExpression (ELiteral x) =
  case x of
    LChar _ char -> Parse.LiteralChar (getAnn' x) char
    LFloat _ float -> Parse.LiteralFloat (getAnn' x) float
    LInt _ int -> Parse.LiteralInt (getAnn' x) int
    LString _ string -> Parse.LiteralString (getAnn' x) (T.unpack string)
denormalizeExpression (EPatternBinding patternBinding) =
  let ann' = getAnn' patternBinding
   in Parse.SExpression
        ann'
        [ Parse.Symbol ann' "@"
        , denormalizeExpression (patternBinding ^. name)
        , denormalizeExpression (patternBinding ^. pattern')
        ]
denormalizeExpression expr'@(ERawExpression _ rawSource) =
  let ann' = getAnn' expr'
   in Parse.SExpression
        ann'
        [Parse.Symbol ann' "raw", Parse.LiteralString ann' (T.unpack rawSource)]
denormalizeExpression (ERecordDefinition recordDefinition) =
  let ann' = getAnn' recordDefinition
      denormalizedBindings =
        map
          (\(var, val) ->
             Parse.SExpression
               ann'
               [Parse.Symbol ann' (T.unpack var), denormalizeExpression val])
          (recordDefinition ^. bindings)
   in Parse.SExpression ann' (Parse.Symbol ann' "record" : denormalizedBindings)
denormalizeExpression (ERecordType recordType) =
  let ann' = getAnn' recordType
      denormalizedFields =
        map
          (\(field, ty) ->
             Parse.SExpression
               ann'
               [Parse.Symbol ann' (T.unpack field), denormalizeExpression ty])
          (recordType ^. fields)
   in Parse.SExpression
        ann'
        (Parse.Symbol ann' "recordType" : denormalizedFields)

denormalizeImportSpecification ::
     ImportSpecification (Maybe SM.Expression) -> SM.Expression
denormalizeImportSpecification importSpec@(ImportAll _) =
  Parse.Symbol (getAnn' importSpec) "all"
denormalizeImportSpecification importSpec@(ImportOnly _ importList) =
  let ann' = getAnn' importSpec
   in Parse.SExpression ann' $ Parse.Symbol ann' "list" :
      map denormalizeImport importList
  where
    denormalizeImport importList'@(ImportItem _ item) =
      Parse.Symbol (getAnn' importList') (T.unpack item)
    denormalizeImport importList'@(ImportType _ type' items) =
      let ann' = getAnn' importList'
       in Parse.SExpression
            ann'
            (Parse.Symbol ann' (T.unpack type') :
             map (Parse.Symbol ann' . T.unpack) items)

denormalizeStatement :: SMStatement -> SM.Expression
denormalizeStatement (SDataDeclaration dataDeclaration) =
  let ann' = getAnn' dataDeclaration
      denormalizedTypeDefinition =
        case dataDeclaration ^. typeDefinition of
          TypeConstructor _ typeConstructor ->
            denormalizeExpression $ EFunctionApplication typeConstructor
          ProperType _ properType ->
            Parse.Symbol
              (getAnn' $ dataDeclaration ^. typeDefinition)
              (T.unpack properType)
      denormalizedConstructors =
        map denormalizeExpression (dataDeclaration ^. constructors)
      denormalizedDerivedConstraintList =
        Parse.SExpression ann' $ Parse.Symbol ann' "list" :
        map denormalizeExpression (dataDeclaration ^. derivedConstraints)
   in Parse.SExpression ann' $ Parse.Symbol ann' "data" :
      denormalizedTypeDefinition :
      (denormalizedConstructors |> denormalizedDerivedConstraintList)
denormalizeStatement (SFunctionDefinition fnDef) =
  let ann' = getAnn' fnDef
   in Parse.SExpression ann' $ Parse.Symbol ann' "=" :
      Parse.SExpression
        ann'
        (Parse.Symbol ann' (T.unpack $ fnDef ^. name) :
         map denormalizeExpression (fnDef ^. arguments)) :
      denormalizeExpression (fnDef ^. body) :
      map denormalizeStatement (fnDef ^. whereBindings)
denormalizeStatement (SMacroDefinition macroDef) =
  let ann' = getAnn' macroDef
   in Parse.SExpression ann' $ Parse.Symbol ann' "=macro" :
      Parse.Symbol ann' (T.unpack $ macroDef ^. functionDefinition . name) :
      denormalizeExpression
        (unsafeHead $ macroDef ^. functionDefinition . arguments) :
      denormalizeExpression (macroDef ^. functionDefinition . body) :
      map denormalizeStatement (macroDef ^. functionDefinition . whereBindings)
denormalizeStatement (SMacroImport macroImport) =
  let ann' = getAnn' macroImport
   in Parse.SExpression
        ann'
        [ Parse.Symbol ann' "importm"
        , Parse.Symbol ann' (T.unpack $ macroImport ^. moduleName)
        , Parse.SExpression ann' $ Parse.Symbol ann' "list" :
          map (Parse.Symbol ann' . T.unpack) (macroImport ^. imports)
        ]
denormalizeStatement stmt@(SModuleDeclaration _ identifier) =
  let ann' = getAnn' stmt
   in Parse.SExpression
        ann'
        [Parse.Symbol ann' "module", Parse.Symbol ann' (T.unpack identifier)]
denormalizeStatement (SNewtypeDeclaration newtypeDeclaration) =
  let ann' = getAnn' newtypeDeclaration
      denormalizedTypeDefinition =
        case newtypeDeclaration ^. typeDefinition of
          TypeConstructor _ typeConstructor ->
            denormalizeExpression $ EFunctionApplication typeConstructor
          ProperType _ properType ->
            Parse.Symbol
              (getAnn' $ newtypeDeclaration ^. typeDefinition)
              (T.unpack properType)
      denormalizedDerivedConstraintList =
        Parse.SExpression ann' $ Parse.Symbol ann' "list" :
        map denormalizeExpression (newtypeDeclaration ^. derivedConstraints)
   in Parse.SExpression
        ann'
        [ Parse.Symbol ann' "newtype"
        , denormalizedTypeDefinition
        , denormalizeExpression $ newtypeDeclaration ^. wrappedType
        , denormalizedDerivedConstraintList
        ]
denormalizeStatement (SPragma pragma) =
  let ann' = getAnn' pragma
   in Parse.SExpression
        ann'
        [ Parse.Symbol ann' "pragma"
        , Parse.LiteralString ann' (T.unpack $ pragma ^. pragmaSpecification)
        ]
denormalizeStatement (SQualifiedImport qualifiedImport) =
  let ann' = getAnn' qualifiedImport
   in Parse.SExpression
        ann'
        [ Parse.Symbol ann' "importq"
        , Parse.Symbol ann' (T.unpack $ qualifiedImport ^. moduleName)
        , Parse.Symbol ann' (T.unpack $ qualifiedImport ^. alias)
        , denormalizeImportSpecification (qualifiedImport ^. imports)
        ]
denormalizeStatement expr'@(SRawStatement _ rawSource) =
  let ann' = getAnn' expr'
   in Parse.SExpression
        ann'
        [Parse.Symbol ann' "raw", Parse.LiteralString ann' (T.unpack rawSource)]
denormalizeStatement (SRestrictedImport restrictedImport) =
  let ann' = getAnn' restrictedImport
   in Parse.SExpression
        ann'
        [ Parse.Symbol ann' "import"
        , Parse.Symbol ann' (T.unpack $ restrictedImport ^. moduleName)
        , denormalizeImportSpecification (restrictedImport ^. imports)
        ]
denormalizeStatement stmt@(STopLevel (TopLevel _ statements)) =
  let ann' = getAnn' stmt
   in Parse.SExpression ann' $ Parse.Symbol ann' "begin" :
      map denormalizeStatement statements
denormalizeStatement (STypeclassDefinition typeclassDefinition) =
  let ann' = getAnn' typeclassDefinition
   in Parse.SExpression
        ann'
        (Parse.Symbol ann' "class" :
         Parse.SExpression
           ann'
           (Parse.Symbol ann' "list" :
            map denormalizeExpression (typeclassDefinition ^. constraints)) :
         denormalizeExpression (typeclassDefinition ^. name) :
         map
           (denormalizeStatement . STypeSignature)
           (typeclassDefinition ^. signatures))
denormalizeStatement (STypeclassInstance typeclassInstance) =
  let ann' = getAnn' typeclassInstance
   in Parse.SExpression
        ann'
        (Parse.Symbol ann' "instance" :
         Parse.SExpression
           ann'
           (Parse.Symbol ann' "list" :
            map denormalizeExpression (typeclassInstance ^. constraints)) :
         denormalizeExpression (typeclassInstance ^. instanceName) :
         map
           (denormalizeStatement . SFunctionDefinition)
           (typeclassInstance ^. definitions))
denormalizeStatement (STypeSignature typeSig) =
  let ann' = getAnn' typeSig
   in Parse.SExpression
        ann'
        [ Parse.Symbol ann' "::"
        , Parse.Symbol ann' (T.unpack $ typeSig ^. name)
        , Parse.SExpression
            ann'
            (Parse.Symbol ann' "list" :
             map denormalizeExpression (typeSig ^. constraints))
        , denormalizeExpression (typeSig ^. typeDefinition)
        ]
denormalizeStatement (STypeSynonym typeSynonym) =
  let ann' = getAnn' typeSynonym
   in Parse.SExpression
        ann'
        [ Parse.Symbol ann' "type"
        , denormalizeExpression (typeSynonym ^. alias)
        , denormalizeExpression (typeSynonym ^. definition)
        ]