axel-0.0.6: src/Axel/Normalize.hs
{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
module Axel.Normalize where
import Axel.AST
( CaseBlock(CaseBlock)
, DataDeclaration(DataDeclaration)
, Expression(ECaseBlock, EEmptySExpression, EFunctionApplication,
EIdentifier, ELambda, ELetBlock, ELiteral, ERawExpression)
, FunctionApplication(FunctionApplication)
, FunctionDefinition(FunctionDefinition)
, Identifier
, Import(ImportItem, ImportType)
, ImportSpecification(ImportAll, ImportOnly)
, Lambda(Lambda)
, LetBlock(LetBlock)
, Literal(LChar, LInt, LString)
, MacroDefinition(MacroDefinition)
, Pragma(Pragma)
, QualifiedImport(QualifiedImport)
, RestrictedImport(RestrictedImport)
, Statement(SDataDeclaration, SFunctionDefinition, SMacroDefinition,
SModuleDeclaration, SPragma, SQualifiedImport, SRawStatement,
SRestrictedImport, STopLevel, STypeSignature, STypeSynonym,
STypeclassDefinition, STypeclassInstance, SUnrestrictedImport)
, TopLevel(TopLevel)
, TypeDefinition(ProperType, TypeConstructor)
, TypeSignature(TypeSignature)
, TypeSynonym(TypeSynonym)
, TypeclassDefinition(TypeclassDefinition)
, TypeclassInstance(TypeclassInstance)
)
import Axel.Error (Error(NormalizeError))
import qualified Axel.Parse as Parse
( Expression(LiteralChar, LiteralInt, LiteralString, SExpression,
Symbol)
)
import Control.Monad.Freer (Eff, Member)
import Control.Monad.Freer.Error (throwError)
import qualified Control.Monad.Freer.Error as Effs (Error)
normalizeExpression ::
(Member (Effs.Error Error) effs) => Parse.Expression -> Eff effs Expression
normalizeExpression (Parse.LiteralChar char) = pure $ ELiteral (LChar char)
normalizeExpression (Parse.LiteralInt int) = pure $ ELiteral (LInt int)
normalizeExpression (Parse.LiteralString string) =
pure $ ELiteral (LString string)
normalizeExpression expr@(Parse.SExpression items) =
case items of
Parse.Symbol "case":var:cases ->
let normalizedCases =
traverse
(\case
Parse.SExpression [pat, body] ->
(,) <$> normalizeExpression pat <*> normalizeExpression body
x -> throwError $ NormalizeError "Invalid case!" [x, expr])
cases
in ECaseBlock <$>
(CaseBlock <$> normalizeExpression var <*> normalizedCases)
[Parse.Symbol "\\", Parse.SExpression args, body] ->
let normalizedArguments = traverse normalizeExpression args
in ELambda <$>
(Lambda <$> normalizedArguments <*> normalizeExpression body)
[Parse.Symbol "let", Parse.SExpression bindings, body] ->
let normalizedBindings =
traverse
(\case
Parse.SExpression [name, value] ->
(,) <$> normalizeExpression name <*>
normalizeExpression value
x -> throwError $ NormalizeError "Invalid pattern!" [x, expr])
bindings
in ELetBlock <$>
(LetBlock <$> normalizedBindings <*> normalizeExpression body)
[Parse.Symbol "raw", rawSource] ->
let normalizedRawSource =
case rawSource of
Parse.LiteralString x -> pure x
x ->
throwError $
NormalizeError
"`raw` takes strings representing the code to inject directly."
[x, expr]
in ERawExpression <$> normalizedRawSource
fn:args ->
EFunctionApplication <$>
(FunctionApplication <$> normalizeExpression fn <*>
traverse normalizeExpression args)
[] -> pure EEmptySExpression
normalizeExpression (Parse.Symbol symbol) = pure $ EIdentifier symbol
normalizeFunctionDefinition ::
(Member (Effs.Error Error) effs)
=> Identifier
-> [Parse.Expression]
-> Parse.Expression
-> Eff effs FunctionDefinition
normalizeFunctionDefinition fnName arguments body =
FunctionDefinition fnName <$> traverse normalizeExpression arguments <*>
normalizeExpression body
normalizeStatement ::
(Member (Effs.Error Error) effs) => Parse.Expression -> Eff effs Statement
normalizeStatement expr@(Parse.SExpression items) =
case items of
[Parse.Symbol "::", Parse.Symbol fnName, typeDef] ->
STypeSignature <$> (TypeSignature fnName <$> normalizeExpression typeDef)
[Parse.Symbol "=", Parse.Symbol fnName, Parse.SExpression arguments, body] ->
SFunctionDefinition <$> normalizeFunctionDefinition fnName arguments body
Parse.Symbol "begin":stmts ->
let normalizedStmts = traverse normalizeStatement stmts
in STopLevel . TopLevel <$> normalizedStmts
Parse.Symbol "class":classConstraints:className:sigs ->
let normalizedConstraints =
normalizeExpression classConstraints >>= \case
EFunctionApplication (FunctionApplication (EIdentifier "list") constraints) ->
pure constraints
_ ->
throwError $
NormalizeError "Invalid constraints!" [classConstraints, expr]
normalizedSigs =
traverse
(\x ->
normalizeStatement x >>= \case
STypeSignature tySig -> pure tySig
_ ->
throwError $
NormalizeError "Invalid type signature!" [x, expr])
sigs
in STypeclassDefinition <$>
(TypeclassDefinition <$> normalizeExpression className <*>
normalizedConstraints <*>
normalizedSigs)
Parse.Symbol "data":typeDef:constructors ->
let normalizedConstructors =
traverse
(\x ->
normalizeExpression x >>= \case
EFunctionApplication functionApplication ->
pure functionApplication
_ ->
throwError $
NormalizeError "Invalid type constructor!" [x, expr])
constructors
in normalizeExpression typeDef >>= \case
EFunctionApplication typeConstructor ->
SDataDeclaration <$>
(DataDeclaration (TypeConstructor typeConstructor) <$>
normalizedConstructors)
EIdentifier properType ->
SDataDeclaration <$>
(DataDeclaration (ProperType properType) <$>
normalizedConstructors)
_ -> throwError $ NormalizeError "Invalid type!" [typeDef, expr]
[Parse.Symbol "import", Parse.Symbol moduleName, importSpec] ->
SRestrictedImport <$>
(RestrictedImport moduleName <$> normalizeImportSpec expr importSpec)
[Parse.Symbol "importq", Parse.Symbol moduleName, Parse.Symbol alias, importSpec] ->
SQualifiedImport <$>
(QualifiedImport moduleName alias <$> normalizeImportSpec expr importSpec)
[Parse.Symbol "importUnrestricted", Parse.Symbol moduleName] ->
pure $ SUnrestrictedImport moduleName
Parse.Symbol "instance":instanceName:defs ->
let normalizedDefs =
traverse
(\x ->
normalizeStatement x >>= \case
SFunctionDefinition fnDef -> pure fnDef
_ ->
throwError $ NormalizeError "Invalid definition!" [x, expr])
defs
in STypeclassInstance <$>
(TypeclassInstance <$> normalizeExpression instanceName <*>
normalizedDefs)
[Parse.Symbol "pragma", Parse.LiteralString pragma] ->
pure $ SPragma (Pragma pragma)
[Parse.Symbol "macro", Parse.Symbol macroName, Parse.SExpression arguments, body] ->
SMacroDefinition . MacroDefinition <$>
normalizeFunctionDefinition macroName arguments body
[Parse.Symbol "module", Parse.Symbol moduleName] ->
pure $ SModuleDeclaration moduleName
[Parse.Symbol "raw", rawSource] ->
let normalizedRawSource =
case rawSource of
Parse.LiteralString x -> pure x
x ->
throwError $
NormalizeError
"`raw` takes strings representing the code to inject directly."
[x, expr]
in SRawStatement <$> normalizedRawSource
[Parse.Symbol "type", alias, def] ->
let normalizedAlias = normalizeExpression alias
normalizedDef = normalizeExpression def
in STypeSynonym <$> (TypeSynonym <$> normalizedAlias <*> normalizedDef)
_ -> throwError $ NormalizeError "Invalid top-level form!" [expr]
where
normalizeImportSpec ctxt importSpec =
case importSpec of
Parse.Symbol "all" -> pure ImportAll
Parse.SExpression importList -> normalizeImportList ctxt importList
x ->
throwError $ NormalizeError "Invalid import specification!" [x, ctxt]
normalizeImportList ctxt input =
ImportOnly <$>
traverse
(\item ->
case item of
Parse.Symbol import' -> pure $ ImportItem import'
Parse.SExpression (Parse.Symbol type':imports) ->
let normalizedImports =
traverse
(\case
Parse.Symbol import' -> pure import'
x ->
throwError $
NormalizeError "Invalid import!" [x, item, ctxt])
imports
in ImportType type' <$> normalizedImports
x -> throwError $ NormalizeError "Invalid import!" [x, item, ctxt])
input
normalizeStatement expr =
throwError $ NormalizeError "Invalid top-level form!" [expr]