diff options
author | Marvin Borner | 2024-09-05 15:34:20 +0200 |
---|---|---|
committer | Marvin Borner | 2024-09-06 14:46:03 +0200 |
commit | c95688c2fa63ba91df518ddf0d97261d6bd02426 (patch) | |
tree | 0c548056289d7551243dd73cb585f54d179403d1 | |
parent | b565350fb5f44f57dcb02a66ae99bab3b27313d3 (diff) |
Refactored Helper.hs
-rw-r--r-- | app/Main.hs | 7 | ||||
-rw-r--r-- | src/Binary.hs | 1 | ||||
-rw-r--r-- | src/Config.hs | 45 | ||||
-rw-r--r-- | src/Conversion.hs | 239 | ||||
-rw-r--r-- | src/Error.hs | 94 | ||||
-rw-r--r-- | src/Eval.hs | 20 | ||||
-rw-r--r-- | src/Helper.hs | 412 | ||||
-rw-r--r-- | src/Humanification.hs | 58 | ||||
-rw-r--r-- | src/Optimizer.hs | 2 | ||||
-rw-r--r-- | src/Parser.hs | 4 | ||||
-rw-r--r-- | src/Reducer.hs | 1 | ||||
-rw-r--r-- | src/Reducer/ION.hs | 1 | ||||
-rw-r--r-- | src/Reducer/RKNL.hs | 1 | ||||
-rw-r--r-- | src/Target.hs | 7 |
14 files changed, 469 insertions, 423 deletions
diff --git a/app/Main.hs b/app/Main.hs index 47d1bd2..7a6d9de 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -1,10 +1,11 @@ module Main where -import Eval -import Helper ( ArgMode(..) +import Options.Applicative + +import Config ( ArgMode(..) , Args(..) ) -import Options.Applicative +import Eval mode :: Parser ArgMode mode = diff --git a/src/Binary.hs b/src/Binary.hs index a6e8ceb..4e6db3f 100644 --- a/src/Binary.hs +++ b/src/Binary.hs @@ -8,6 +8,7 @@ module Binary ) where import qualified Data.BitString as Bit + import Helper toBinary :: Expression -> String diff --git a/src/Config.hs b/src/Config.hs new file mode 100644 index 0000000..8b062ac --- /dev/null +++ b/src/Config.hs @@ -0,0 +1,45 @@ +-- MIT License, Copyright (c) 2022 Marvin Borner +module Config where + +import Data.Maybe ( fromMaybe + , isNothing + ) + +data ArgMode = ArgEval | ArgEvalBblc | ArgEvalBlc | ArgDumpBblc | ArgDumpBlc + +data Args = Args + { _argMode :: ArgMode + , _argNoTests :: Bool + , _argVerbose :: Bool + , _argOptimize :: Bool + , _argToTarget :: String + , _argReducer :: String + , _argPath :: Maybe String + } + +data EvalConf = EvalConf + { _isRepl :: Bool + , _isVerbose :: Bool + , _evalTests :: Bool + , _optimize :: Bool + , _nicePath :: String + , _path :: String + , _evalPaths :: [String] + , _toTarget :: String + , _reducer :: String + , _hasArg :: Bool + } + +argsToConf :: Args -> EvalConf +argsToConf args = EvalConf { _isRepl = isNothing $ _argPath args + , _isVerbose = _argVerbose args + , _evalTests = not $ _argNoTests args + , _optimize = _argOptimize args + , _path = path + , _nicePath = path + , _evalPaths = [] + , _toTarget = _argToTarget args + , _reducer = _argReducer args + , _hasArg = False + } + where path = fromMaybe "" (_argPath args) diff --git a/src/Conversion.hs b/src/Conversion.hs new file mode 100644 index 0000000..38d8399 --- /dev/null +++ b/src/Conversion.hs @@ -0,0 +1,239 @@ +-- MIT License, Copyright (c) 2022 Marvin Borner +module Conversion where + +import qualified Data.BitString as Bit +import qualified Data.ByteString.Lazy as Byte +import qualified Data.ByteString.Lazy.Char8 as C +import Data.Char ( chr ) +import GHC.Real ( denominator + , numerator + ) +import Numeric ( showFFloatAlt ) + +import Helper + +listify :: [Expression] -> Expression +listify [] = Abstraction (Abstraction (Bruijn 0)) +listify (e : es) = + Abstraction (Application (Application (Bruijn 0) e) (listify es)) + +binarify :: [Expression] -> Expression +binarify = foldr Application (Bruijn 2) + +encodeByte :: [Bool] -> Expression +encodeByte bits = Abstraction $ Abstraction $ Abstraction $ binarify + (map encodeBit bits) + where + encodeBit False = Bruijn 0 + encodeBit True = Bruijn 1 + +-- TODO: There must be a better way to do this :D +encodeBytes :: Byte.ByteString -> Expression +encodeBytes bytes = listify $ map + (encodeByte . Bit.toList . Bit.bitStringLazy . Byte.pack . (: [])) + (Byte.unpack bytes) + +stringToExpression :: String -> Expression +stringToExpression = encodeBytes . C.pack + +charToExpression :: Char -> Expression +charToExpression ch = encodeByte $ Bit.toList $ Bit.bitStringLazy $ C.pack [ch] + +encodeStdin :: IO Expression +encodeStdin = encodeBytes <$> Byte.getContents + +unlistify :: Expression -> Maybe [Expression] +unlistify (Abstraction (Abstraction (Bruijn 0))) = Just [] +unlistify (Abstraction (Application (Application (Bruijn 0) e) es)) = + (:) <$> Just e <*> unlistify es +unlistify _ = Nothing + +unpairify :: Expression -> Maybe [Expression] +unpairify (Abstraction (Application (Application (Bruijn 0) e1) e2)) = + Just (e1 : [e2]) +unpairify _ = Nothing + +decodeByte :: Expression -> Maybe [Bool] +decodeByte (Abstraction (Abstraction (Abstraction es))) = decodeByte es +decodeByte (Application (Bruijn 0) es) = (:) <$> Just False <*> decodeByte es +decodeByte (Application (Bruijn 1) es) = (:) <$> Just True <*> decodeByte es +decodeByte (Bruijn 2 ) = Just [] +decodeByte _ = Nothing + +decodeStdout :: Expression -> Maybe String +decodeStdout e = do + u <- unlistify e + pure $ C.unpack $ Byte.concat $ map + (\m -> case decodeByte m of + Just b -> Bit.realizeBitStringLazy $ Bit.fromList b + Nothing -> Byte.empty + ) + u + +--- + +floatToRational :: Rational -> Expression +floatToRational f = Abstraction + (Application (Application (Bruijn 0) (decimalToTernary p)) + (decimalToTernary $ q - 1) + ) + where + p = numerator f + q = denominator f + +floatToReal :: Rational -> Expression +floatToReal = Abstraction . floatToRational + +floatToComplex :: Rational -> Rational -> Expression +floatToComplex r i = Abstraction $ Abstraction $ Application + (Application (Bruijn 0) (Application (floatToReal r) (Bruijn 1))) + (Application (floatToReal i) (Bruijn 1)) + +-- Dec to Bal3 in Bruijn encoding: reversed application with 0=>0; 1=>1; T=>2; end=>3 +-- e.g. 0=0=[[[[3]]]]; 2=1T=[[[[2 (1 3)]]]] -5=T11=[[[[1 (1 (2 3))]]]] +decimalToTernary :: Integer -> Expression +decimalToTernary n = + Abstraction $ Abstraction $ Abstraction $ Abstraction $ gen n + where + gen 0 = Bruijn 3 + gen n' = + Application (Bruijn $ fromIntegral $ mod n' 3) (gen $ div (n' + 1) 3) + +-- Decimal to binary encoding +decimalToBinary :: Integer -> Expression +decimalToBinary n | n < 0 = decimalToBinary 0 + | otherwise = Abstraction $ Abstraction $ Abstraction $ gen n + where + gen 0 = Bruijn 2 + gen n' = Application (Bruijn $ fromIntegral $ mod n' 2) (gen $ div n' 2) + +-- Decimal to unary (church) encoding +decimalToUnary :: Integer -> Expression +decimalToUnary n | n < 0 = decimalToUnary 0 + | otherwise = Abstraction $ Abstraction $ gen n + where + gen 0 = Bruijn 0 + gen n' = Application (Bruijn 1) (gen (n' - 1)) + +-- Decimal to de Bruijn encoding +decimalToDeBruijn :: Integer -> Expression +decimalToDeBruijn n | n < 0 = decimalToDeBruijn 0 + | otherwise = gen n + where + gen 0 = Abstraction $ Bruijn $ fromInteger n + gen n' = Abstraction $ gen (n' - 1) + +unaryToDecimal :: Expression -> Maybe String +unaryToDecimal e = (<> "u") . show <$> unaryToDecimal' e + +unaryToDecimal' :: Expression -> Maybe Integer +unaryToDecimal' e = do + res <- resolve e + return (sum res :: Integer) + where + multiplier (Bruijn 1) = Just 1 + multiplier _ = Nothing + resolve' (Bruijn 0) = Just [] + resolve' (Application x@(Bruijn _) (Bruijn 0)) = + (:) <$> multiplier x <*> Just [] + resolve' (Application x@(Bruijn _) xs@(Application _ _)) = + (:) <$> multiplier x <*> resolve' xs + resolve' _ = Nothing + resolve (Abstraction (Abstraction n)) = resolve' n + resolve _ = Nothing + +binaryToChar :: Expression -> Maybe String +binaryToChar e = show <$> binaryToChar' e + +binaryToChar' :: Expression -> Maybe Char +binaryToChar' e = do + n <- binaryToDecimal e + if n > 31 && n < 127 || n == 10 then Just $ chr $ fromIntegral n else Nothing + +binaryToString :: Expression -> Maybe String +binaryToString e = (<> "b") . show <$> binaryToDecimal e + +binaryToDecimal :: Expression -> Maybe Integer +binaryToDecimal e = do + res <- resolve e + return (sum $ zipWith (*) res (iterate (* 2) 1) :: Integer) + where + multiplier (Bruijn 0) = Just 0 + multiplier (Bruijn 1) = Just 1 + multiplier _ = Nothing + resolve' (Bruijn 2) = Just [] + resolve' (Application x@(Bruijn _) (Bruijn 2)) = + (:) <$> multiplier x <*> Just [] + resolve' (Application x@(Bruijn _) xs@(Application _ _)) = + (:) <$> multiplier x <*> resolve' xs + resolve' _ = Nothing + resolve (Abstraction (Abstraction (Abstraction n))) = resolve' n + resolve _ = Nothing + +ternaryToString :: Expression -> Maybe String +ternaryToString e = (<> "t") . show <$> ternaryToDecimal e + +ternaryToDecimal :: Expression -> Maybe Integer +ternaryToDecimal e = do + res <- resolve e + return (sum $ zipWith (*) res (iterate (* 3) 1) :: Integer) + where + multiplier (Bruijn 0) = Just 0 + multiplier (Bruijn 1) = Just 1 + multiplier (Bruijn 2) = Just (-1) + multiplier _ = Nothing + resolve' (Bruijn 3) = Just [] + resolve' (Application x@(Bruijn _) (Bruijn 3)) = + (:) <$> multiplier x <*> Just [] + resolve' (Application x@(Bruijn _) xs@(Application _ _)) = + (:) <$> multiplier x <*> resolve' xs + resolve' _ = Nothing + resolve (Abstraction (Abstraction (Abstraction (Abstraction n)))) = + resolve' n + resolve _ = Nothing + +rationalToString :: Expression -> Maybe String +rationalToString (Abstraction (Application (Application (Bruijn 0) a) b)) = do + n <- ternaryToDecimal a + d <- ternaryToDecimal b + Just + $ show n + <> "/" + <> show (d + 1) + <> " (approx. " + <> showFFloatAlt (Just 8) + (fromIntegral n / fromIntegral (d + 1) :: Double) + "" + <> ")" +rationalToString _ = Nothing + +realToString :: Expression -> Maybe String +realToString (Abstraction e) = rationalToString e +realToString _ = Nothing + +complexToString :: Expression -> Maybe String +complexToString (Abstraction (Abstraction (Application (Application (Bruijn 0) (Abstraction (Application (Application (Bruijn 0) lr) rr))) (Abstraction (Application (Application (Bruijn 0) li) ri))))) + = do + nlr <- ternaryToDecimal lr + drr <- ternaryToDecimal rr + nli <- ternaryToDecimal li + dri <- ternaryToDecimal ri + Just + $ show nlr + <> "/" + <> show (drr + 1) + <> " + " + <> show nli + <> "/" + <> show (dri + 1) + <> "i" + <> " (approx. " + <> showFFloatAlt (Just 8) + (fromIntegral nlr / fromIntegral (drr + 1) :: Double) + "" + <> "+" + <> showFFloatAlt (Just 8) + (fromIntegral nli / fromIntegral (dri + 1) :: Double) + "" + <> "i)" +complexToString _ = Nothing diff --git a/src/Error.hs b/src/Error.hs new file mode 100644 index 0000000..0260aa1 --- /dev/null +++ b/src/Error.hs @@ -0,0 +1,94 @@ +-- MIT License, Copyright (c) 2022 Marvin Borner +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} + +module Error where + +import Data.List ( intercalate ) +import Text.Megaparsec + +import Helper + +errPrefix :: String +errPrefix = "\ESC[101m\ESC[30mERROR\ESC[0m " + +okPrefix :: String +okPrefix = "\ESC[102m\ESC[30m OK \ESC[0m " + +data Error = SyntaxError String + | UndefinedIdentifier Identifier + | UnmatchedMixfix [MixfixIdentifierKind] [Mixfix] + | InvalidIndex Int + | FailedTest Expression Expression Expression Expression + | PassedTest Expression Expression + | ContextualError Error Context + | SuggestSolution Error String + | ImportError String + | OptimizerError String + +instance Show Error where + show (ContextualError err ctx) = show err <> "\n" <> printContext ctx + show (SuggestSolution err sol) = + show err <> "\n\ESC[102m\ESC[30msuggestion\ESC[0m Perhaps you meant " <> sol + show (SyntaxError err) = + errPrefix <> "invalid syntax\n\ESC[105m\ESC[30mnear\ESC[0m " <> err + show (UndefinedIdentifier ident) = + errPrefix <> "undefined identifier " <> show ident + show (UnmatchedMixfix ks ms) = + errPrefix + <> "couldn't find matching mixfix for " + <> intercalate "" (map show ks) + <> "\n\ESC[105m\ESC[30mnear\ESC[0m " + <> unwords (map show ms) + show (InvalidIndex err) = errPrefix <> "invalid index " <> show err + show (PassedTest exp1 exp2) = + okPrefix <> "test passed: " <> show exp1 <> " = " <> show exp2 + show (FailedTest exp1 exp2 red1 red2) = + errPrefix + <> "test failed: " + <> show exp1 + <> " = " + <> show exp2 + <> "\n reduced to " + <> show red1 + <> " = " + <> show red2 + show (ImportError path) = errPrefix <> "invalid import " <> show path + show (OptimizerError msg ) = errPrefix <> "optimizer failed: " <> msg + +type Failable = Either Error + +-- Modified from megaparsec's errorBundlePretty +printBundle + :: forall s e + . (VisualStream s, TraversableStream s, ShowErrorComponent e) + => ParseErrorBundle s e + -> String +printBundle ParseErrorBundle {..} = + let (r, _) = foldl f (id, bundlePosState) bundleErrors in drop 1 (r "") + where + f :: (ShowS, PosState s) -> ParseError s e -> (ShowS, PosState s) + f (o, !pst) e = (o . (outChunk ++), pst') + where + (msline, pst') = reachOffset (errorOffset e) pst + epos = pstateSourcePos pst' + outChunk = "\n\n" <> offendingLine <> init (parseErrorTextPretty e) + offendingLine = case msline of + Nothing -> "" + Just sline -> + let pointer = "^" + rpadding = replicate rpshift ' ' + rpshift = unPos (sourceColumn epos) - 2 + lineNumber = (show . unPos . sourceLine) epos + padding = replicate (length lineNumber + 1) ' ' + in padding + <> "|\n" + <> " | " + <> sline + <> "\n" + <> padding + <> "| " + <> rpadding + <> pointer + <> "\n" diff --git a/src/Eval.hs b/src/Eval.hs index 548b43a..9b204ea 100644 --- a/src/Eval.hs +++ b/src/Eval.hs @@ -3,7 +3,6 @@ module Eval ( evalMain ) where -import Binary import Control.Concurrent import Control.DeepSeq ( deepseq ) import Control.Exception @@ -18,11 +17,7 @@ import Data.List import qualified Data.Map as M import Data.Maybe import Data.Time.Clock -import Helper -import Optimizer -import Parser import Paths_bruijn -import Reducer import System.Clock import System.Console.Haskeline import System.Directory @@ -35,6 +30,16 @@ import Text.Megaparsec hiding ( State , try ) +import Binary +import Config +import Conversion +import Error +import Helper +import Humanification +import Optimizer +import Parser +import Reducer + data EnvState = EnvState { _env :: Environment , _conf :: EvalConf @@ -217,8 +222,8 @@ evalCommand inp s@(EnvState env@(Environment envDefs) conf cache) = \case Watch path -> let monitor mtime = do - threadDelay 100000 - full <- fullPath "" path + threadDelay 100000 -- TODO: fix watch + full <- fullPath (_path conf) path t <- getModificationTime full if t > mtime then @@ -237,7 +242,6 @@ evalCommand inp s@(EnvState env@(Environment envDefs) conf cache) = \case >> pure s else if M.member path (_imported cache) then -- load from cache - let (Environment env') = fromJust $ M.lookup path (_imported cache) prefix | null namespace = takeBaseName path ++ "." diff --git a/src/Helper.hs b/src/Helper.hs index 5f5adf6..c6b466b 100644 --- a/src/Helper.hs +++ b/src/Helper.hs @@ -1,30 +1,15 @@ -- MIT License, Copyright (c) 2022 Marvin Borner -{-# LANGUAGE BangPatterns #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ScopedTypeVariables #-} module Helper where import Control.DeepSeq ( NFData ) import qualified Control.Monad.State as S import Data.Array -import qualified Data.BitString as Bit -import qualified Data.ByteString.Lazy as Byte -import qualified Data.ByteString.Lazy.Char8 as C -import Data.Char -import Data.List +import Data.List ( intercalate ) import qualified Data.Map as M -import Data.Maybe ( fromMaybe - , isNothing - ) import GHC.Generics ( Generic ) -import GHC.Real ( denominator - , numerator - ) -import Numeric ( showFFloatAlt ) -import Text.Megaparsec invalidProgramState :: a invalidProgramState = error "invalid program state" @@ -46,80 +31,6 @@ printContext (Context inp path) = p $ lines inp p (l : ls) = p [l] <> nearText <> intercalate "\n" (map (" | " ++) $ take 3 ls) <> "\n" -errPrefix :: String -errPrefix = "\ESC[101m\ESC[30mERROR\ESC[0m " - -okPrefix :: String -okPrefix = "\ESC[102m\ESC[30m OK \ESC[0m " - -data Error = SyntaxError String | UndefinedIdentifier Identifier | UnmatchedMixfix [MixfixIdentifierKind] [Mixfix] | InvalidIndex Int | FailedTest Expression Expression Expression Expression | PassedTest Expression Expression | ContextualError Error Context | SuggestSolution Error String | ImportError String | OptimizerError String - -instance Show Error where - show (ContextualError err ctx) = show err <> "\n" <> printContext ctx - show (SuggestSolution err sol) = - show err <> "\n\ESC[102m\ESC[30msuggestion\ESC[0m Perhaps you meant " <> sol - show (SyntaxError err) = - errPrefix <> "invalid syntax\n\ESC[105m\ESC[30mnear\ESC[0m " <> err - show (UndefinedIdentifier ident) = - errPrefix <> "undefined identifier " <> show ident - show (UnmatchedMixfix ks ms) = - errPrefix - <> "couldn't find matching mixfix for " - <> intercalate "" (map show ks) - <> "\n\ESC[105m\ESC[30mnear\ESC[0m " - <> unwords (map show ms) - show (InvalidIndex err) = errPrefix <> "invalid index " <> show err - show (PassedTest exp1 exp2) = - okPrefix <> "test passed: " <> show exp1 <> " = " <> show exp2 - show (FailedTest exp1 exp2 red1 red2) = - errPrefix - <> "test failed: " - <> show exp1 - <> " = " - <> show exp2 - <> "\n reduced to " - <> show red1 - <> " = " - <> show red2 - show (ImportError path) = errPrefix <> "invalid import " <> show path - show (OptimizerError msg ) = errPrefix <> "optimizer failed: " <> msg - -type Failable = Either Error - --- Modified from megaparsec's errorBundlePretty -printBundle - :: forall s e - . (VisualStream s, TraversableStream s, ShowErrorComponent e) - => ParseErrorBundle s e - -> String -printBundle ParseErrorBundle {..} = - let (r, _) = foldl f (id, bundlePosState) bundleErrors in drop 1 (r "") - where - f :: (ShowS, PosState s) -> ParseError s e -> (ShowS, PosState s) - f (o, !pst) e = (o . (outChunk ++), pst') - where - (msline, pst') = reachOffset (errorOffset e) pst - epos = pstateSourcePos pst' - outChunk = "\n\n" <> offendingLine <> init (parseErrorTextPretty e) - offendingLine = case msline of - Nothing -> "" - Just sline -> - let pointer = "^" - rpadding = replicate rpshift ' ' - rpshift = unPos (sourceColumn epos) - 2 - lineNumber = (show . unPos . sourceLine) epos - padding = replicate (length lineNumber + 1) ' ' - in padding - <> "|\n" - <> " | " - <> sline - <> "\n" - <> padding - <> "| " - <> rpadding - <> pointer - <> "\n" - data MixfixIdentifierKind = MixfixSome String | MixfixNone deriving (Ord, Eq, Generic, NFData) @@ -185,30 +96,8 @@ data Command = Input String | Watch String | Import String String | Test Express data Instruction = Define Identifier Expression [Instruction] | Evaluate Expression | Comment | Commands [Command] | ContextualInstruction Instruction String deriving (Show) -data ArgMode = ArgEval | ArgEvalBblc | ArgEvalBlc | ArgDumpBblc | ArgDumpBlc - -data Args = Args - { _argMode :: ArgMode - , _argNoTests :: Bool - , _argVerbose :: Bool - , _argOptimize :: Bool - , _argToTarget :: String - , _argReducer :: String - , _argPath :: Maybe String - } - -data EvalConf = EvalConf - { _isRepl :: Bool - , _isVerbose :: Bool - , _evalTests :: Bool - , _optimize :: Bool - , _nicePath :: String - , _path :: String - , _evalPaths :: [String] - , _toTarget :: String - , _reducer :: String - , _hasArg :: Bool - } +defaultFlags :: ExpFlags +defaultFlags = ExpFlags { _isImported = False } newtype ExpFlags = ExpFlags { _isImported :: Bool @@ -231,83 +120,6 @@ newtype EnvCache = EnvCache type EvalState = S.State Environment -argsToConf :: Args -> EvalConf -argsToConf args = EvalConf { _isRepl = isNothing $ _argPath args - , _isVerbose = _argVerbose args - , _evalTests = not $ _argNoTests args - , _optimize = _argOptimize args - , _path = path - , _nicePath = path - , _evalPaths = [] - , _toTarget = _argToTarget args - , _reducer = _argReducer args - , _hasArg = False - } - where path = fromMaybe "" (_argPath args) - -defaultFlags :: ExpFlags -defaultFlags = ExpFlags { _isImported = False } - ---- - -listify :: [Expression] -> Expression -listify [] = Abstraction (Abstraction (Bruijn 0)) -listify (e : es) = - Abstraction (Application (Application (Bruijn 0) e) (listify es)) - -binarify :: [Expression] -> Expression -binarify = foldr Application (Bruijn 2) - -encodeByte :: [Bool] -> Expression -encodeByte bits = Abstraction $ Abstraction $ Abstraction $ binarify - (map encodeBit bits) - where - encodeBit False = Bruijn 0 - encodeBit True = Bruijn 1 - --- TODO: There must be a better way to do this :D -encodeBytes :: Byte.ByteString -> Expression -encodeBytes bytes = listify $ map - (encodeByte . Bit.toList . Bit.bitStringLazy . Byte.pack . (: [])) - (Byte.unpack bytes) - -stringToExpression :: String -> Expression -stringToExpression = encodeBytes . C.pack - -charToExpression :: Char -> Expression -charToExpression ch = encodeByte $ Bit.toList $ Bit.bitStringLazy $ C.pack [ch] - -encodeStdin :: IO Expression -encodeStdin = encodeBytes <$> Byte.getContents - -unlistify :: Expression -> Maybe [Expression] -unlistify (Abstraction (Abstraction (Bruijn 0))) = Just [] -unlistify (Abstraction (Application (Application (Bruijn 0) e) es)) = - (:) <$> Just e <*> unlistify es -unlistify _ = Nothing - -unpairify :: Expression -> Maybe [Expression] -unpairify (Abstraction (Application (Application (Bruijn 0) e1) e2)) = - Just (e1 : [e2]) -unpairify _ = Nothing - -decodeByte :: Expression -> Maybe [Bool] -decodeByte (Abstraction (Abstraction (Abstraction es))) = decodeByte es -decodeByte (Application (Bruijn 0) es) = (:) <$> Just False <*> decodeByte es -decodeByte (Application (Bruijn 1) es) = (:) <$> Just True <*> decodeByte es -decodeByte (Bruijn 2 ) = Just [] -decodeByte _ = Nothing - -decodeStdout :: Expression -> Maybe String -decodeStdout e = do - u <- unlistify e - pure $ C.unpack $ Byte.concat $ map - (\m -> case decodeByte m of - Just b -> Bit.realizeBitStringLazy $ Bit.fromList b - Nothing -> Byte.empty - ) - u - --- -- from reddit u/cgibbard @@ -335,221 +147,3 @@ matchingFunctions e (Environment env) = intercalate ", " $ map (functionName . fst) $ M.toList $ M.filter (\EnvDef { _exp = e' } -> e == e') env - --- TODO: Show binary as char if in ascii range (=> + humanify strings) --- TODO: Show list as pair if not ending with empty -maybeHumanifyExpression :: Expression -> Maybe String -maybeHumanifyExpression e = - unaryToDecimal e - <|> binaryToChar e - <|> binaryToString e - <|> ternaryToString e - <|> rationalToString e - <|> realToString e - <|> complexToString e - <|> humanifyString e - <|> humanifyList e - <|> humanifyPair e - <|> humanifyMeta e - -humanifyExpression :: Expression -> String -humanifyExpression e = fromMaybe "" (maybeHumanifyExpression e) - -humanifyMeta :: Expression -> Maybe String -humanifyMeta e = ("`" <>) <$> go e - where - go (Abstraction (Abstraction (Abstraction (Application (Bruijn 0) t)))) = - go t >>= (\a -> pure $ "[" <> a <> "]") - go (Abstraction (Abstraction (Abstraction (Application (Application (Bruijn 1) a) b)))) - = go a >>= \l -> go b >>= \r -> pure $ "(" <> l <> " " <> r <> ")" - go (Abstraction (Abstraction (Abstraction (Application (Bruijn 2) n)))) = - fmap show (unaryToDecimal' n) - go _ = Nothing - -humanifyList :: Expression -> Maybe String -humanifyList e = do - es <- unlistify e - let conv x = fromMaybe (show x) (maybeHumanifyExpression x) - m = map conv es - pure $ "{" <> intercalate ", " m <> "}" - -humanifyString :: Expression -> Maybe String -humanifyString e = do - es <- unlistify e - str <- mapM binaryToChar' es - pure $ "\"" <> str <> "\"" - -humanifyPair :: Expression -> Maybe String -humanifyPair e = do - es <- unpairify e - let conv x = fromMaybe (show x) (maybeHumanifyExpression x) - m = map conv es - pure $ "<" <> intercalate " : " m <> ">" - ---- - -floatToRational :: Rational -> Expression -floatToRational f = Abstraction - (Application (Application (Bruijn 0) (decimalToTernary p)) - (decimalToTernary $ q - 1) - ) - where - p = numerator f - q = denominator f - -floatToReal :: Rational -> Expression -floatToReal = Abstraction . floatToRational - -floatToComplex :: Rational -> Rational -> Expression -floatToComplex r i = Abstraction $ Abstraction $ Application - (Application (Bruijn 0) (Application (floatToReal r) (Bruijn 1))) - (Application (floatToReal i) (Bruijn 1)) - --- Dec to Bal3 in Bruijn encoding: reversed application with 0=>0; 1=>1; T=>2; end=>3 --- e.g. 0=0=[[[[3]]]]; 2=1T=[[[[2 (1 3)]]]] -5=T11=[[[[1 (1 (2 3))]]]] -decimalToTernary :: Integer -> Expression -decimalToTernary n = - Abstraction $ Abstraction $ Abstraction $ Abstraction $ gen n - where - gen 0 = Bruijn 3 - gen n' = - Application (Bruijn $ fromIntegral $ mod n' 3) (gen $ div (n' + 1) 3) - --- Decimal to binary encoding -decimalToBinary :: Integer -> Expression -decimalToBinary n | n < 0 = decimalToBinary 0 - | otherwise = Abstraction $ Abstraction $ Abstraction $ gen n - where - gen 0 = Bruijn 2 - gen n' = Application (Bruijn $ fromIntegral $ mod n' 2) (gen $ div n' 2) - --- Decimal to unary (church) encoding -decimalToUnary :: Integer -> Expression -decimalToUnary n | n < 0 = decimalToUnary 0 - | otherwise = Abstraction $ Abstraction $ gen n - where - gen 0 = Bruijn 0 - gen n' = Application (Bruijn 1) (gen (n' - 1)) - --- Decimal to de Bruijn encoding -decimalToDeBruijn :: Integer -> Expression -decimalToDeBruijn n | n < 0 = decimalToDeBruijn 0 - | otherwise = gen n - where - gen 0 = Abstraction $ Bruijn $ fromInteger n - gen n' = Abstraction $ gen (n' - 1) - -unaryToDecimal :: Expression -> Maybe String -unaryToDecimal e = (<> "u") . show <$> unaryToDecimal' e - -unaryToDecimal' :: Expression -> Maybe Integer -unaryToDecimal' e = do - res <- resolve e - return (sum res :: Integer) - where - multiplier (Bruijn 1) = Just 1 - multiplier _ = Nothing - resolve' (Bruijn 0) = Just [] - resolve' (Application x@(Bruijn _) (Bruijn 0)) = - (:) <$> multiplier x <*> Just [] - resolve' (Application x@(Bruijn _) xs@(Application _ _)) = - (:) <$> multiplier x <*> resolve' xs - resolve' _ = Nothing - resolve (Abstraction (Abstraction n)) = resolve' n - resolve _ = Nothing - -binaryToChar :: Expression -> Maybe String -binaryToChar e = show <$> binaryToChar' e - -binaryToChar' :: Expression -> Maybe Char -binaryToChar' e = do - n <- binaryToDecimal e - if n > 31 && n < 127 || n == 10 then Just $ chr $ fromIntegral n else Nothing - -binaryToString :: Expression -> Maybe String -binaryToString e = (<> "b") . show <$> binaryToDecimal e - -binaryToDecimal :: Expression -> Maybe Integer -binaryToDecimal e = do - res <- resolve e - return (sum $ zipWith (*) res (iterate (* 2) 1) :: Integer) - where - multiplier (Bruijn 0) = Just 0 - multiplier (Bruijn 1) = Just 1 - multiplier _ = Nothing - resolve' (Bruijn 2) = Just [] - resolve' (Application x@(Bruijn _) (Bruijn 2)) = - (:) <$> multiplier x <*> Just [] - resolve' (Application x@(Bruijn _) xs@(Application _ _)) = - (:) <$> multiplier x <*> resolve' xs - resolve' _ = Nothing - resolve (Abstraction (Abstraction (Abstraction n))) = resolve' n - resolve _ = Nothing - -ternaryToString :: Expression -> Maybe String -ternaryToString e = (<> "t") . show <$> ternaryToDecimal e - -ternaryToDecimal :: Expression -> Maybe Integer -ternaryToDecimal e = do - res <- resolve e - return (sum $ zipWith (*) res (iterate (* 3) 1) :: Integer) - where - multiplier (Bruijn 0) = Just 0 - multiplier (Bruijn 1) = Just 1 - multiplier (Bruijn 2) = Just (-1) - multiplier _ = Nothing - resolve' (Bruijn 3) = Just [] - resolve' (Application x@(Bruijn _) (Bruijn 3)) = - (:) <$> multiplier x <*> Just [] - resolve' (Application x@(Bruijn _) xs@(Application _ _)) = - (:) <$> multiplier x <*> resolve' xs - resolve' _ = Nothing - resolve (Abstraction (Abstraction (Abstraction (Abstraction n)))) = - resolve' n - resolve _ = Nothing - -rationalToString :: Expression -> Maybe String -rationalToString (Abstraction (Application (Application (Bruijn 0) a) b)) = do - n <- ternaryToDecimal a - d <- ternaryToDecimal b - Just - $ show n - <> "/" - <> show (d + 1) - <> " (approx. " - <> showFFloatAlt (Just 8) - (fromIntegral n / fromIntegral (d + 1) :: Double) - "" - <> ")" -rationalToString _ = Nothing - -realToString :: Expression -> Maybe String -realToString (Abstraction e) = rationalToString e -realToString _ = Nothing - -complexToString :: Expression -> Maybe String -complexToString (Abstraction (Abstraction (Application (Application (Bruijn 0) (Abstraction (Application (Application (Bruijn 0) lr) rr))) (Abstraction (Application (Application (Bruijn 0) li) ri))))) - = do - nlr <- ternaryToDecimal lr - drr <- ternaryToDecimal rr - nli <- ternaryToDecimal li - dri <- ternaryToDecimal ri - Just - $ show nlr - <> "/" - <> show (drr + 1) - <> " + " - <> show nli - <> "/" - <> show (dri + 1) - <> "i" - <> " (approx. " - <> showFFloatAlt (Just 8) - (fromIntegral nlr / fromIntegral (drr + 1) :: Double) - "" - <> "+" - <> showFFloatAlt (Just 8) - (fromIntegral nli / fromIntegral (dri + 1) :: Double) - "" - <> "i)" -complexToString _ = Nothing diff --git a/src/Humanification.hs b/src/Humanification.hs new file mode 100644 index 0000000..77a5580 --- /dev/null +++ b/src/Humanification.hs @@ -0,0 +1,58 @@ +-- MIT License, Copyright (c) 2022 Marvin Borner +module Humanification where + +import Control.Applicative ( (<|>) ) +import Data.List ( intercalate ) +import Data.Maybe ( fromMaybe ) + +import Conversion +import Helper + +-- TODO: Show list as pair if not ending with empty +maybeHumanifyExpression :: Expression -> Maybe String +maybeHumanifyExpression e = + unaryToDecimal e + <|> binaryToChar e + <|> binaryToString e + <|> ternaryToString e + <|> rationalToString e + <|> realToString e + <|> complexToString e + <|> humanifyString e + <|> humanifyList e + <|> humanifyPair e + <|> humanifyMeta e + +humanifyExpression :: Expression -> String +humanifyExpression e = fromMaybe "" (maybeHumanifyExpression e) + +humanifyMeta :: Expression -> Maybe String +humanifyMeta e = ("`" <>) <$> go e + where + go (Abstraction (Abstraction (Abstraction (Application (Bruijn 0) t)))) = + go t >>= (\a -> pure $ "[" <> a <> "]") + go (Abstraction (Abstraction (Abstraction (Application (Application (Bruijn 1) a) b)))) + = go a >>= \l -> go b >>= \r -> pure $ "(" <> l <> " " <> r <> ")" + go (Abstraction (Abstraction (Abstraction (Application (Bruijn 2) n)))) = + fmap show (unaryToDecimal' n) + go _ = Nothing + +humanifyList :: Expression -> Maybe String +humanifyList e = do + es <- unlistify e + let conv x = fromMaybe (show x) (maybeHumanifyExpression x) + m = map conv es + pure $ "{" <> intercalate ", " m <> "}" + +humanifyString :: Expression -> Maybe String +humanifyString e = do + es <- unlistify e + str <- mapM binaryToChar' es + pure $ "\"" <> str <> "\"" + +humanifyPair :: Expression -> Maybe String +humanifyPair e = do + es <- unpairify e + let conv x = fromMaybe (show x) (maybeHumanifyExpression x) + m = map conv es + pure $ "<" <> intercalate " : " m <> ">" diff --git a/src/Optimizer.hs b/src/Optimizer.hs index e7f56ab..d7292dd 100644 --- a/src/Optimizer.hs +++ b/src/Optimizer.hs @@ -6,6 +6,8 @@ module Optimizer import Data.List ( tails ) import qualified Data.Map as M + +import Config import Helper import Reducer diff --git a/src/Parser.hs b/src/Parser.hs index 53ff076..83f03aa 100644 --- a/src/Parser.hs +++ b/src/Parser.hs @@ -7,12 +7,14 @@ module Parser import Control.Monad ( ap , void ) +import Conversion import Data.Void import GHC.Real ( (%) ) -import Helper import Text.Megaparsec hiding ( parseTest ) import Text.Megaparsec.Char +import Helper + type Parser = Parsec Void String -- exactly one space diff --git a/src/Reducer.hs b/src/Reducer.hs index 31ed3da..f71605a 100644 --- a/src/Reducer.hs +++ b/src/Reducer.hs @@ -4,6 +4,7 @@ module Reducer , reduceNoIO ) where +import Config import Helper import qualified Reducer.HigherOrder as HigherOrder import qualified Reducer.ION as ION diff --git a/src/Reducer/ION.hs b/src/Reducer/ION.hs index 5eb959b..1034cb8 100644 --- a/src/Reducer/ION.hs +++ b/src/Reducer/ION.hs @@ -15,6 +15,7 @@ import Data.Char ( chr ) import qualified Data.Map as M import Data.Map ( Map ) + import Helper ncomb :: Int diff --git a/src/Reducer/RKNL.hs b/src/Reducer/RKNL.hs index 5aa6ca1..93c9d5d 100644 --- a/src/Reducer/RKNL.hs +++ b/src/Reducer/RKNL.hs @@ -9,6 +9,7 @@ import Data.List ( elemIndex ) import Data.Map.Strict ( Map ) import qualified Data.Map.Strict as Map import Data.Maybe ( fromMaybe ) + import Helper type Store = Map Int Box diff --git a/src/Target.hs b/src/Target.hs index ea46161..492d356 100644 --- a/src/Target.hs +++ b/src/Target.hs @@ -4,14 +4,17 @@ module Target ( toTarget ) where -import Binary import Control.Exception import qualified Data.BitString as Bit import qualified Data.ByteString.Lazy.Char8 as Byte -import Helper import System.IO import System.Process +import Binary +import Config +import Error +import Helper + tryIO :: IO a -> IO (Either IOException a) tryIO = try |