mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			112 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			112 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
module Data.Foreign
 | 
						|
  ( Foreign(..)
 | 
						|
  , ForeignParser(ForeignParser)
 | 
						|
  , parseForeign
 | 
						|
  , parseJSON
 | 
						|
  , ReadForeign
 | 
						|
  , read
 | 
						|
  , prop
 | 
						|
  ) where
 | 
						|
 | 
						|
import Prelude
 | 
						|
import Data.Array
 | 
						|
import Data.Either
 | 
						|
import Data.Maybe
 | 
						|
import Data.Tuple
 | 
						|
import Data.Traversable
 | 
						|
 | 
						|
foreign import data Foreign :: *
 | 
						|
 | 
						|
foreign import fromString
 | 
						|
  "function fromString (str) { \
 | 
						|
  \  try { \
 | 
						|
  \    return _ps.Data_Either.Right(JSON.parse(str)); \
 | 
						|
  \  } catch (e) { \
 | 
						|
  \    return _ps.Data_Either.Left(e.toString()); \
 | 
						|
  \  } \
 | 
						|
  \}" :: String -> Either String Foreign
 | 
						|
 | 
						|
foreign import readPrimType
 | 
						|
  "function readPrimType (typeName) { \
 | 
						|
  \  return function (value) { \
 | 
						|
  \    if (toString.call(value) == '[object ' + typeName + ']') { \
 | 
						|
  \      return _ps.Data_Either.Right(value);\
 | 
						|
  \    } \
 | 
						|
  \    return _ps.Data_Either.Left('Value is not a ' + typeName + ''); \
 | 
						|
  \  }; \
 | 
						|
  \}" :: forall a. String -> Foreign -> Either String a
 | 
						|
 | 
						|
foreign import readMaybeImpl
 | 
						|
  "function readMaybeImpl (value) { \
 | 
						|
  \  return value === undefined || value === null ? _ps.Data_Maybe.Nothing : _ps.Data_Maybe.Just(value); \
 | 
						|
  \}" :: forall a. Foreign -> Maybe Foreign
 | 
						|
 | 
						|
foreign import readPropImpl
 | 
						|
  "function readPropImpl (k) { \
 | 
						|
  \  return function (obj) { \
 | 
						|
  \    return _ps.Data_Either.Right(obj[k]);\
 | 
						|
  \  }; \
 | 
						|
  \}" :: forall a. String -> Foreign -> Either String Foreign
 | 
						|
 | 
						|
foreign import showForeignImpl
 | 
						|
  "var showForeignImpl = JSON.stringify;" :: Foreign -> String
 | 
						|
 | 
						|
instance showForeign :: Prelude.Show Foreign where
 | 
						|
  show = showForeignImpl
 | 
						|
 | 
						|
data ForeignParser a = ForeignParser (Foreign -> Either String a)
 | 
						|
 | 
						|
parseForeign :: forall a. ForeignParser a -> Foreign -> Either String a
 | 
						|
parseForeign (ForeignParser p) x = p x
 | 
						|
 | 
						|
parseJSON :: forall a. (ReadForeign a) => String -> Either String a
 | 
						|
parseJSON json = fromString json >>= parseForeign read
 | 
						|
 | 
						|
instance monadForeignParser :: Prelude.Monad ForeignParser where
 | 
						|
  return x = ForeignParser \_ -> Right x
 | 
						|
  (>>=) (ForeignParser p) f = ForeignParser \x -> case p x of
 | 
						|
      Left err -> Left err
 | 
						|
      Right x' -> parseForeign (f x') x
 | 
						|
 | 
						|
instance applicativeForeignParser :: Prelude.Applicative ForeignParser where
 | 
						|
  pure x = ForeignParser \_ -> Right x
 | 
						|
  (<*>) (ForeignParser f) (ForeignParser p) = ForeignParser \x -> case f x of
 | 
						|
      Left err -> Left err
 | 
						|
      Right f' -> f' <$> p x
 | 
						|
 | 
						|
instance functorForeignParser :: Prelude.Functor ForeignParser where
 | 
						|
  (<$>) f (ForeignParser p) = ForeignParser \x -> f <$> p x
 | 
						|
 | 
						|
class ReadForeign a where
 | 
						|
  read :: ForeignParser a
 | 
						|
 | 
						|
instance readString :: ReadForeign String where
 | 
						|
  read = ForeignParser $ readPrimType "String"
 | 
						|
 | 
						|
instance readNumber :: ReadForeign Number where
 | 
						|
  read = ForeignParser $ readPrimType "Number"
 | 
						|
 | 
						|
instance readBoolean :: ReadForeign Boolean where
 | 
						|
  read = ForeignParser $ readPrimType "Boolean"
 | 
						|
 | 
						|
instance readArray :: (ReadForeign a) => ReadForeign [a] where
 | 
						|
  read =
 | 
						|
    let arrayItem (Tuple i x) = case parseForeign read x of
 | 
						|
      Right result -> Right result
 | 
						|
      Left err -> Left $ "Error reading item at index " ++ (show i) ++ ":\n" ++ err
 | 
						|
    in
 | 
						|
    (ForeignParser $ readPrimType "Array") >>= \xs -> 
 | 
						|
      ForeignParser \_ -> arrayItem `traverse` (zip (range 0 (length xs)) xs)
 | 
						|
 | 
						|
instance readMaybe :: (ReadForeign a) => ReadForeign (Maybe a) where
 | 
						|
  read = (ForeignParser $ Right <<< readMaybeImpl) >>= \x -> 
 | 
						|
    ForeignParser \_ -> case x of
 | 
						|
      Just x' -> parseForeign read x' >>= return <<< Just
 | 
						|
      Nothing -> return Nothing
 | 
						|
 | 
						|
prop :: forall a. (ReadForeign a) => String -> ForeignParser a
 | 
						|
prop p = (ForeignParser \x -> readPropImpl p x) >>= \x -> 
 | 
						|
  ForeignParser \_ -> case parseForeign read x of
 | 
						|
    Right result -> Right result
 | 
						|
    Left err -> Left $ "Error reading property '" ++ p ++ "':\n" ++ err
 |