Initial commit
This commit is contained in:
87
forth.hs
Normal file
87
forth.hs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
|
-- This is a WIP solution to
|
||||||
|
-- https://exercism.org/tracks/haskell/exercises/forth
|
||||||
|
|
||||||
|
module Forth (
|
||||||
|
ForthError(..),
|
||||||
|
ForthState,
|
||||||
|
evalText,
|
||||||
|
toList,
|
||||||
|
emptyState
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.Text (Text)
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import Data.Text.Read
|
||||||
|
import Data.Either
|
||||||
|
import Data.Maybe
|
||||||
|
|
||||||
|
data ForthError
|
||||||
|
= DivisionByZero
|
||||||
|
| StackUnderflow
|
||||||
|
| InvalidWord
|
||||||
|
| UnknownWord Text
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
data ForthState = ForthState [Int]
|
||||||
|
|
||||||
|
instance Show ForthState where
|
||||||
|
show (ForthState stack) = "ForthState " ++ show stack
|
||||||
|
|
||||||
|
emptyState :: ForthState
|
||||||
|
emptyState = ForthState []
|
||||||
|
|
||||||
|
-- Your evaluator has to support the following words:
|
||||||
|
-- +, -, *, / (integer arithmetic)
|
||||||
|
-- DUP, DROP, SWAP, OVER (stack manipulation)
|
||||||
|
evalText :: Text -> ForthState -> Either ForthError ForthState
|
||||||
|
evalText text =
|
||||||
|
case text of
|
||||||
|
"/" -> forthOp div
|
||||||
|
"+" -> forthOp (+)
|
||||||
|
"-" -> forthOp (-)
|
||||||
|
"*" -> forthOp (*)
|
||||||
|
"DUP" -> forthDup
|
||||||
|
"DROP" -> forthDrop
|
||||||
|
"SWAP" -> forthSwap
|
||||||
|
"OVER" -> forthOver
|
||||||
|
otherwise -> appendAsNum
|
||||||
|
where
|
||||||
|
appendAsNum =
|
||||||
|
case decimal text of
|
||||||
|
Right v -> forthAppend $ fst v
|
||||||
|
Left _ -> \_ -> Left $ UnknownWord text
|
||||||
|
|
||||||
|
-- Pop a, b from stack, apply `op` to them and push the result on top.
|
||||||
|
forthOp :: (Int -> Int -> Int) -> ForthState -> Either ForthError ForthState
|
||||||
|
forthOp op (ForthState (x1:x2:xs)) = Right $ ForthState (op x1 x2:xs)
|
||||||
|
forthOp op _ = Left StackUnderflow
|
||||||
|
|
||||||
|
-- Duplicate the stack head
|
||||||
|
forthDup :: ForthState -> Either ForthError ForthState
|
||||||
|
forthDup (ForthState (x:xs)) = Right $ ForthState (x:x:xs)
|
||||||
|
forthDup _ = Left StackUnderflow
|
||||||
|
|
||||||
|
-- Discard the stack head
|
||||||
|
forthDrop :: ForthState -> Either ForthError ForthState
|
||||||
|
forthDrop (ForthState (_:xs)) = Right $ ForthState xs
|
||||||
|
forthDrop _ = Left StackUnderflow
|
||||||
|
|
||||||
|
-- Swap the top two elements of the stack.
|
||||||
|
forthSwap :: ForthState -> Either ForthError ForthState
|
||||||
|
forthSwap (ForthState (xa:xb:xs)) = Right $ ForthState (xb:xa:xs)
|
||||||
|
forthSwap _ = Left StackUnderflow
|
||||||
|
|
||||||
|
-- Copy second item to top
|
||||||
|
forthOver :: ForthState -> Either ForthError ForthState
|
||||||
|
forthOver (ForthState (x1:x2:xs)) = Right $ ForthState (x2:x1:x2:xs)
|
||||||
|
forthOver _ = Left StackUnderflow
|
||||||
|
|
||||||
|
-- Add v to the top of the stack
|
||||||
|
forthAppend :: Int -> ForthState -> Either ForthError ForthState
|
||||||
|
forthAppend v (ForthState (x:xs)) = Right $ ForthState (v:x:xs)
|
||||||
|
|
||||||
|
toList :: ForthState -> [Int]
|
||||||
|
toList (ForthState stack) = stack
|
||||||
|
|
||||||
Reference in New Issue
Block a user