module Compiler.ASM.AstToAsm
( astIntToAsm
, astBoolToAsm
, astSymbolToAsm
, astListToAsm
, astCallToAsm
, builtinMap
) where
import Control.Monad.State (get, lift)
import Data.Text (Text, pack)
import qualified Data.Map.Strict as Map
import Compiler.ASM.Builtins (builtinMap)
import Compiler.ASM.CompilerMonad
( CompilerMonad
, emitInstruction
, emitCallToLabel
, lookupSymbol
)
import Compiler.CompilerState (CompilerState(..), ScopeType(..))
import Compiler.Instruction (Instruction(..), Immediate(..))
import Common.Type.Integer (IntValue(..))
import AST.Ast (Ast(..))
astIntToAsm :: IntValue -> CompilerMonad ()
astIntToAsm :: IntValue -> CompilerMonad ()
astIntToAsm IntValue
v = Instruction -> CompilerMonad ()
emitInstruction (Immediate -> Instruction
Push (IntValue -> Immediate
ImmInt IntValue
v))
astBoolToAsm :: Bool -> CompilerMonad ()
astBoolToAsm :: Bool -> CompilerMonad ()
astBoolToAsm Bool
b = Instruction -> CompilerMonad ()
emitInstruction (Immediate -> Instruction
Push (Bool -> Immediate
ImmBool Bool
b))
astSymbolToAsm :: Text -> CompilerMonad ()
astSymbolToAsm :: Text -> CompilerMonad ()
astSymbolToAsm Text
name = do
currentState <- StateT CompilerState (Either Text) CompilerState
forall s (m :: * -> *). MonadState s m => m s
get
case Map.lookup name (csSymbols currentState) of
Just (ScopeType
ScopeGlobal, Int
idx, Text
_) -> Instruction -> CompilerMonad ()
emitInstruction (Int -> Instruction
LoadGlobal Int
idx)
Just (ScopeType
ScopeLocal, Int
idx, Text
_) -> Instruction -> CompilerMonad ()
emitInstruction (Int -> Instruction
LoadLocal Int
idx)
Just (ScopeType
ScopeCapture, Int
idx, Text
_) -> Instruction -> CompilerMonad ()
emitInstruction (Int -> Instruction
LoadCapture Int
idx)
Maybe (ScopeType, Int, Text)
Nothing -> Either Text () -> CompilerMonad ()
forall (m :: * -> *) a. Monad m => m a -> StateT CompilerState m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Either Text () -> CompilerMonad ())
-> Either Text () -> CompilerMonad ()
forall a b. (a -> b) -> a -> b
$ Text -> Either Text ()
forall a b. a -> Either a b
Left (String -> Text
pack String
"Undefined symbol: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
name)
astListToAsm :: (Ast -> CompilerMonad ()) -> [Ast] -> CompilerMonad ()
astListToAsm :: (Ast -> CompilerMonad ()) -> [Ast] -> CompilerMonad ()
astListToAsm Ast -> CompilerMonad ()
compileFn [Ast]
elements = (Ast -> CompilerMonad ()) -> [Ast] -> CompilerMonad ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Ast -> CompilerMonad ()
compileFn [Ast]
elements CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Instruction -> CompilerMonad ()
emitInstruction (Int -> Instruction
BuildList ([Ast] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Ast]
elements))
astCallToAsm :: (Ast -> CompilerMonad ()) -> Ast -> [Ast] -> CompilerMonad ()
astCallToAsm :: (Ast -> CompilerMonad ()) -> Ast -> [Ast] -> CompilerMonad ()
astCallToAsm Ast -> CompilerMonad ()
compileFn (ASymbol Text
name) [Ast
a, Ast
b] | Text
name Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
pack String
">" =
Ast -> CompilerMonad ()
compileFn Ast
b CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Ast -> CompilerMonad ()
compileFn Ast
a CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Instruction -> CompilerMonad ()
emitInstruction Instruction
Lt
astCallToAsm Ast -> CompilerMonad ()
compileFn (ASymbol Text
name) [Ast
a, Ast
b] | Text
name Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
pack String
">=" =
Ast -> CompilerMonad ()
compileFn Ast
b CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Ast -> CompilerMonad ()
compileFn Ast
a CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Instruction -> CompilerMonad ()
emitInstruction Instruction
Le
astCallToAsm Ast -> CompilerMonad ()
compileFn (ASymbol Text
name) [Ast
a, Ast
b] | Text
name Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
pack String
"neq?" =
Ast -> CompilerMonad ()
compileFn Ast
a CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Ast -> CompilerMonad ()
compileFn Ast
b CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Instruction -> CompilerMonad ()
emitInstruction Instruction
Eq CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Instruction -> CompilerMonad ()
emitInstruction Instruction
Not
astCallToAsm Ast -> CompilerMonad ()
compileFn (ASymbol Text
name) [Ast
a, Ast
b] | Text
name Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
pack String
"tneq?" =
Ast -> CompilerMonad ()
compileFn Ast
a CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Ast -> CompilerMonad ()
compileFn Ast
b CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Instruction -> CompilerMonad ()
emitInstruction Instruction
TEq CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Instruction -> CompilerMonad ()
emitInstruction Instruction
Not
astCallToAsm Ast -> CompilerMonad ()
compileFn (ASymbol Text
name) [Ast]
args = case Text -> Map Text Instruction -> Maybe Instruction
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Text
name Map Text Instruction
builtinMap of
Just Instruction
instr -> (Ast -> CompilerMonad ()) -> [Ast] -> CompilerMonad ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Ast -> CompilerMonad ()
compileFn [Ast]
args CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Instruction -> CompilerMonad ()
emitInstruction Instruction
instr
Maybe Instruction
Nothing -> do
sym <- Text -> CompilerMonad (Maybe (ScopeType, Int, Text))
lookupSymbol Text
name
case sym of
Just (ScopeType, Int, Text)
_ -> (Ast -> CompilerMonad ()) -> [Ast] -> CompilerMonad ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Ast -> CompilerMonad ()
compileFn [Ast]
args CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Ast -> CompilerMonad ()
compileFn (Text -> Ast
ASymbol Text
name) CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Instruction -> CompilerMonad ()
emitInstruction Instruction
CallIndirect
Maybe (ScopeType, Int, Text)
Nothing -> (Ast -> CompilerMonad ()) -> [Ast] -> CompilerMonad ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Ast -> CompilerMonad ()
compileFn [Ast]
args CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Text -> CompilerMonad ()
emitCallToLabel (String -> Text
pack String
"fun_" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
name)
astCallToAsm Ast -> CompilerMonad ()
_ (AInteger IntValue
_) [Ast]
_ =
Either Text () -> CompilerMonad ()
forall (m :: * -> *) a. Monad m => m a -> StateT CompilerState m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Either Text () -> CompilerMonad ())
-> Either Text () -> CompilerMonad ()
forall a b. (a -> b) -> a -> b
$ Text -> Either Text ()
forall a b. a -> Either a b
Left (String -> Text
pack String
"Error: Cannot call an Integer")
astCallToAsm Ast -> CompilerMonad ()
_ (ABool Bool
_) [Ast]
_ =
Either Text () -> CompilerMonad ()
forall (m :: * -> *) a. Monad m => m a -> StateT CompilerState m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Either Text () -> CompilerMonad ())
-> Either Text () -> CompilerMonad ()
forall a b. (a -> b) -> a -> b
$ Text -> Either Text ()
forall a b. a -> Either a b
Left (String -> Text
pack String
"Error: Cannot call a Boolean")
astCallToAsm Ast -> CompilerMonad ()
_ Ast
AVoid [Ast]
_ =
Either Text () -> CompilerMonad ()
forall (m :: * -> *) a. Monad m => m a -> StateT CompilerState m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Either Text () -> CompilerMonad ())
-> Either Text () -> CompilerMonad ()
forall a b. (a -> b) -> a -> b
$ Text -> Either Text ()
forall a b. a -> Either a b
Left (String -> Text
pack String
"Error: Cannot call Void")
astCallToAsm Ast -> CompilerMonad ()
compileFn Ast
expr [Ast]
args =
(Ast -> CompilerMonad ()) -> [Ast] -> CompilerMonad ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Ast -> CompilerMonad ()
compileFn [Ast]
args CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Ast -> CompilerMonad ()
compileFn Ast
expr CompilerMonad () -> CompilerMonad () -> CompilerMonad ()
forall a b.
StateT CompilerState (Either Text) a
-> StateT CompilerState (Either Text) b
-> StateT CompilerState (Either Text) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Instruction -> CompilerMonad ()
emitInstruction Instruction
CallIndirect