elna/lib/Language/Elna/Intermediate.hs

316 lines
13 KiB
Haskell
Raw Normal View History

2024-08-12 21:00:52 +02:00
module Language.Elna.Intermediate
2024-09-25 23:06:02 +02:00
( Operand(..)
, Quadruple(..)
2024-09-08 02:08:13 +02:00
{- , Label(..)
, Variable(..) -}
2024-08-15 20:13:56 +02:00
, intermediate
2024-08-12 21:00:52 +02:00
) where
2024-08-18 20:13:59 +02:00
import Data.Bifunctor (Bifunctor(..))
2024-08-15 20:13:56 +02:00
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
2024-09-25 23:06:02 +02:00
import Data.Vector (Vector)
import qualified Data.Vector as Vector
import Data.Int (Int32)
2024-08-15 20:13:56 +02:00
import Data.Word (Word32)
2024-09-25 23:06:02 +02:00
import Data.Text (Text)
import qualified Language.Elna.AST as AST
import Language.Elna.SymbolTable (SymbolTable{-, Info(..) -})
import Data.Foldable (Foldable(..))
import Control.Monad.Trans.State (State, runState)
import Data.Maybe (catMaybes)
2024-08-12 21:00:52 +02:00
2024-09-25 23:06:02 +02:00
newtype Operand
= IntOperand Int32
-- | VariableOperand Variable
2024-08-12 21:00:52 +02:00
deriving (Eq, Show)
data Quadruple
= StartQuadruple
2024-09-25 23:06:02 +02:00
| StopQuadruple
| ParameterQuadruple Operand
| CallQuadruple Text Word32
{-| GoToQuadruple Label
2024-08-12 21:00:52 +02:00
| AssignQuadruple Operand Variable
2024-08-15 20:13:56 +02:00
| ArrayQuadruple Variable Operand Variable
2024-08-17 14:16:16 +02:00
| ArrayAssignQuadruple Operand Operand Variable
2024-08-12 21:00:52 +02:00
| AddQuadruple Operand Operand Variable
| SubtractionQuadruple Operand Operand Variable
| ProductQuadruple Operand Operand Variable
| DivisionQuadruple Operand Operand Variable
| NegationQuadruple Operand Variable
| EqualQuadruple Operand Operand Label
| NonEqualQuadruple Operand Operand Label
| LessQuadruple Operand Operand Label
| GreaterQuadruple Operand Operand Label
| LessOrEqualQuadruple Operand Operand Label
| GreaterOrEqualQuadruple Operand Operand Label
2024-09-25 23:06:02 +02:00
| LabelQuadruple Label -}
2024-08-12 21:00:52 +02:00
deriving (Eq, Show)
2024-08-15 20:13:56 +02:00
2024-09-25 23:06:02 +02:00
newtype Intermediate a = Intermediate
{ runIntermediate :: State Word32 a }
instance Functor Intermediate
where
2024-09-25 23:06:02 +02:00
fmap f (Intermediate x) = Intermediate $ f <$> x
2024-09-25 23:06:02 +02:00
instance Applicative Intermediate
2024-08-30 14:55:40 +02:00
where
2024-09-25 23:06:02 +02:00
pure = Intermediate . pure
(Intermediate f) <*> (Intermediate x) = Intermediate $ f <*> x
instance Monad Intermediate
where
(Intermediate x) >>= f = Intermediate $ x >>= (runIntermediate . f)
intermediate :: SymbolTable -> AST.Program -> HashMap AST.Identifier (Vector Quadruple)
intermediate globalTable
= fst
. flip runState 0
. runIntermediate
. program globalTable
2024-08-30 14:55:40 +02:00
program
:: SymbolTable
-> AST.Program
-> Intermediate (HashMap AST.Identifier (Vector Quadruple))
2024-09-25 23:06:02 +02:00
program globalTable (AST.Program declarations) = HashMap.fromList . catMaybes
<$> traverse (declaration globalTable) declarations
declaration
:: SymbolTable
-> AST.Declaration
-> Intermediate (Maybe (AST.Identifier, Vector Quadruple))
declaration globalTable (AST.ProcedureDeclaration procedureName _ _ statements)
= Just
. (procedureName,)
. Vector.cons StartQuadruple
. flip Vector.snoc StopQuadruple
. fold
<$> traverse (statement globalTable) statements
-- declaration (AST.TypeDefinition _ _) accumulator = pure accumulator
statement :: SymbolTable -> AST.Statement -> Intermediate (Vector Quadruple)
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
$ Vector.length argumentStatements
{- statement localTable (AST.AssignmentStatement variableAccess' assignee) = do
(rhsOperand, rhsStatements) <- expression localTable assignee
let variableType' = variableType variableAccess' localTable
accessResult <- variableAccess localTable variableAccess' Nothing variableType' mempty
pure $ rhsStatements <> case accessResult of
2024-08-17 14:16:16 +02:00
(AST.Identifier identifier, Just accumulatedIndex, accumulatedStatements) ->
Vector.snoc accumulatedStatements
$ ArrayAssignQuadruple rhsOperand accumulatedIndex
$ Variable identifier
(AST.Identifier identifier, Nothing, accumulatedStatements) ->
Vector.snoc accumulatedStatements
$ AssignQuadruple rhsOperand
$ Variable identifier
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
2024-08-17 14:16:16 +02:00
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)
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
<> Vector.fromList [GoToQuadruple conditionLabel, LabelQuadruple endLabel]
2024-08-17 14:16:16 +02:00
statement localTable (AST.CompoundStatement statements) =
2024-09-25 23:06:02 +02:00
fold <$> traverse (statement localTable) statements -}
{-
import Language.Elna.Types (Type(..))
import qualified Language.Elna.SymbolTable as SymbolTable
import GHC.Records (HasField(..))
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
newtype Label = Label Text
deriving Eq
instance Show Label
where
show (Label label) = '.' : Text.unpack label
createLabel :: Intermediate Label
createLabel = do
currentCounter <- Intermediate $ gets labelCounter
Intermediate $ modify' modifier
pure
$ Label
$ Text.Lazy.toStrict
$ Text.Builder.toLazyText
$ Text.Builder.decimal currentCounter
where
modifier generator = generator
{ labelCounter = getField @"labelCounter" generator + 1
}
createTemporary :: Intermediate Variable
createTemporary = do
currentCounter <- Intermediate $ gets temporaryCounter
Intermediate $ modify' modifier
pure $ TempVariable currentCounter
where
modifier generator = generator
{ temporaryCounter = getField @"temporaryCounter" generator + 1
}
condition
:: SymbolTable
-> AST.Condition
-> Intermediate (Vector Quadruple, Label -> Quadruple)
condition localTable (AST.EqualCondition lhs rhs) = do
(lhsOperand, lhsStatements) <- expression localTable lhs
(rhsOperand, rhsStatements) <- expression localTable rhs
pure
( lhsStatements <> rhsStatements
, EqualQuadruple lhsOperand rhsOperand
)
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
-> Maybe Operand
-> Type
-> Vector Quadruple
-> Intermediate (AST.Identifier, Maybe Operand, Vector Quadruple)
2024-08-15 20:13:56 +02:00
variableAccess _ (AST.VariableAccess identifier) accumulatedIndex _ accumulatedStatements =
pure (identifier, accumulatedIndex, accumulatedStatements)
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."
variableType :: AST.VariableAccess -> SymbolTable -> Type
variableType (AST.VariableAccess identifier) symbolTable
| Just (TypeInfo type') <- SymbolTable.lookup identifier symbolTable = type'
| otherwise = error "Undefined type."
variableType (AST.ArrayAccess arrayAccess' _) symbolTable =
variableType arrayAccess' symbolTable
2024-09-25 23:06:02 +02:00
-}
expression :: SymbolTable -> AST.Expression -> Intermediate (Operand, Vector Quadruple)
2024-09-25 23:06:02 +02:00
expression _localTable = \case
(AST.LiteralExpression literal') -> pure (literal literal', mempty)
{- (AST.VariableExpression variableExpression) -> do
2024-08-15 20:13:56 +02:00
let variableType' = variableType variableExpression localTable
variableAccess' <- variableAccess localTable variableExpression Nothing variableType' mempty
case variableAccess' of
2024-08-15 20:13:56 +02:00
(AST.Identifier identifier, Nothing, statements) ->
pure (VariableOperand (Variable identifier), statements)
2024-08-30 14:55:40 +02:00
(AST.Identifier identifier, Just operand, statements) -> do
arrayAddress <- createTemporary
let arrayStatement = ArrayQuadruple (Variable identifier) operand arrayAddress
pure
( VariableOperand arrayAddress
, Vector.snoc statements arrayStatement
)
(AST.NegationExpression negation) -> do
(operand, statements) <- expression localTable negation
2024-08-30 14:55:40 +02:00
tempVariable <- createTemporary
let negationQuadruple = NegationQuadruple operand tempVariable
pure
( VariableOperand tempVariable
, Vector.snoc statements negationQuadruple
)
2024-08-15 20:13:56 +02:00
(AST.SumExpression lhs rhs) -> binaryExpression AddQuadruple lhs rhs
(AST.SubtractionExpression lhs rhs) ->
binaryExpression SubtractionQuadruple lhs rhs
(AST.ProductExpression lhs rhs) ->
binaryExpression ProductQuadruple lhs rhs
(AST.DivisionExpression lhs rhs) ->
binaryExpression DivisionQuadruple lhs rhs
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-09-25 23:06:02 +02:00
data Variable = Variable Text | TempVariable Int32
deriving Eq
instance Show Variable
where
show (Variable variable) = '$' : Text.unpack variable
show (TempVariable variable) = '$' : show variable
-}
2024-08-15 20:13:56 +02:00
literal :: AST.Literal -> Operand
literal (AST.IntegerLiteral integer) = IntOperand integer
2024-09-25 23:06:02 +02:00
{-literal (AST.HexadecimalLiteral integer) = IntOperand integer
2024-08-15 20:13:56 +02:00
literal (AST.CharacterLiteral character) = IntOperand $ fromIntegral character
literal (AST.BooleanLiteral boolean)
| boolean = IntOperand 1
2024-09-25 23:06:02 +02:00
| otherwise = IntOperand 0 -}