{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wno-missing-signatures #-}
module Wrench.Translator.Parser.Misc (
literal,
byteLiteral,
intLiteral,
wordLiteral,
name,
labelRef,
comment,
comma,
nothing,
eol',
label,
reference,
referenceWithDirective,
referenceWithFn,
constantRef,
SectionItem (..),
orgDirective,
sectionItems,
sectionOrg,
) where
import Data.Bits
import Data.Text qualified as T
import Relude
import Relude.Unsafe as Unsafe
import Text.Megaparsec (
SourcePos,
anySingle,
anySingleBut,
choice,
getOffset,
getSourcePos,
manyTill,
setOffset,
single,
try,
)
import Text.Megaparsec.Char (
char,
digitChar,
eol,
hexDigitChar,
hspace,
hspace1,
letterChar,
string,
)
import Wrench.Machine.Word (fitSigned)
import Wrench.Translator.Parser.Types
import Wrench.Translator.Types
data SectionItem i = Item i | Org Int
sectionItems :: [SectionItem i] -> [i]
sectionItems :: forall i. [SectionItem i] -> [i]
sectionItems = (SectionItem i -> Maybe i) -> [SectionItem i] -> [i]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe ((SectionItem i -> Maybe i) -> [SectionItem i] -> [i])
-> (SectionItem i -> Maybe i) -> [SectionItem i] -> [i]
forall a b. (a -> b) -> a -> b
$ \case
Item i
i -> i -> Maybe i
forall a. a -> Maybe a
Just i
i
Org Int
_ -> Maybe i
forall a. Maybe a
Nothing
sectionOrg :: [SectionItem i] -> Maybe Int
sectionOrg :: forall i. [SectionItem i] -> Maybe Int
sectionOrg [SectionItem i]
items =
case [Int
i | Org Int
i <- [SectionItem i]
items] of
[] -> Maybe Int
forall a. Maybe a
Nothing
[Int
x] -> Int -> Maybe Int
forall a. a -> Maybe a
Just Int
x
(Int
_ : Int
_ : [Int]
_) -> Text -> Maybe Int
forall a t. (HasCallStack, IsText t) => t -> a
error Text
"error: multiple .org directives not allowed"
orgDirective :: String -> Parser Int
orgDirective :: String -> Parser Int
orgDirective String
cstart = do
ParsecT Void String Identity (Tokens String)
-> ParsecT Void String Identity ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT Void String Identity (Tokens String)
-> ParsecT Void String Identity ())
-> ParsecT Void String Identity (Tokens String)
-> ParsecT Void String Identity ()
forall a b. (a -> b) -> a -> b
$ Tokens String -> ParsecT Void String Identity (Tokens String)
forall e s (m :: * -> *).
MonadParsec e s m =>
Tokens s -> m (Tokens s)
string Tokens String
".org"
ParsecT Void String Identity ()
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m ()
hspace1
value <- Parser Int
intLiteral
eol' cstart
return value
removeUnderscores :: String -> String
removeUnderscores :: String -> String
removeUnderscores = Text -> String
forall a. ToString a => a -> String
toString (Text -> String) -> (String -> Text) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HasCallStack => Text -> Text -> Text -> Text
Text -> Text -> Text -> Text
T.replace Text
"_" Text
"" (Text -> Text) -> (String -> Text) -> String -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
forall a. ToText a => a -> Text
toText
num :: Parser String
num :: Parser String
num = do
s <-
[Parser String] -> Parser String
forall (f :: * -> *) (m :: * -> *) a.
(Foldable f, Alternative m) =>
f (m a) -> m a
choice
[ Parser String -> Parser String
forall a.
ParsecT Void String Identity a -> ParsecT Void String Identity a
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try (Parser String -> Parser String) -> Parser String -> Parser String
forall a b. (a -> b) -> a -> b
$ Token String -> ParsecT Void String Identity (Token String)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token String
'-' ParsecT Void String Identity Char -> Parser String -> Parser String
forall a b.
ParsecT Void String Identity a
-> ParsecT Void String Identity b -> ParsecT Void String Identity b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Parser String
decDigits Parser String -> (String -> String) -> Parser String
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> (:) Char
'-'
, Parser String
decDigits
]
return $ removeUnderscores s
where
decDigits :: Parser String
decDigits = (:) (Char -> String -> String)
-> ParsecT Void String Identity Char
-> ParsecT Void String Identity (String -> String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Void String Identity Char
ParsecT Void String Identity (Token String)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Token s)
digitChar ParsecT Void String Identity (String -> String)
-> Parser String -> Parser String
forall a b.
ParsecT Void String Identity (a -> b)
-> ParsecT Void String Identity a -> ParsecT Void String Identity b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ParsecT Void String Identity Char -> Parser String
forall a.
ParsecT Void String Identity a -> ParsecT Void String Identity [a]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (ParsecT Void String Identity Char
ParsecT Void String Identity (Token String)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Token s)
digitChar ParsecT Void String Identity Char
-> ParsecT Void String Identity Char
-> ParsecT Void String Identity Char
forall a.
ParsecT Void String Identity a
-> ParsecT Void String Identity a -> ParsecT Void String Identity a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Token String -> ParsecT Void String Identity (Token String)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token String
'_')
hexNum :: Parser String
hexNum :: Parser String
hexNum = Parser String -> Parser String
forall a.
ParsecT Void String Identity a -> ParsecT Void String Identity a
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try (Parser String -> Parser String) -> Parser String -> Parser String
forall a b. (a -> b) -> a -> b
$ do
ParsecT Void String Identity (Tokens String)
-> ParsecT Void String Identity ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT Void String Identity (Tokens String)
-> ParsecT Void String Identity ())
-> ParsecT Void String Identity (Tokens String)
-> ParsecT Void String Identity ()
forall a b. (a -> b) -> a -> b
$ Tokens String -> ParsecT Void String Identity (Tokens String)
forall e s (m :: * -> *).
MonadParsec e s m =>
Tokens s -> m (Tokens s)
string Tokens String
"0x"
ds <- (:) (Char -> String -> String)
-> ParsecT Void String Identity Char
-> ParsecT Void String Identity (String -> String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Void String Identity Char
ParsecT Void String Identity (Token String)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Token s)
hexDigitChar ParsecT Void String Identity (String -> String)
-> Parser String -> Parser String
forall a b.
ParsecT Void String Identity (a -> b)
-> ParsecT Void String Identity a -> ParsecT Void String Identity b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ParsecT Void String Identity Char -> Parser String
forall a.
ParsecT Void String Identity a -> ParsecT Void String Identity [a]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (ParsecT Void String Identity Char
ParsecT Void String Identity (Token String)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Token s)
hexDigitChar ParsecT Void String Identity Char
-> ParsecT Void String Identity Char
-> ParsecT Void String Identity Char
forall a.
ParsecT Void String Identity a
-> ParsecT Void String Identity a -> ParsecT Void String Identity a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Token String -> ParsecT Void String Identity (Token String)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token String
'_')
return $ "0x" <> removeUnderscores ds
literal :: Parser Integer
literal :: Parser Integer
literal = String -> Integer
forall a. Read a => String -> a
Unsafe.read (String -> Integer) -> Parser String -> Parser Integer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Parser String] -> Parser String
forall (f :: * -> *) (m :: * -> *) a.
(Foldable f, Alternative m) =>
f (m a) -> m a
choice [Parser String
hexNum, Parser String
num]
wordLiteral :: forall w. (IsWord w) => Parser w
wordLiteral :: forall w. IsWord w => Parser w
wordLiteral = Text -> Parser w
forall a. (FiniteBits a, Integral a) => Text -> Parser a
anyPattern (Text -> Parser w) -> Text -> Parser w
forall a b. (a -> b) -> a -> b
$ Text
"a " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall b a. (Show a, IsString b) => a -> b
show (w -> Int
forall b. FiniteBits b => b -> Int
finiteBitSize (w
forall a. Bits a => a
zeroBits :: w)) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"-bit machine word"
byteLiteral :: Parser Word8
byteLiteral :: Parser Word8
byteLiteral = Text -> Parser Word8
forall a. (FiniteBits a, Integral a) => Text -> Parser a
anyPattern Text
"a byte"
intLiteral :: Parser Int
intLiteral :: Parser Int
intLiteral = Text -> Integer -> Integer -> Parser Int
forall a. Integral a => Text -> Integer -> Integer -> Parser a
narrowed Text
"an Int" (Int -> Integer
forall a. Integral a => a -> Integer
toInteger (Int
forall a. Bounded a => a
minBound :: Int)) (Int -> Integer
forall a. Integral a => a -> Integer
toInteger (Int
forall a. Bounded a => a
maxBound :: Int))
anyPattern :: forall a. (FiniteBits a, Integral a) => Text -> Parser a
anyPattern :: forall a. (FiniteBits a, Integral a) => Text -> Parser a
anyPattern Text
what = Text -> Integer -> Integer -> Parser a
forall a. Integral a => Text -> Integer -> Integer -> Parser a
narrowed Text
what (Integer -> Integer
forall a. Num a => a -> a
negate (Int -> Integer
forall a. Bits a => Int -> a
bit (Int
width Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1))) (Int -> Integer
forall a. Bits a => Int -> a
bit Int
width Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
1)
where
width :: Int
width = a -> Int
forall b. FiniteBits b => b -> Int
finiteBitSize (a
forall a. Bits a => a
zeroBits :: a)
narrowed :: (Integral a) => Text -> Integer -> Integer -> Parser a
narrowed :: forall a. Integral a => Text -> Integer -> Integer -> Parser a
narrowed Text
what Integer
lo Integer
hi = do
literalPos <- Parser Int
forall e s (m :: * -> *). MonadParsec e s m => m Int
getOffset
value <- literal
if lo <= value && value <= hi
then return $ fromInteger value
else do
setOffset literalPos
fail $
concat
[ "literal "
, show value
, " doesn't fit "
, toString what
, ", expected "
, show lo
, ".."
, show hi
]
comma :: Parser ()
comma :: ParsecT Void String Identity ()
comma = ParsecT Void String Identity ()
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m ()
hspace ParsecT Void String Identity ()
-> ParsecT Void String Identity ()
-> ParsecT Void String Identity ()
forall a b.
ParsecT Void String Identity a
-> ParsecT Void String Identity b -> ParsecT Void String Identity b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ParsecT Void String Identity Char
-> ParsecT Void String Identity ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Token String -> ParsecT Void String Identity (Token String)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token String
',') ParsecT Void String Identity ()
-> ParsecT Void String Identity ()
-> ParsecT Void String Identity ()
forall a b.
ParsecT Void String Identity a
-> ParsecT Void String Identity b -> ParsecT Void String Identity b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ParsecT Void String Identity ()
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m ()
hspace
eol' :: String -> ParsecT Void String Identity ()
eol' String
cstart = ParsecT Void String Identity ()
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m ()
hspace ParsecT Void String Identity ()
-> ParsecT Void String Identity ()
-> ParsecT Void String Identity ()
forall a b.
ParsecT Void String Identity a
-> ParsecT Void String Identity b -> ParsecT Void String Identity b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Parser String -> ParsecT Void String Identity ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Parser String
ParsecT Void String Identity (Tokens String)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Tokens s)
eol Parser String -> Parser String -> Parser String
forall a.
ParsecT Void String Identity a
-> ParsecT Void String Identity a -> ParsecT Void String Identity a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> String -> Parser String
comment String
cstart)
name :: Parser Text
name :: Parser Text
name = do
x <- ParsecT Void String Identity Char
ParsecT Void String Identity (Token String)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Token s)
letterChar ParsecT Void String Identity Char
-> ParsecT Void String Identity Char
-> ParsecT Void String Identity Char
forall a.
ParsecT Void String Identity a
-> ParsecT Void String Identity a -> ParsecT Void String Identity a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Token String -> ParsecT Void String Identity (Token String)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token String
'_'
xs <- many (letterChar <|> digitChar <|> char '_')
return $ toText (x : xs)
comment :: String -> Parser String
String
cstart = do
ParsecT Void String Identity (Tokens String)
-> ParsecT Void String Identity ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT Void String Identity (Tokens String)
-> ParsecT Void String Identity ())
-> ParsecT Void String Identity (Tokens String)
-> ParsecT Void String Identity ()
forall a b. (a -> b) -> a -> b
$ Tokens String -> ParsecT Void String Identity (Tokens String)
forall e s (m :: * -> *).
MonadParsec e s m =>
Tokens s -> m (Tokens s)
string String
Tokens String
cstart
ParsecT Void String Identity Char
-> ParsecT Void String Identity (Tokens String) -> Parser String
forall (m :: * -> *) a end. MonadPlus m => m a -> m end -> m [a]
manyTill ParsecT Void String Identity Char
ParsecT Void String Identity (Token String)
forall e s (m :: * -> *). MonadParsec e s m => m (Token s)
anySingle ParsecT Void String Identity (Tokens String)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Tokens s)
eol
nothing :: (Monad m) => m a -> m (Maybe b)
nothing :: forall (m :: * -> *) a b. Monad m => m a -> m (Maybe b)
nothing m a
p = m a
p m a -> m (Maybe b) -> m (Maybe b)
forall a b. m a -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Maybe b -> m (Maybe b)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe b
forall a. Maybe a
Nothing
label :: Parser Text
label :: Parser Text
label = Parser Text -> Parser Text
forall a.
ParsecT Void String Identity a -> ParsecT Void String Identity a
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try (Parser Text -> Parser Text) -> Parser Text -> Parser Text
forall a b. (a -> b) -> a -> b
$ do
n <- Parser Text
name
void $ single ':'
return n
labelRef :: Parser Text
labelRef = Parser Text
name
referenceWithFn :: (IsWord w) => (w -> w) -> Parser (Ref w)
referenceWithFn :: forall w. IsWord w => (w -> w) -> Parser (Ref w)
referenceWithFn w -> w
f = do
pos <- ParsecT Void String Identity SourcePos
forall s e (m :: * -> *).
(TraversableStream s, MonadParsec e s m) =>
m SourcePos
getSourcePos
choice
[ constantAt f pos
, Ref f pos <$> labelRef
]
constantRef :: (IsWord w) => Parser (Ref w)
constantRef :: forall w. IsWord w => Parser (Ref w)
constantRef = ParsecT Void String Identity SourcePos
forall s e (m :: * -> *).
(TraversableStream s, MonadParsec e s m) =>
m SourcePos
getSourcePos ParsecT Void String Identity SourcePos
-> (SourcePos -> ParsecT Void String Identity (Ref w))
-> ParsecT Void String Identity (Ref w)
forall a b.
ParsecT Void String Identity a
-> (a -> ParsecT Void String Identity b)
-> ParsecT Void String Identity b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (w -> w) -> SourcePos -> ParsecT Void String Identity (Ref w)
forall w. IsWord w => (w -> w) -> SourcePos -> Parser (Ref w)
constantAt w -> w
forall a. a -> a
id
constantAt :: (IsWord w) => (w -> w) -> SourcePos -> Parser (Ref w)
constantAt :: forall w. IsWord w => (w -> w) -> SourcePos -> Parser (Ref w)
constantAt w -> w
f SourcePos
pos =
[ParsecT Void String Identity (Ref w)]
-> ParsecT Void String Identity (Ref w)
forall (f :: * -> *) (m :: * -> *) a.
(Foldable f, Alternative m) =>
f (m a) -> m a
choice
[ do
ParsecT Void String Identity (Token String)
-> ParsecT Void String Identity ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void ParsecT Void String Identity (Token String)
quote
c <- Token String -> ParsecT Void String Identity (Token String)
forall e s (m :: * -> *).
MonadParsec e s m =>
Token s -> m (Token s)
anySingleBut Char
Token String
'\''
void quote
return $ ValueR f pos $ fromIntegral $ ord c
, (w -> w) -> SourcePos -> w -> Ref w
forall w. (w -> w) -> SourcePos -> w -> Ref w
ValueR w -> w
f SourcePos
pos (w -> Ref w)
-> ParsecT Void String Identity w
-> ParsecT Void String Identity (Ref w)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Void String Identity w
forall w. IsWord w => Parser w
wordLiteral
]
where
quote :: ParsecT Void String Identity (Token String)
quote = Token String -> ParsecT Void String Identity (Token String)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token String
'\''
referenceWithDirective :: (IsWord w) => Parser (Ref w)
referenceWithDirective :: forall w. IsWord w => Parser (Ref w)
referenceWithDirective =
[ParsecT Void String Identity (Ref w)]
-> ParsecT Void String Identity (Ref w)
forall (f :: * -> *) (m :: * -> *) a.
(Foldable f, Alternative m) =>
f (m a) -> m a
choice
[ do
ParsecT Void String Identity (Tokens String)
-> ParsecT Void String Identity ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT Void String Identity (Tokens String)
-> ParsecT Void String Identity ())
-> ParsecT Void String Identity (Tokens String)
-> ParsecT Void String Identity ()
forall a b. (a -> b) -> a -> b
$ Tokens String -> ParsecT Void String Identity (Tokens String)
forall e s (m :: * -> *).
MonadParsec e s m =>
Tokens s -> m (Tokens s)
string Tokens String
"%hi("
ref <- (w -> w) -> ParsecT Void String Identity (Ref w)
forall w. IsWord w => (w -> w) -> Parser (Ref w)
referenceWithFn (\w
w -> ((w
w w -> w -> w
forall a. Num a => a -> a -> a
+ w
0x800) w -> Int -> w
forall a. Bits a => a -> Int -> a
`shiftR` Int
12) w -> w -> w
forall a. Bits a => a -> a -> a
.&. w
0xFFFFF)
void $ string ")"
return ref
, do
ParsecT Void String Identity (Tokens String)
-> ParsecT Void String Identity ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT Void String Identity (Tokens String)
-> ParsecT Void String Identity ())
-> ParsecT Void String Identity (Tokens String)
-> ParsecT Void String Identity ()
forall a b. (a -> b) -> a -> b
$ Tokens String -> ParsecT Void String Identity (Tokens String)
forall e s (m :: * -> *).
MonadParsec e s m =>
Tokens s -> m (Tokens s)
string Tokens String
"%lo("
ref <- (w -> w) -> ParsecT Void String Identity (Ref w)
forall w. IsWord w => (w -> w) -> Parser (Ref w)
referenceWithFn (Int -> w -> w
forall w. IsWord w => Int -> w -> w
fitSigned Int
12)
void $ string ")"
return ref
, ParsecT Void String Identity (Ref w)
forall w. IsWord w => Parser (Ref w)
reference
]
reference :: (IsWord w) => Parser (Ref w)
reference :: forall w. IsWord w => Parser (Ref w)
reference = (w -> w) -> Parser (Ref w)
forall w. IsWord w => (w -> w) -> Parser (Ref w)
referenceWithFn w -> w
forall a. a -> a
id