elna/lib/Language/Elna/Glue.hs

302 lines
13 KiB
Haskell
Raw Normal View History

2024-10-02 22:56:15 +02:00
module Language.Elna.Glue
( glue
2024-08-12 21:00:52 +02:00
) where
2024-10-08 17:29:08 +02:00
import Control.Monad.Trans.State (State, gets, modify', runState)
2024-08-18 20:13:59 +02:00
import Data.Bifunctor (Bifunctor(..))
import Data.Foldable (Foldable(..), traverse_)
2024-08-15 20:13:56 +02:00
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
2024-10-02 22:56:15 +02:00
import Data.Maybe (catMaybes)
2024-09-25 23:06:02 +02:00
import Data.Vector (Vector)
2024-10-11 16:14:01 +02:00
import qualified Data.Text.Lazy.Builder.Int as Text.Builder
import qualified Data.Text.Lazy.Builder as Text.Builder
import qualified Data.Text.Lazy as Text.Lazy
2024-09-25 23:06:02 +02:00
import qualified Data.Vector as Vector
2024-08-15 20:13:56 +02:00
import Data.Word (Word32)
2024-10-02 22:56:15 +02:00
import qualified Language.Elna.Frontend.AST as AST
2024-11-06 22:23:49 +01:00
import Language.Elna.Frontend.Types (Type(..))
2024-10-11 16:14:01 +02:00
import Language.Elna.Backend.Intermediate
( Label(..)
, Operand(..)
, Quadruple(..)
, Variable(..)
)
2024-11-06 22:23:49 +01:00
import Language.Elna.Frontend.SymbolTable (Info(..), SymbolTable)
import qualified Language.Elna.Frontend.SymbolTable as SymbolTable
2024-10-08 17:29:08 +02:00
import GHC.Records (HasField(..))
import Language.Elna.Frontend.AST (Identifier(..))
2024-10-08 17:29:08 +02:00
2024-10-11 16:14:01 +02:00
data Paste = Paste
2024-10-08 17:29:08 +02:00
{ temporaryCounter :: Word32
2024-10-11 16:14:01 +02:00
, labelCounter :: Word32
, localMap :: HashMap Identifier Variable
2024-10-08 17:29:08 +02:00
}
2024-08-12 21:00:52 +02:00
2024-10-02 22:56:15 +02:00
newtype Glue a = Glue
2024-10-08 17:29:08 +02:00
{ runGlue :: State Paste a }
2024-08-15 20:13:56 +02:00
2024-10-02 22:56:15 +02:00
instance Functor Glue
where
2024-10-02 22:56:15 +02:00
fmap f (Glue x) = Glue $ f <$> x
2024-10-02 22:56:15 +02:00
instance Applicative Glue
2024-08-30 14:55:40 +02:00
where
2024-10-02 22:56:15 +02:00
pure = Glue . pure
(Glue f) <*> (Glue x) = Glue $ f <*> x
2024-09-25 23:06:02 +02:00
2024-10-02 22:56:15 +02:00
instance Monad Glue
2024-09-25 23:06:02 +02:00
where
2024-10-02 22:56:15 +02:00
(Glue x) >>= f = Glue $ x >>= (runGlue . f)
2024-09-25 23:06:02 +02:00
glue :: SymbolTable -> AST.Program -> HashMap Identifier (Vector (Quadruple Variable))
2024-10-02 22:56:15 +02:00
glue globalTable
2024-09-25 23:06:02 +02:00
= fst
. flip runState emptyPaste
2024-10-02 22:56:15 +02:00
. runGlue
2024-09-25 23:06:02 +02:00
. program globalTable
where
emptyPaste = Paste
{ temporaryCounter = 0
, labelCounter = 0
, localMap = mempty
}
2024-08-30 14:55:40 +02:00
program :: SymbolTable -> AST.Program -> Glue (HashMap Identifier (Vector (Quadruple Variable)))
program globalTable (AST.Program declarations)
= HashMap.fromList . catMaybes
2024-09-25 23:06:02 +02:00
<$> traverse (declaration globalTable) declarations
declaration
:: SymbolTable
-> AST.Declaration
2024-10-02 22:56:15 +02:00
-> Glue (Maybe (AST.Identifier, Vector (Quadruple Variable)))
2024-11-24 13:05:11 +01:00
declaration globalTable (AST.ProcedureDeclaration procedureName parameters variableDeclarations statements)
= Glue (modify' resetTemporaryCounter)
>> traverseWithIndex registerVariable variableDeclarations
>> traverseWithIndex registerParameter (reverse parameters)
>> nameQuadruplesTuple <$> traverse (statement globalTable) statements
where
2024-11-24 13:05:11 +01:00
traverseWithIndex f = traverse_ (uncurry f) . zip [0..]
registerParameter index (AST.Parameter identifier _ _) =
Glue $ modify' $ modifier identifier $ ParameterVariable index
registerVariable index (AST.VariableDeclaration identifier _) =
Glue $ modify' $ modifier identifier $ LocalVariable index
modifier identifier currentCounter generator = generator
{ localMap = HashMap.insert identifier currentCounter
$ getField @"localMap" generator
}
nameQuadruplesTuple quadrupleList = Just
( procedureName
, Vector.cons StartQuadruple
$ flip Vector.snoc StopQuadruple
$ fold quadrupleList
)
resetTemporaryCounter paste = paste
{ temporaryCounter = 0
, localMap = mempty
}
2024-10-17 00:37:42 +02:00
declaration _ (AST.TypeDefinition _ _) = pure Nothing
2024-10-02 22:56:15 +02:00
statement :: SymbolTable -> AST.Statement -> Glue (Vector (Quadruple Variable))
statement _ AST.EmptyStatement = pure mempty
2024-09-25 23:06:02 +02:00
statement localTable (AST.CallStatement (AST.Identifier callName) arguments) = do
visitedArguments <- traverse (expression localTable) arguments
let (parameterStatements, argumentStatements)
= bimap (Vector.fromList . fmap ParameterQuadruple) Vector.concat
$ unzip visitedArguments
in pure
$ Vector.snoc (argumentStatements <> parameterStatements)
$ CallQuadruple callName
$ fromIntegral
$ length arguments
2024-10-04 18:26:10 +02:00
statement localTable (AST.CompoundStatement statements) =
fold <$> traverse (statement localTable) statements
2024-10-11 16:14:01 +02:00
statement localTable (AST.IfStatement ifCondition ifStatement elseStatement) = do
(conditionStatements, jumpConstructor) <- condition localTable ifCondition
ifLabel <- createLabel
endLabel <- createLabel
ifStatements <- statement localTable ifStatement
possibleElseStatements <- traverse (statement localTable) elseStatement
pure $ conditionStatements <> case possibleElseStatements of
Just elseStatements -> Vector.cons (jumpConstructor ifLabel) elseStatements
<> Vector.fromList [GoToQuadruple endLabel, LabelQuadruple ifLabel]
<> Vector.snoc ifStatements (LabelQuadruple endLabel)
Nothing -> Vector.fromList [jumpConstructor ifLabel, GoToQuadruple endLabel, LabelQuadruple ifLabel]
<> Vector.snoc ifStatements (LabelQuadruple endLabel)
2024-11-06 22:23:49 +01:00
statement localTable (AST.AssignmentStatement variableAccess' assignee) = do
(rhsOperand, rhsStatements) <- expression localTable assignee
let variableType' = variableType variableAccess' localTable
accessResult <- variableAccess localTable variableAccess' Nothing variableType' mempty
lhsStatements <- case accessResult of
2024-11-06 22:23:49 +01:00
{-(AST.Identifier identifier, Just accumulatedIndex, accumulatedStatements) ->
2024-08-17 14:16:16 +02:00
Vector.snoc accumulatedStatements
$ ArrayAssignQuadruple rhsOperand accumulatedIndex
2024-11-06 22:23:49 +01:00
$ LocalVariable identifier -}
(identifier, _Nothing, accumulatedStatements)
-> Vector.snoc accumulatedStatements
. AssignQuadruple rhsOperand
<$> lookupLocal identifier
pure $ rhsStatements <> lhsStatements
2024-11-24 13:05:11 +01:00
statement localTable (AST.WhileStatement whileCondition whileStatement) = do
(conditionStatements, jumpConstructor) <- condition localTable whileCondition
startLabel <- createLabel
endLabel <- createLabel
conditionLabel <- createLabel
whileStatements <- statement localTable whileStatement
pure $ Vector.fromList [LabelQuadruple conditionLabel]
2024-08-18 20:13:59 +02:00
<> conditionStatements
<> Vector.fromList [jumpConstructor startLabel, GoToQuadruple endLabel, LabelQuadruple startLabel]
<> whileStatements
2024-11-24 13:05:11 +01:00
<> Vector.fromList [GoToQuadruple conditionLabel, LabelQuadruple endLabel]
2024-09-25 23:06:02 +02:00
2024-10-02 22:56:15 +02:00
createTemporary :: Glue Variable
2024-09-29 19:50:55 +02:00
createTemporary = do
2024-10-08 17:29:08 +02:00
currentCounter <- Glue $ gets $ getField @"temporaryCounter"
Glue $ modify' modifier
2024-09-29 19:50:55 +02:00
pure $ TempVariable currentCounter
2024-10-08 17:29:08 +02:00
where
modifier generator = generator
{ temporaryCounter = getField @"temporaryCounter" generator + 1
}
2024-09-29 19:50:55 +02:00
lookupLocal :: Identifier -> Glue Variable
lookupLocal identifier =
fmap (HashMap.! identifier) $ Glue $ gets $ getField @"localMap"
2024-10-11 16:14:01 +02:00
createLabel :: Glue Label
createLabel = do
currentCounter <- Glue $ gets $ getField @"labelCounter"
Glue $ modify' modifier
pure $ Label
$ Text.Lazy.toStrict
$ Text.Builder.toLazyText
$ ".L" <> Text.Builder.decimal currentCounter
2024-09-25 23:06:02 +02:00
where
2024-10-11 16:14:01 +02:00
modifier generator = generator
{ labelCounter = getField @"labelCounter" generator + 1
}
2024-09-25 23:06:02 +02:00
condition
:: SymbolTable
-> AST.Condition
2024-10-11 16:14:01 +02:00
-> Glue (Vector (Quadruple Variable), Label -> Quadruple Variable)
condition localTable (AST.EqualCondition lhs rhs) = do
(lhsOperand, lhsStatements) <- expression localTable lhs
(rhsOperand, rhsStatements) <- expression localTable rhs
pure
( lhsStatements <> rhsStatements
, EqualQuadruple lhsOperand rhsOperand
)
2024-10-13 12:59:47 +02:00
condition localTable (AST.NonEqualCondition lhs rhs) = do
(lhsOperand, lhsStatements) <- expression localTable lhs
(rhsOperand, rhsStatements) <- expression localTable rhs
pure
( lhsStatements <> rhsStatements
, NonEqualQuadruple lhsOperand rhsOperand
)
condition localTable (AST.LessCondition lhs rhs) = do
(lhsOperand, lhsStatements) <- expression localTable lhs
(rhsOperand, rhsStatements) <- expression localTable rhs
pure (lhsStatements <> rhsStatements, LessQuadruple lhsOperand rhsOperand)
condition localTable (AST.GreaterCondition lhs rhs) = do
(lhsOperand, lhsStatements) <- expression localTable lhs
(rhsOperand, rhsStatements) <- expression localTable rhs
pure
( lhsStatements <> rhsStatements
, GreaterQuadruple lhsOperand rhsOperand
)
condition localTable (AST.LessOrEqualCondition lhs rhs) = do
(lhsOperand, lhsStatements) <- expression localTable lhs
(rhsOperand, rhsStatements) <- expression localTable rhs
pure
( lhsStatements <> rhsStatements
, LessOrEqualQuadruple lhsOperand rhsOperand
)
condition localTable (AST.GreaterOrEqualCondition lhs rhs) = do
(lhsOperand, lhsStatements) <- expression localTable lhs
(rhsOperand, rhsStatements) <- expression localTable rhs
pure
( lhsStatements <> rhsStatements
, GreaterOrEqualQuadruple lhsOperand rhsOperand
)
2024-08-15 20:13:56 +02:00
variableAccess
:: SymbolTable
-> AST.VariableAccess
2024-11-06 22:23:49 +01:00
-> Maybe (Operand Variable)
2024-08-15 20:13:56 +02:00
-> Type
2024-11-06 22:23:49 +01:00
-> Vector (Quadruple Variable)
-> Glue (AST.Identifier, Maybe (Operand Variable), Vector (Quadruple Variable))
2024-08-15 20:13:56 +02:00
variableAccess _ (AST.VariableAccess identifier) accumulatedIndex _ accumulatedStatements =
pure (identifier, accumulatedIndex, accumulatedStatements)
2024-11-06 22:23:49 +01:00
{- variableAccess localTable (AST.ArrayAccess access1 index1) Nothing (ArrayType _ baseType) _ = do
(indexPlace, statements) <- expression localTable index1
variableAccess localTable access1 (Just indexPlace) baseType statements
variableAccess localTable (AST.ArrayAccess arrayAccess' arrayIndex) (Just baseIndex) (ArrayType arraySize baseType) statements = do
(indexPlace, statements') <- expression localTable arrayIndex
2024-08-30 14:55:40 +02:00
resultVariable <- createTemporary
let resultOperand = VariableOperand resultVariable
2024-08-15 20:13:56 +02:00
indexCalculation = Vector.fromList
[ ProductQuadruple (IntOperand $ fromIntegral arraySize) baseIndex resultVariable
, AddQuadruple indexPlace resultOperand resultVariable
]
in variableAccess localTable arrayAccess' (Just resultOperand) baseType
$ statements <> indexCalculation <> statements'
variableAccess _ _ _ _ _ = error "Array access operator doesn't match the type."
2024-11-06 22:23:49 +01:00
-}
2024-08-15 20:13:56 +02:00
variableType :: AST.VariableAccess -> SymbolTable -> Type
variableType (AST.VariableAccess identifier) symbolTable
| Just (TypeInfo type') <- SymbolTable.lookup identifier symbolTable = type'
| otherwise = error "Undefined type."
2024-11-06 22:23:49 +01:00
{-variableType (AST.ArrayAccess arrayAccess' _) symbolTable =
variableType arrayAccess' symbolTable -}
2024-10-02 22:56:15 +02:00
expression :: SymbolTable -> AST.Expression -> Glue (Operand Variable, Vector (Quadruple Variable))
2024-09-29 19:50:55 +02:00
expression localTable = \case
2024-09-25 23:06:02 +02:00
(AST.LiteralExpression literal') -> pure (literal literal', mempty)
2024-09-29 19:50:55 +02:00
(AST.SumExpression lhs rhs) -> binaryExpression AddQuadruple lhs rhs
(AST.SubtractionExpression lhs rhs) ->
binaryExpression SubtractionQuadruple lhs rhs
2024-10-02 22:56:15 +02:00
(AST.NegationExpression negation) -> do
(operand, statements) <- expression localTable negation
tempVariable <- createTemporary
let negationQuadruple = NegationQuadruple operand tempVariable
pure
( VariableOperand tempVariable
, Vector.snoc statements negationQuadruple
)
2024-10-04 18:26:10 +02:00
(AST.ProductExpression lhs rhs) ->
binaryExpression ProductQuadruple lhs rhs
2024-10-06 18:07:57 +02:00
(AST.DivisionExpression lhs rhs) ->
binaryExpression DivisionQuadruple lhs rhs
2024-11-06 22:23:49 +01:00
(AST.VariableExpression variableExpression) -> do
let variableType' = variableType variableExpression localTable
variableAccess' <- variableAccess localTable variableExpression Nothing variableType' mempty
case variableAccess' of
(identifier, _Nothing, statements)
-> (, statements) . VariableOperand
<$> lookupLocal identifier
{-(AST.Identifier identifier, Just operand, statements) -> do
2024-08-30 14:55:40 +02:00
arrayAddress <- createTemporary
let arrayStatement = ArrayQuadruple (Variable identifier) operand arrayAddress
pure
( VariableOperand arrayAddress
, Vector.snoc statements arrayStatement
2024-10-06 18:07:57 +02:00
) -}
2024-08-15 20:13:56 +02:00
where
binaryExpression f lhs rhs = do
(lhsOperand, lhsStatements) <- expression localTable lhs
(rhsOperand, rhsStatements) <- expression localTable rhs
2024-08-30 14:55:40 +02:00
tempVariable <- createTemporary
let newQuadruple = f lhsOperand rhsOperand tempVariable
pure
( VariableOperand tempVariable
, Vector.snoc (lhsStatements <> rhsStatements) newQuadruple
)
2024-08-15 20:13:56 +02:00
2024-10-01 00:02:19 +02:00
literal :: AST.Literal -> Operand Variable
literal (AST.DecimalLiteral integer) = IntOperand integer
2024-10-04 18:26:10 +02:00
literal (AST.HexadecimalLiteral integer) = IntOperand integer
2024-08-15 20:13:56 +02:00
literal (AST.CharacterLiteral character) = IntOperand $ fromIntegral character