packages feed

jni-0.8.0: src/common/Foreign/JNI/Internal.hs

{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module Foreign.JNI.Internal where

import Data.Text (Text)
import qualified Data.Text as Text
import qualified Foreign.JNI.String as JNI

-- | A reference type name is not just any 'JNI.String', but a fully qualified
-- identifier well-formed by construction.
newtype ReferenceTypeName = ReferenceTypeName JNI.String
  deriving (Eq, Ord)

instance Show ReferenceTypeName where
  show (ReferenceTypeName str) = show str

-- | A string representing a signature, well-formed by construction.
newtype Signature = Signature JNI.String
  deriving (Eq, Ord)

instance Show Signature where
  show (Signature str) = show str

-- | A string representing a method signature, well-formed by construction.
newtype MethodSignature = MethodSignature JNI.String
  deriving (Eq, Ord)

instance Show MethodSignature where
  show (MethodSignature str) = show str

jniMethodToJavaSignature :: Text -> Either String ([Text], Text)
jniMethodToJavaSignature sig = do
    (argTypes, rest1) <- dropChar '(' sig >>= many toJavaType
    (returnType, rest2) <- dropChar ')' rest1 >>= toJavaType
    if Text.null rest2 then return (argTypes, returnType)
    else Left $ "Unexpected suffix " ++ show rest2
  where
    dropChar c t = case Text.uncons t of
      Just (c', t') | c == c' -> Right t'
      _ -> Left $ unwords
              [ "Expected ", show c, "but found", show t]
    many p = go id
      where
        go acc t = case p t of
          Left _ -> Right (acc [], t)
          Right (x, t') -> go (acc . (x:)) t'
    toJavaType t = case Text.uncons t of
      Just (c, t') ->
        case c of
          'L' -> case Text.breakOn ";" t' of
            (jtype, rest) -> Right (Text.map substSlash jtype, Text.drop 1 rest)
          '[' ->
            fmap (\(jtype, rest) -> (jtype <> "[]", rest)) (toJavaType t')
          'Z' -> Right ("boolean", t')
          'B' -> Right ("byte", t')
          'C' -> Right ("char", t')
          'S' -> Right ("short", t')
          'I' -> Right ("int", t')
          'J' -> Right ("long", t')
          'F' -> Right ("float", t')
          'D' -> Right ("double", t')
          'V' -> Right ("void", t')
          _ -> Left $ "Unexpected char " ++ show c ++ " at " ++ show t'
      Nothing ->
        Left "Unexpected empty text"
    substSlash = \case
      '/' -> '.'
      c -> c