packages feed

arghwxhaskell (empty) → 0.8.1.0

raw patch · 5 files changed

+1318/−0 lines, 5 filesdep +basedep +directorydep +wxsetup-changed

Dependencies added: base, directory, wx

Files

+ Argh.hs view
@@ -0,0 +1,927 @@+{-  An interpreter for the Argh! programming language in wxHaskell
+
+    Copyright (C) 2007 Simeon Visser
+    Contact: svisser@cs.uu.nl
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+-}
+{- |
+An interpreter for the Argh! programming language in wxHaskell.
+Argh! is an esoteric programming language created by Sascha Wilde. An Argh!
+program is a two-dimensional grid (80x40 cells) and
+each cell contains an integer that can be interpreted as such or
+as a command that can be executed.
+A stack is used to store values and to do calculations. For more information
+about Argh!, see <http://www.sha-bang.de/index.php?page=12_eso> (in German).
+
+This implementation (v0.8) is based on the following language specification:
+<http://www.sha-bang.de/content/12_eso/Argh-Spec.txt>. All commands are
+supported /except/ @e@ and @E@ (these are used for inserting EOF in cells).
+Existing Argh! programs may or may not behave as expected: the @e@ and @E@
+commands will produce an error and other language elements,
+such as the @g@ and @G@ commands that use input from stdin
+(a @TextEntry@ in this case), may also differ.
+
+Available under the GNU General Public License. For more information,
+see <http://www.gnu.org/licenses/>.
+
+For more information about wxHaskell, see <http://wxhaskell.sourceforge.net/>.
+
+Tested on Windows XP using GHCi 6.4.1 and wxHaskell 0.9.4. The window of the
+program has a fixed size suited for 1024*768 resolution. This can be changed by removing
+@resizeable := False@ in the 'interpreter' function yet the window still has
+a minimum size because the @code@ widget has a minimum size. Of course, this
+can be modified if you want to run it on 800*600 or lower.
+
+Notes:
+
+* Zero is considered to be both positive and negative when executing the @x@ and @X@
+commands (see 'turnCond') - this is based on the fact that the @tenhello.agh@
+example in the official Argh! distribution (version 0.2.3) would print /Hello world/
+only 9 times if 0 is not considered a negative value.
+
+* Checking the /Run even invalid code/ option doesn't turn this implementation
+into Aargh! (that's Argh! without the maximum of 40 lines).
+When checked, the interpreter will ignore the size limitations (80x40)
+and\/or invalid characters and run anyway. The 'makeGrid' function makes use of the
+'maxWidth' and 'maxHeight' constants so the grid might not have the expected size
+if you use longer lines or more than the specified 40. As such, storing values in
+non-existant cells will result in undefined behaviour. The option can be useful,
+for example, when comments in the program contain invalid characters. Using it is
+not recommended, however.
+
+February 2007, Simeon Visser
+
+For comments, bugs, etc: svisser\@cs.uu.nl
+-}
+
+-- module ArghInterpreter where
+module Main where
+
+import System.Directory (doesFileExist)
+import Data.Char (chr, ord)
+import Data.Maybe (listToMaybe, catMaybes)
+import Data.List (intersperse, findIndices)
+import Data.Ix (inRange)
+import Graphics.UI.WX
+
+-- * Data structures
+
+data ArghStack
+  = Stack [Int] -- ^ The stack.
+  deriving (Show)
+data ArghGrid
+  -- | An Argh! program is a two-dimensional grid of 'ArghCell' elements.
+  = Grid [[ArghCell]]
+  deriving (Show)
+data ArghCell
+  -- | Every cell of the 'ArghGrid' can store an @Int@.
+  = Cell Int
+  -- | An existing but undefined cell (cells outside the 'ArghGrid' don't exist).
+  | Undefined
+  deriving (Show)
+
+-- | Valid directions (control flow of an Argh! program).
+data ArghDirection = ArghUp | ArghRight | ArghDown | ArghLeft
+data ArghPointer
+  -- | The pointer stores an 'ArghDirection' and a position (x,y).
+  = Pointer ArghDirection Coordinate Coordinate
+  deriving (Show)
+
+instance (Show ArghDirection) where
+  show ArghUp    = "Going up!\n"
+  show ArghRight = "Going right!\n"
+  show ArghDown  = "Going down!\n"
+  show ArghLeft  = "Going left!\n"
+
+type Coordinate = Int
+type ErrorMessage = String
+type ArghProgram = [String]
+
+-- * Constants
+
+-- | Version number.
+version :: Float
+version = 0.8
+
+{- |
+Maximum width; the interpreter complains when a line
+is longer than this number of characters. Default maximum width is 80.
+-}
+maxWidth :: Int
+maxWidth = 80
+
+{- |
+Maximum height; the interpreter complains when the program
+consists of more than this number of lines. Default maximum height is 40.
+-}
+maxHeight :: Int
+maxHeight = 40
+
+{- |
+This is used to specify the files the user can open in the Open dialogs.
+-}
+openFiles :: [(String,[String])]
+openFiles =
+  [ ("Argh! programs (*.agh)",["*.agh"])
+  , ("Any file (*.*)",["*.*"]) ]
+
+{- |
+This is used to specify the files the user can save in the Save dialogs.
+-}
+saveFiles :: [(String,[String])]
+saveFiles = [("Argh! programs (*.agh)", ["*.agh"])]
+
+{- |
+This is used to specify the output files.
+-}
+outputFiles :: [(String, [String])]
+outputFiles =
+  [ ("Text files (*.txt)", ["*.txt"])
+  , ("Any file (*.*)",["*.*"]) ]
+
+-- * Argh! interpreter
+
+{- |
+The main function. Call this to start the interpreter.
+-}
+main :: IO ()
+main = start interpreter
+
+{- |
+The program; initializes variables to store state, creates the
+controls for the user interface and creates the layout.
+-}
+interpreter :: IO ()
+interpreter = do
+   stack <- variable [ value := Stack [ ] ]
+
+   -- variables
+   bRunWithErrors <- variable [ value := False ]
+   bShowLocation <- variable [ value := False ]
+   bShowFullTrace <- variable [ value := False ]
+
+   filepath <- variable [ value := "Default.agh" ]
+   filepath' <- variable [ value := "Output.txt" ]
+
+   -- the frame
+   f <- frame [ text := ("Argh! interpreter v" ++ (show version))
+              , resizeable := False ]
+
+   -- text controls
+   code <- textCtrlRich f [ font := fontFixed, wrap := WrapNone ]
+   console <- textCtrlRich f [ font := fontFixed, wrap := WrapNone ]
+   input <- textEntry f []
+
+   -- the buttons
+   check <- button f [ text := "Validate"
+                     , on command := buttonCheckCode f code console
+                     , tooltip := "Validates the current Argh! program " ]
+   run <- button f [ text := "Run"
+                   , on command := run code console input stack
+                                   bRunWithErrors bShowLocation bShowFullTrace
+                   , tooltip := "Runs the current Argh! program" ]
+
+   -- checkboxes
+   cb1 <- checkBox f [ text := "Run even invalid code (unsafe)"
+                     , on command := set bRunWithErrors [ value :~ not ]
+                     , tooltip := "Enable to allow execution of invalid code" ]
+   cb2 <- checkBox f [ text := "Show location (x,y) when error occurs"
+                     , on command := set bShowLocation [ value :~ not ]
+                     , tooltip := "Enable to show the location in an error message" ]
+   cb3 <- checkBox f [ text := "Output all executed commands"
+                     , on command := set bShowFullTrace [ value :~ not ]
+                     , tooltip := "Enable to output all executed commands"
+                     ]
+
+   -- statusbar
+   status <- statusField []
+   set f [ statusBar := [ status ] ]
+
+   -- the menubar
+   mfile <- makeFileMenu f filepath filepath' code console
+   medit <- makeEditMenu f code
+   mhelp <- makeHelpMenu f
+
+   set f [ menuBar := [ mfile, medit, mhelp ] ]
+
+   -- layout
+   set f [ layout := margin 5 $ grid 5 5 $
+            [ [ row 5 [ column 5 [ boxed "Argh!".fill.minsize (sz 550 300).widget $ code
+                                 , boxed "Input".fill.widget $ input
+                                 , boxed "Output".fill.widget $ console ]
+              , column 5 [ boxed "Settings" $
+                             column 5 [ alignCenter.row 5 $ [ widget run, widget check ]
+                                      , widget cb1
+                                      , widget cb2
+                                      , widget cb3
+                                      ]
+                         ] ]
+              ]
+            ]
+         ]
+
+{- |
+This function does preparations before the execution of the program begins (see
+'exec'). It checks if the Argh! program is valid and creates an 'ArghGrid' to
+execute the program using the settings specified by the variables (i.e., showing
+error location yes\/no and outputting every command yes\/no).
+-}
+run :: TextCtrl () -> TextCtrl () -> TextCtrl () -> Var ArghStack -> Var Bool
+        -> Var Bool -> Var Bool -> IO ()
+run code console input vstack vbRunWithErrors vbShowLocation
+      vbShowFullTrace = do
+  txt <- get code text
+  stack <- varGet vstack
+  bRunWithErrors <- varGet vbRunWithErrors
+  bShowLoc <- varGet vbShowLocation
+  bShowFullTrace <- varGet vbShowFullTrace
+  set console [ text := "" ]
+  let program = lines txt
+  case arghCompliant program of
+     Just msg -> do
+       case bRunWithErrors of
+         False -> set console [ text := "Argh! invalid:\n" ++ msg ]
+         True -> do
+           let grid = makeGrid program
+           input' <- get input text
+           exec grid (Pointer ArghLeft 1 1) console input' stack bShowLoc bShowFullTrace
+     Nothing -> do
+       let grid = makeGrid program
+       input' <- get input text
+       exec grid (Pointer ArghLeft 1 1) console input' stack bShowLoc bShowFullTrace
+
+{- |
+The main loop. Reads the value from the current 'ArghCell', calls a function to execute
+the command (if needed) and moves in the current execution direction.
+-}
+exec :: ArghGrid -> ArghPointer -> TextCtrl () -> String -> ArghStack -> Bool
+     -> Bool -> IO ()
+exec grid ptr@(Pointer dir x y) console input stack bShowLoc bShowFullTrace = do
+  case getGrid grid x y of
+    Just (Cell s) -> do
+       case chr s of
+          ' ' -> exec grid (move dir ptr) console input stack bShowLoc bShowFullTrace
+          'q' -> set console [ text :~ (++ "\nProgram terminated succesfully.\n") ]
+          'h' -> do if bShowFullTrace then appendText console (show ArghLeft) else return ()
+                    exec grid (move ArghLeft ptr) console input stack bShowLoc bShowFullTrace
+          'j' -> do if bShowFullTrace then appendText console (show ArghDown) else return ()
+                    exec grid (move ArghDown ptr) console input stack bShowLoc bShowFullTrace
+          'k' -> do if bShowFullTrace then appendText console (show ArghUp) else return ()
+                    exec grid (move ArghUp ptr) console input stack bShowLoc bShowFullTrace
+          'l' -> do if bShowFullTrace then appendText console (show ArghRight) else return ()
+                    exec grid (move ArghRight ptr) console input stack bShowLoc bShowFullTrace
+          'H' -> do if bShowFullTrace then appendText console "Going left, looking for value equal to value on top of stack!\n" else return ()
+                    gridMove' grid (move ArghLeft ptr) console input stack bShowLoc bShowFullTrace
+          'J' -> do if bShowFullTrace then appendText console "Going down, looking for value equal to value on top of stack!\n" else return ()
+                    gridMove' grid (move ArghDown ptr) console input stack bShowLoc bShowFullTrace
+          'K' -> do if bShowFullTrace then appendText console "Going up, looking for value equal to value on top of stack!\n" else return ()
+                    gridMove' grid (move ArghUp ptr) console input stack bShowLoc bShowFullTrace
+          'L' -> do if bShowFullTrace then appendText console "Going right, looking for value equal to value on top of stack!\n" else return ()
+                    gridMove' grid (move ArghDown ptr) console input stack bShowLoc bShowFullTrace
+          'x' -> do turnCond grid ptr console input stack bShowLoc (>= 0) turnRight bShowFullTrace
+          'X' -> do turnCond grid ptr console input stack bShowLoc (<= 0)  turnLeft bShowFullTrace
+          's' -> do store grid ptr console input stack bShowLoc (+1) bShowFullTrace
+          'S' -> do store grid ptr console input stack bShowLoc ((+) (-1)) bShowFullTrace
+          'd' -> do dupDel grid ptr console input stack bShowLoc dupl bShowFullTrace
+          'D' -> do dupDel grid ptr console input stack bShowLoc delst bShowFullTrace
+          'a' -> do addRed grid ptr console input stack bShowLoc (+1) addst bShowFullTrace
+          'A' -> do addRed grid ptr console input stack bShowLoc ((+) (-1)) addst bShowFullTrace
+          'r' -> do addRed grid ptr console input stack bShowLoc (+1) redst bShowFullTrace
+          'R' -> do addRed grid ptr console input stack bShowLoc ((+) (-1)) redst  bShowFullTrace
+          'f' -> do popStack grid ptr console input stack bShowLoc (+1) bShowFullTrace
+          'F' -> do popStack grid ptr console input stack bShowLoc ((+) (-1)) bShowFullTrace
+          'p' -> do showCell grid ptr console input stack bShowLoc (+1) bShowFullTrace
+          'P' -> do showCell grid ptr console input stack bShowLoc ((+) (-1)) bShowFullTrace
+          'g' -> do readStore grid ptr console input stack bShowLoc (+1) bShowFullTrace
+          'G' -> do readStore grid ptr console input stack bShowLoc ((+) (-1)) bShowFullTrace
+          '#' -> do
+              case (x,y) == (1,1) of
+                False -> arghError bShowLoc console x y
+                True -> do
+                  case getGrid grid 2 1 of
+                    Just (Cell i) -> do
+                      case i == ord '!' of
+                        False -> arghError bShowLoc console x y
+                        True -> exec grid (move ArghDown ptr) console input stack bShowLoc bShowFullTrace
+                    _ -> arghError bShowLoc console x y
+          _ -> do arghError bShowLoc console x y
+    Just Undefined ->
+      case validPos x y of
+        False -> arghError bShowLoc console x y
+        True -> exec grid (move dir ptr) console input stack bShowLoc bShowFullTrace
+    _ -> arghError bShowLoc console x y
+
+-- ** Command processing
+
+{- |
+Used for the @H@, @J@, @K@ and @L@ commands. It moves over the grid looking for
+a specific value; it outputs an error if it's not found, else it'll continue the
+execution of the program. The actual moving is done by 'gridMove'.
+-}
+gridMove' :: ArghGrid -> ArghPointer -> TextCtrl () -> String -> ArghStack
+          -> Bool -> Bool -> IO ()
+gridMove' grid ptr@(Pointer dir x y) console input stack bShowLoc bShowFullTrace = do
+  case gridMove grid ptr (getTop stack) of
+    Nothing -> arghError bShowLoc console x y
+    Just (a,b) -> do
+      if bShowFullTrace then appendText console "Found value!\n" else return ()
+      exec grid (move dir (Pointer dir a b)) console input stack bShowLoc bShowFullTrace
+
+{- |
+Used for the @x@ and @X@ commands. It checks the value of the stack and turns
+depending on a condition (the @Int -> Bool@ function). Zero is considered to be
+both positive and negative. See the notes above for an explanation.
+-}
+turnCond
+  :: ArghGrid
+  -> ArghPointer
+  -> TextCtrl () -- ^ The main @TextCtrl@ (containing the source code).
+  -> String -- ^ The input (not the source code).
+  -> ArghStack
+  -> Bool -- ^ Show error location in error message yes\/no.
+  -> (Int -> Bool) -- ^ The condition to turn (e.g., @(>= 0)@, @(<= 0)@).
+  -> (ArghDirection -> ArghDirection) -- ^ Turning function (see 'turnLeft' and 'turnRight').
+  -> Bool -- ^ Output all executed commands yes\/no.
+  -> IO ()
+turnCond grid ptr@(Pointer dir x y) console input stack bShowLoc cond f bShowFullTrace = do
+  case getTop stack of
+    Nothing -> arghError bShowLoc console x y
+    Just n ->
+      case cond n of
+        False -> exec grid (move dir ptr) console input stack bShowLoc bShowFullTrace
+        True -> do
+          let newdir = f dir
+          if bShowFullTrace then appendText console (show newdir) else return()
+          exec grid (move newdir ptr) console input stack bShowLoc bShowFullTrace
+
+{- |
+Used for the @s@ and @S@ commands. Pushes the value in the 'ArghCell' above or below
+the current one on the stack.
+-}
+store
+  :: ArghGrid
+  -> ArghPointer
+  -> TextCtrl () -- ^ The main @TextCtrl@ (containing the source code).
+  -> String -- ^ The input (not the source code).
+  -> ArghStack
+  -> Bool -- ^ Show error location in error message yes\/no.
+  -> (Coordinate -> Coordinate) -- ^ Used to calculate new y-coordinate.
+  -> Bool -- ^ Output all executed commands yes\/no.
+  -> IO ()
+store grid ptr@(Pointer dir x y) console input stack bShowLoc f bShowFullTrace = do
+  case getGrid grid x (f y) of
+    Just (Cell i) -> do
+      let stack' = push stack i
+      if bShowFullTrace then viewStack stack' console else return ()
+      exec grid (move dir ptr) console input stack' bShowLoc bShowFullTrace
+    _ -> arghError bShowLoc console x y
+
+
+{- |
+Used for the @d@ and @D@ commands. Duplicates or deletes the value on top off the
+stack, if it exists.
+-}
+dupDel
+  :: ArghGrid
+  -> ArghPointer
+  -> TextCtrl () -- ^ The main @TextCtrl@ (containing the source code).
+  -> String -- ^ The input (not the source code).
+  -> ArghStack
+  -> Bool -- ^ Show error location in error message yes\/no.
+  -> (ArghStack -> Maybe ArghStack) -- ^ The stack operation, see 'dupl' and 'delst'.
+  -> Bool -- ^ Output all executed commands yes\/no.
+  -> IO ()
+dupDel grid ptr@(Pointer dir x y) console input stack bShowLoc f bShowFullTrace= do
+  case f stack of
+    Nothing -> arghError bShowLoc console x y
+    Just stack' -> do
+      if bShowFullTrace then viewStack stack' console else return ()
+      exec grid (move dir ptr) console input stack' bShowLoc bShowFullTrace
+
+{- |
+Used for the @a@, @A@, @r@ and @R@ commands. Adds or reduces the value on top of
+the stack with the value in the 'ArghCell' above or below the current one.
+-}
+addRed
+  :: ArghGrid
+  -> ArghPointer
+  -> TextCtrl () -- ^ The main @TextCtrl@ (containing the source code).
+  -> String -- ^ The input (not the source code).
+  -> ArghStack
+  -> Bool -- ^ Show error location in error message yes\/no.
+  -> (Coordinate -> Coordinate) -- ^ Used to calculate the new y-coordinate.
+  -> (ArghStack -> Int -> Maybe ArghStack) -- ^ The stack operation, see 'addst' and 'redst'.
+  -> Bool -- ^ Output all executed commands yes\/no.
+  -> IO ()
+addRed grid ptr@(Pointer dir x y) console input stack bShowLoc f g bShowFullTrace = do
+  case getGrid grid x (f y) of
+    Just (Cell i) -> do
+      case g stack i of
+        Nothing -> arghError bShowLoc console x y
+        Just stack' -> do
+          if bShowFullTrace then viewStack stack' console else return ()
+          exec grid (move dir ptr) console input stack' bShowLoc bShowFullTrace
+    _ -> arghError bShowLoc console x y
+
+{- |
+Used for the @f@ and @F@ commands. Pops the value from the top of the stack
+and stores it in the 'ArghCell' above or below the current one.
+-}
+popStack
+  :: ArghGrid 
+  -> ArghPointer
+  -> TextCtrl () -- ^ The main @TextCtrl@ (containing the source code).
+  -> String -- ^ The input (not the source code).
+  -> ArghStack
+  -> Bool -- ^ Show error location in error message yes\/no.
+  -> (Coordinate -> Coordinate) -- ^ Used to calculate the new y-coordinate.
+  -> Bool -- ^ Output all executed commands yes\/no.
+  -> IO ()
+popStack grid ptr@(Pointer dir x y) console input stack bShowLoc f bShowFullTrace= do
+  let (pop', stack') = pop stack
+  case pop' of
+    Nothing -> arghError bShowLoc console x y
+    Just i ->
+      case validPos x (f y) of
+        False -> do
+          if bShowFullTrace then viewStack stack' console else return ()
+          arghError bShowLoc console x y
+        True ->
+          case setGrid grid x (f y) i of
+            Nothing -> do
+              if bShowFullTrace then viewStack stack' console else return ()
+              arghError bShowLoc console x y
+            Just grid' -> do
+              if bShowFullTrace then viewStack stack' console else return ()
+              exec grid' (move dir ptr) console input stack' bShowLoc bShowFullTrace
+
+{- |
+Used for the @p@ and @P@ commands. Showing the value of the 'ArghCell' above
+or below the current one.
+-}
+showCell
+  :: ArghGrid
+  -> ArghPointer
+  -> TextCtrl () -- ^ The main @TextCtrl@ (containing the source code).
+  -> String -- ^ The input (not the source code).
+  -> ArghStack
+  -> Bool -- ^ Show error location in error message yes\/no.
+  -> (Coordinate -> Coordinate) -- ^ Used to calculate the new y-coordinate.
+  -> Bool -- ^ Output all executed commands yes\/no.
+  -> IO ()
+showCell grid ptr@(Pointer dir x y) console input stack bShowLoc f bShowFullTrace = do
+  case getGrid grid x (f y) of
+    Just (Cell i) -> do
+      let c = chr i
+      appendText console [c]
+      exec grid (move dir ptr) console input stack bShowLoc bShowFullTrace
+    _ -> arghError bShowLoc console x y
+
+{- |
+Used for the @g@ and @G@ commands. Reads a value from the input (a @String@) and stores
+it in the 'ArghCell' above or below the current one. It outputs an error if the input
+is empty or if the 'ArghCell' above or below the current one doesn't exist.
+-}
+readStore
+  :: ArghGrid
+  -> ArghPointer
+  -> TextCtrl () -- ^ The main @TextCtrl@ (containing the source code).
+  -> String -- ^ The input (not the source code).
+  -> ArghStack
+  -> Bool -- ^ Show error location in error message yes\/no.
+  -> (Coordinate -> Coordinate) -- ^ Used to calculate the new y-coordinate.
+  -> Bool -- ^ Output all executed commands yes\/no.
+  -> IO ()
+readStore grid ptr@(Pointer dir x y) console input stack bShowLoc f bShowFullTrace = do
+  case null input of
+    True -> arghError bShowLoc console x y
+    False -> do
+      case getGrid grid x (f y) of
+        Nothing -> arghError bShowLoc console x y
+        _ -> do
+          let value = ord.head $ input
+          case setGrid grid x (f y) value of
+            Nothing -> arghError bShowLoc console x y
+            Just grid' -> do
+              if bShowFullTrace then appendText console ("Storing: " ++ show value) else return ()
+              exec grid' (move dir ptr) console (tail input) stack bShowLoc bShowFullTrace
+
+-- | Returns an 'ArghPointer' that has been moved in the given 'ArghDirection'.
+move :: ArghDirection -> ArghPointer -> ArghPointer
+move ArghLeft  = move' ((+) (-1)) id ArghLeft
+move ArghRight = move' ((+) 1) id    ArghRight
+move ArghUp    = move' id ((+) (-1)) ArghUp
+move ArghDown  = move' id ((+) 1)    ArghDown
+
+{- |
+Applies the two functions to the location of the 'ArghPointer'. It returns
+a new 'ArghPointer' with the given 'ArghDirection' and the new position.
+-}
+move' :: (Coordinate -> Coordinate) -- ^ Will be applied to the x-coordinate.
+      -> (Coordinate -> Coordinate) -- ^ Will be applied to the y-coordinate.
+      -> ArghDirection -> ArghPointer -> ArghPointer
+move' f g dir (Pointer _ x y) = (Pointer dir (f x) (g y))
+
+-- ** Stack operations
+
+-- | Returns the contents of an 'ArghStack'.
+viewS :: ArghStack -> [Int]
+viewS (Stack s) = s
+
+-- | Outputs the contents of the 'ArghStack' to the specified @TextCtrl@.
+viewStack :: ArghStack -> TextCtrl () -> IO ()
+viewStack (Stack xs) console =
+  appendText console ("Stack: " ++ show xs ++ "\n")
+
+-- | Returns the value on top of the stack (@Just@), else @Nothing@.
+getTop :: ArghStack -> Maybe Int
+getTop = listToMaybe.viewS
+
+-- | Pushes the value on the 'ArghStack'.
+push :: ArghStack -> Int -> ArghStack
+push s x = Stack (x : viewS s)
+
+{- |
+Pops the value off the 'ArghStack'. It returns the
+popped value (if it exists) and the new stack.
+-}
+pop :: ArghStack -> (Maybe Int, ArghStack)
+pop s@(Stack []) = (Nothing, s)
+pop (Stack (x:xs)) = (Just x, Stack xs)
+
+-- | Duplicates the value on top of the 'ArghStack', if it exists.
+dupl :: ArghStack -> Maybe ArghStack
+dupl (Stack xs) = checkToMaybe xs (Stack ((head xs):xs))
+
+-- | Deletes the value on top of the 'ArghStack', if it exists.
+delst :: ArghStack -> Maybe ArghStack
+delst (Stack xs) = checkToMaybe xs (Stack (tail xs))
+
+-- | Redures the value on top of the 'ArghStack', if it exists, by the given value.
+redst :: ArghStack -> Int -> Maybe ArghStack
+redst = opst (-)
+
+-- | Add the given value to the value on top of the 'ArghStack', if it exists.
+addst :: ArghStack -> Int -> Maybe ArghStack
+addst = opst (+)
+
+{- |
+Applies the function and the value to the value on top of the 'ArghStack'.
+Returns the new stack if succesful.
+-}
+opst :: (Int -> Int -> Int) -> ArghStack -> Int -> Maybe ArghStack
+opst f (Stack xs) i = checkToMaybe xs (Stack ((f (head xs) i):(tail xs)))
+
+-- ** Grid operations
+
+{- |
+Sets the value of a value in the 'ArghGrid'. It returns the new grid if
+succesful.
+-}
+setGrid :: ArghGrid -> Coordinate -> Coordinate -> Int -> Maybe ArghGrid
+setGrid grid@(Grid list) x y value =
+  if not (validPos x y)
+  then Nothing
+  else
+    case getRow grid y of
+      Nothing -> Nothing
+      Just l ->
+        let newrow = [concat [(take (x-1) l), [(Cell value)], (drop x l)]]
+        in let newlist = concat [(take (y-1) list), newrow, (drop y list)]
+           in Just (Grid newlist)
+
+{- |
+Moves the 'ArghPointer' over the 'ArghGrid', looking for a specific value.
+Returns the location of the cell where it is found, else @Nothing@.
+-}
+gridMove :: ArghGrid -> ArghPointer -> Maybe Int -> Maybe (Coordinate, Coordinate)
+gridMove _ _ Nothing = Nothing
+gridMove grid ptr@(Pointer dir x y) k@(Just value) =
+ case getGrid grid x y of
+   Just (Cell c) ->
+     case c == value of
+       True -> Just (x,y)
+       False -> gridMove grid (move dir ptr) k
+   _ -> Nothing
+
+{- |
+Creates an 'ArghGrid' for a given 'ArghProgram'. This function performs
+no checks to see if the program is valid. Running the interpreter with an
+invalid Argh! program could result in undefined behaviour. This function
+makes use of the 'maxWidth' and 'maxHeight' constants so the produced
+grid might not have the expected size when constructed from an
+invalid 'ArghProgram'.
+-}
+makeGrid :: ArghProgram -> ArghGrid
+makeGrid s = Grid z2
+  where f = map ((.) Cell ord)
+        g x = let i = length x in if i < maxHeight then x ++ k i else x
+        k i = take (maxHeight-i) (repeat Undefined)
+        z = map (g.f) s
+        z2 = let j = length z in if j < maxWidth then z ++ replicate (maxWidth-j) (k 0) else z
+
+{- |
+Returns a row in the 'ArghGrid', if it exists.
+-}
+getRow :: ArghGrid -> Int -> Maybe [ArghCell]
+getRow (Grid list) n = checkToMaybe' (not.inRange (1,maxWidth) $ n) (list !! (n-1))
+
+{- |
+Returns the value of a specific 'ArghCell' in the 'ArghGrid', if it exists.
+-}
+getGrid :: ArghGrid -> Coordinate -> Coordinate -> Maybe ArghCell
+getGrid _ 0 _ = Nothing
+getGrid _ _ 0 = Nothing
+getGrid grid@(Grid list) x y =
+  case getRow grid y of
+    Nothing -> Nothing
+    Just list ->
+      let dropped = drop (x-1) list
+      in checkToMaybe dropped (head dropped)
+
+-- | Returns @True@ if it's a valid position (x,y).
+validPos :: Coordinate -> Coordinate -> Bool
+validPos x y = inRange (1,maxHeight) x && inRange (1,maxWidth) y
+
+-- ** Code validation
+
+{- |
+Returns an 'ErrorMessage' if the specified @String@ (the Argh! program)
+is invalid. This error message is a combination of the error messages produced
+by 'checkHeight', 'checkWidth' and 'checkChar'.
+-}
+arghCompliant :: ArghProgram -> Maybe ErrorMessage
+arghCompliant [] = Just "There's no program!"
+arghCompliant s = checkToMaybe k k
+  where k = concat.catMaybes $ [ isDir.head.head $ s, checkToMaybe l l ]
+        l = concat.catMaybes $ [checkHeight s, checkWidth s, checkChar s]
+        isDir x = checkToMaybe' (any (==x) "hjkl") string
+        string = concat [ "Character at (1,1) doesn't specify an execution direction.\n"
+                        , "Use 'h' for left, 'j' for down, 'k' for up or 'l' for right.\n" ]
+
+{- |
+Checks the width of the 'ArghProgram'.
+-}
+checkWidth :: ArghProgram -> Maybe ErrorMessage
+checkWidth s = let k = checkLength.map length $ s in checkToMaybe k k
+
+{- |
+Checks the length of the list of @Int@ (each @Int@ is the length of a specific line).
+-}
+checkLength :: [Int] -> ErrorMessage
+checkLength s =
+  let f (a,b) = concat [ "Line ", show a, " has a length of "
+                       , show b, " characters."]
+  in unlines [ f x | x <- (zip [1..] s), (snd x) > maxWidth ]
+
+{- |
+Checks the height of the 'ArghProgram'. Returns
+an 'ErrorMessage' if needed, else @Nothing@.
+-}
+checkHeight :: ArghProgram -> Maybe ErrorMessage
+checkHeight s =
+  let k = length s
+  in checkToMaybe' (k <= maxWidth) (concat ["Too many lines: ", show k, ".\n"])
+
+{- |
+Checks a line for invalid characters. Returns an 'ErrorMessage' if needed,
+else @Nothing@.
+-}
+checkLine :: String -> Maybe ErrorMessage
+checkLine list = let x = g list in checkToMaybe x (j x)
+  where j = concat.intersperse ", ".map show
+        g = map (+1).findIndices (not.validChar)
+
+{- |
+Checks an 'ArghProgram' for invalid characters. Returns
+an 'ErrorMessage' if needed, else @Nothing@.
+-}
+checkChar :: ArghProgram -> Maybe ErrorMessage
+checkChar s = let k = checkChar' s in checkToMaybe k (unlines k)
+  where checkChar' s =
+         let f (a,b) = (a, checkLine b)
+         in filter (not.null) $ [ checkChar2.f $ x | x <- (zip [1..] s) ]
+        checkChar2 (_, Nothing) = ""
+        checkChar2 (n, Just x) =
+          concat [ "Invalid character(s) (Line: ", show n, ", Position(s): ", x, ")." ]
+
+{- |
+Returns @True@ for valid characters. Valid characters have ASCII value 32 - 127
+or newline (10).
+-}
+validChar :: Char -> Bool
+validChar c = let ordc = ord c in ordc >= 32 && ordc < 127 || ordc == 10
+
+-- * Miscellaneous
+
+-- | Returns @Just b@ if the list is not empty, else @Nothing@.
+checkToMaybe :: [a] -> b -> Maybe b
+checkToMaybe xs = checkToMaybe' (null xs)
+
+-- | Returns @Just a@ if @False@, else @Nothing@.
+checkToMaybe' :: Bool -> a -> Maybe a
+checkToMaybe' True  _ = Nothing
+checkToMaybe' False j = Just j
+
+-- | Turns right.
+turnRight :: ArghDirection -> ArghDirection
+turnRight ArghUp    = ArghRight
+turnRight ArghRight = ArghDown
+turnRight ArghDown  = ArghLeft
+turnRight ArghLeft  = ArghUp
+
+-- | Turns left.
+turnLeft :: ArghDirection -> ArghDirection
+turnLeft = turnRight.turnRight.turnRight
+
+-- * User interface
+
+{- |
+Restores the settings (font, wrapping) of the @TextCtrl@.
+-}
+restoreSettings :: TextCtrl () -> IO ()
+restoreSettings code = set code [ text := "", font := fontFixed, wrap := WrapNone ]
+
+{- |
+Used for the /Validate/ button (outputs if the Argh! program is valid or not).
+-}
+buttonCheckCode :: Frame ()
+                -> TextCtrl () -- ^ @TextCtrl@ containing the Argh! source code
+                -> TextCtrl () -- ^ @TextCtrl@ containing the output.
+                -> IO ()
+buttonCheckCode f code console = do
+   txt <- get code text
+   case arghCompliant (lines txt) of
+     Nothing -> set console [ text := "Argh! OK!" ]
+     Just msg -> set console [ text := "Argh! invalid:\n" ++ msg ]
+
+{- |
+Outputs the Argh! error message. If the Bool value is True, it appends
+the location (x,y) where the error occurred (the two Int parameters).
+-}
+arghError :: Bool -> TextCtrl () -> Coordinate -> Coordinate -> IO ()
+arghError bShowLocation console x y =
+  case bShowLocation of
+    False -> set console [ text :~ (++ "Argh!") ]
+    True ->
+      let z = concat [ "Argh! (", show x, ",", show y, ")" ]
+      in set console [ text :~ (++ z) ]
+
+-- | Creates the File menu.
+makeFileMenu :: Frame () -> Var String -> Var String
+             -> TextCtrl () -> TextCtrl () -> IO (Menu ())
+makeFileMenu f filepath filepath' code console = do
+   mfile <- menuPane [ text := "&File" ]
+   mnew <- menuItem mfile [ text := "&New\tCtrl+N"
+                          , on command := onFileNew f filepath code
+                          , help := "Create a new Argh! program" ]
+   mopen <- menuItem mfile [ text := "&Open...\tCtrl+O"
+                           , on command := onFileOpen f filepath code
+                           , help := "Open an existing Argh! program" ]
+   msave <- menuItem mfile [ text := "&Save\tCtrl+S"
+                           , on command := onFileSave f filepath code
+                           , help := "Save the current Argh! program" ]
+   msaveas <- menuItem mfile [ text := "Save &as..."
+                           , on command := onFileSaveAs f filepath code
+                           , help := "Save the current Argh! program with a new name" ]
+   menuLine mfile
+   msaveoutput <- menuItem mfile [ text := "Save output"
+                                 , on command := onFileSaveOutput f filepath' console
+                                 , help := "Save the output" ]
+   msaveoutputas <- menuItem mfile [ text := "Save output as..."
+                                   , on command := onFileSaveOutputAs f filepath' console
+                                   , help := "Save the output with a new name" ]
+   menuLine mfile
+   mquit <- menuQuit mfile [ on command := close f
+                           , help := "Exit the program" ]
+   return mfile
+
+-- | Creates the Help menu.
+makeHelpMenu :: Frame () -> IO (Menu ())
+makeHelpMenu f = do
+  mhelp <- menuPane [ text := "&Help" ]
+  mabout <- menuAbout mhelp [ help := "About this Argh! interpreter"
+                            , on command := onHelpAbout f ]
+  return mhelp
+
+-- | Creates the Edit menu.
+makeEditMenu :: Frame () -> TextCtrl () -> IO (Menu ())
+makeEditMenu f code = do
+  medit <- menuPane [ text := "&Edit" ]
+  mappend <- menuItem medit [ text := "&Append file..."
+                            , on command := onEditAppend f code
+                            , help := "Append the contents of a file" ]
+  return medit
+
+-- | Handles the New option in the File menu.
+onFileNew :: Frame () -> Var String -> TextCtrl () -> IO ()
+onFileNew f filepath code = do
+  txt <- get code text
+  case null txt of
+    True -> return ()
+    False -> do
+      result <- confirmDialog f "Argh!" "The current Argh! program will be lost. Want to save?" True
+      case result of
+        False -> restoreSettings code
+        True -> do
+          filepath' <- get filepath value
+          result <- fileSaveDialog f True True "Save Argh! program" saveFiles filepath' ""
+          case result of
+            Nothing -> return ()
+            Just path -> do
+              set filepath [ value := path ]
+              writeFile path txt
+              restoreSettings code
+
+-- | Handles the Open option in the File menu.
+onFileOpen :: Frame () -> Var String -> TextCtrl () -> IO ()
+onFileOpen f filepath code = do
+  result <- fileOpenDialog f True True "Open Argh! program" openFiles "" ""
+  case result of
+    Nothing -> return ()
+    Just path -> do
+      exists <- doesFileExist path
+      case exists of
+        False -> return ()
+        True -> do
+          contents <- readFile path
+          restoreSettings code
+          set code [ text := contents ]
+          set filepath [ value := path ]
+
+-- | Handles the Save option in the File menu.
+onFileSave :: Frame () -> Var String -> TextCtrl () -> IO ()
+onFileSave f filepath code = do
+  txt <- get code text
+  filepath' <- get filepath value
+  writeFile filepath' txt
+
+-- | Handles the Save as option in the File menu.
+onFileSaveAs :: Frame () -> Var String -> TextCtrl () -> IO ()
+onFileSaveAs f filepath code = do
+  txt <- get code text
+  filepath' <- get filepath value
+  result <- fileSaveDialog f True True "Save Argh! program" saveFiles filepath' ""
+  case result of
+    Nothing -> return ()
+    Just path -> do
+      set filepath [ value := path ]
+      writeFile path txt
+
+-- | Handles the Save output option in the File menu.
+onFileSaveOutput :: Frame () -> Var String -> TextCtrl () -> IO ()
+onFileSaveOutput f filepath console = do
+  output <- get console text
+  filepath' <- get filepath value
+  writeFile filepath' output
+
+-- | Handles the Save output as option in the File menu.
+onFileSaveOutputAs :: Frame () -> Var String -> TextCtrl () -> IO ()
+onFileSaveOutputAs f filepath console = do
+  output <- get console text
+  filepath' <- get filepath value
+  result <- fileSaveDialog f True True "Save output" outputFiles filepath' ""
+  case result of
+    Nothing -> return ()
+    Just path -> do
+      set filepath [ value := path ]
+      writeFile path output
+
+-- | Handles the Append output option in the Edit menu.
+onEditAppend :: Frame () -> TextCtrl () -> IO ()
+onEditAppend f code = do
+  result <- fileOpenDialog f True True "Append file" openFiles "" ""
+  case result of
+    Nothing -> return ()
+    Just path -> do
+      exists <- doesFileExist path
+      case exists of
+        False -> return ()
+        True -> do
+          currentCode <- get code text
+          contents <- readFile path
+          restoreSettings code
+          set code [ text := (currentCode ++ contents) ]
+
+-- | Handles the About option in the Help menu.
+onHelpAbout :: Frame () -> IO ()
+onHelpAbout f = do
+  let string = unlines [ "Version " ++ show version ++ " - Created by Simeon Visser, February 2007."
+                       , ""
+                       , "For more information, see included readme and documentation."
+                       , ""
+                       , "Available under the GNU General Public License." ]
+  infoDialog f "About this Argh! interpreter" string
+ GPL.txt view
@@ -0,0 +1,339 @@+		    GNU GENERAL PUBLIC LICENSE+		       Version 2, June 1991++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA+ Everyone is permitted to copy and distribute verbatim copies+ of this license document, but changing it is not allowed.++			    Preamble++  The licenses for most software are designed to take away your+freedom to share and change it.  By contrast, the GNU General Public+License is intended to guarantee your freedom to share and change free+software--to make sure the software is free for all its users.  This+General Public License applies to most of the Free Software+Foundation's software and to any other program whose authors commit to+using it.  (Some other Free Software Foundation software is covered by+the GNU Lesser General Public License instead.)  You can apply it to+your programs, too.++  When we speak of free software, we are referring to freedom, not+price.  Our General Public Licenses are designed to make sure that you+have the freedom to distribute copies of free software (and charge for+this service if you wish), that you receive source code or can get it+if you want it, that you can change the software or use pieces of it+in new free programs; and that you know you can do these things.++  To protect your rights, we need to make restrictions that forbid+anyone to deny you these rights or to ask you to surrender the rights.+These restrictions translate to certain responsibilities for you if you+distribute copies of the software, or if you modify it.++  For example, if you distribute copies of such a program, whether+gratis or for a fee, you must give the recipients all the rights that+you have.  You must make sure that they, too, receive or can get the+source code.  And you must show them these terms so they know their+rights.++  We protect your rights with two steps: (1) copyright the software, and+(2) offer you this license which gives you legal permission to copy,+distribute and/or modify the software.++  Also, for each author's protection and ours, we want to make certain+that everyone understands that there is no warranty for this free+software.  If the software is modified by someone else and passed on, we+want its recipients to know that what they have is not the original, so+that any problems introduced by others will not reflect on the original+authors' reputations.++  Finally, any free program is threatened constantly by software+patents.  We wish to avoid the danger that redistributors of a free+program will individually obtain patent licenses, in effect making the+program proprietary.  To prevent this, we have made it clear that any+patent must be licensed for everyone's free use or not licensed at all.++  The precise terms and conditions for copying, distribution and+modification follow.++		    GNU GENERAL PUBLIC LICENSE+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION++  0. This License applies to any program or other work which contains+a notice placed by the copyright holder saying it may be distributed+under the terms of this General Public License.  The "Program", below,+refers to any such program or work, and a "work based on the Program"+means either the Program or any derivative work under copyright law:+that is to say, a work containing the Program or a portion of it,+either verbatim or with modifications and/or translated into another+language.  (Hereinafter, translation is included without limitation in+the term "modification".)  Each licensee is addressed as "you".++Activities other than copying, distribution and modification are not+covered by this License; they are outside its scope.  The act of+running the Program is not restricted, and the output from the Program+is covered only if its contents constitute a work based on the+Program (independent of having been made by running the Program).+Whether that is true depends on what the Program does.++  1. You may copy and distribute verbatim copies of the Program's+source code as you receive it, in any medium, provided that you+conspicuously and appropriately publish on each copy an appropriate+copyright notice and disclaimer of warranty; keep intact all the+notices that refer to this License and to the absence of any warranty;+and give any other recipients of the Program a copy of this License+along with the Program.++You may charge a fee for the physical act of transferring a copy, and+you may at your option offer warranty protection in exchange for a fee.++  2. You may modify your copy or copies of the Program or any portion+of it, thus forming a work based on the Program, and copy and+distribute such modifications or work under the terms of Section 1+above, provided that you also meet all of these conditions:++    a) You must cause the modified files to carry prominent notices+    stating that you changed the files and the date of any change.++    b) You must cause any work that you distribute or publish, that in+    whole or in part contains or is derived from the Program or any+    part thereof, to be licensed as a whole at no charge to all third+    parties under the terms of this License.++    c) If the modified program normally reads commands interactively+    when run, you must cause it, when started running for such+    interactive use in the most ordinary way, to print or display an+    announcement including an appropriate copyright notice and a+    notice that there is no warranty (or else, saying that you provide+    a warranty) and that users may redistribute the program under+    these conditions, and telling the user how to view a copy of this+    License.  (Exception: if the Program itself is interactive but+    does not normally print such an announcement, your work based on+    the Program is not required to print an announcement.)++These requirements apply to the modified work as a whole.  If+identifiable sections of that work are not derived from the Program,+and can be reasonably considered independent and separate works in+themselves, then this License, and its terms, do not apply to those+sections when you distribute them as separate works.  But when you+distribute the same sections as part of a whole which is a work based+on the Program, the distribution of the whole must be on the terms of+this License, whose permissions for other licensees extend to the+entire whole, and thus to each and every part regardless of who wrote it.++Thus, it is not the intent of this section to claim rights or contest+your rights to work written entirely by you; rather, the intent is to+exercise the right to control the distribution of derivative or+collective works based on the Program.++In addition, mere aggregation of another work not based on the Program+with the Program (or with a work based on the Program) on a volume of+a storage or distribution medium does not bring the other work under+the scope of this License.++  3. You may copy and distribute the Program (or a work based on it,+under Section 2) in object code or executable form under the terms of+Sections 1 and 2 above provided that you also do one of the following:++    a) Accompany it with the complete corresponding machine-readable+    source code, which must be distributed under the terms of Sections+    1 and 2 above on a medium customarily used for software interchange; or,++    b) Accompany it with a written offer, valid for at least three+    years, to give any third party, for a charge no more than your+    cost of physically performing source distribution, a complete+    machine-readable copy of the corresponding source code, to be+    distributed under the terms of Sections 1 and 2 above on a medium+    customarily used for software interchange; or,++    c) Accompany it with the information you received as to the offer+    to distribute corresponding source code.  (This alternative is+    allowed only for noncommercial distribution and only if you+    received the program in object code or executable form with such+    an offer, in accord with Subsection b above.)++The source code for a work means the preferred form of the work for+making modifications to it.  For an executable work, complete source+code means all the source code for all modules it contains, plus any+associated interface definition files, plus the scripts used to+control compilation and installation of the executable.  However, as a+special exception, the source code distributed need not include+anything that is normally distributed (in either source or binary+form) with the major components (compiler, kernel, and so on) of the+operating system on which the executable runs, unless that component+itself accompanies the executable.++If distribution of executable or object code is made by offering+access to copy from a designated place, then offering equivalent+access to copy the source code from the same place counts as+distribution of the source code, even though third parties are not+compelled to copy the source along with the object code.++  4. You may not copy, modify, sublicense, or distribute the Program+except as expressly provided under this License.  Any attempt+otherwise to copy, modify, sublicense or distribute the Program is+void, and will automatically terminate your rights under this License.+However, parties who have received copies, or rights, from you under+this License will not have their licenses terminated so long as such+parties remain in full compliance.++  5. You are not required to accept this License, since you have not+signed it.  However, nothing else grants you permission to modify or+distribute the Program or its derivative works.  These actions are+prohibited by law if you do not accept this License.  Therefore, by+modifying or distributing the Program (or any work based on the+Program), you indicate your acceptance of this License to do so, and+all its terms and conditions for copying, distributing or modifying+the Program or works based on it.++  6. Each time you redistribute the Program (or any work based on the+Program), the recipient automatically receives a license from the+original licensor to copy, distribute or modify the Program subject to+these terms and conditions.  You may not impose any further+restrictions on the recipients' exercise of the rights granted herein.+You are not responsible for enforcing compliance by third parties to+this License.++  7. If, as a consequence of a court judgment or allegation of patent+infringement or for any other reason (not limited to patent issues),+conditions are imposed on you (whether by court order, agreement or+otherwise) that contradict the conditions of this License, they do not+excuse you from the conditions of this License.  If you cannot+distribute so as to satisfy simultaneously your obligations under this+License and any other pertinent obligations, then as a consequence you+may not distribute the Program at all.  For example, if a patent+license would not permit royalty-free redistribution of the Program by+all those who receive copies directly or indirectly through you, then+the only way you could satisfy both it and this License would be to+refrain entirely from distribution of the Program.++If any portion of this section is held invalid or unenforceable under+any particular circumstance, the balance of the section is intended to+apply and the section as a whole is intended to apply in other+circumstances.++It is not the purpose of this section to induce you to infringe any+patents or other property right claims or to contest validity of any+such claims; this section has the sole purpose of protecting the+integrity of the free software distribution system, which is+implemented by public license practices.  Many people have made+generous contributions to the wide range of software distributed+through that system in reliance on consistent application of that+system; it is up to the author/donor to decide if he or she is willing+to distribute software through any other system and a licensee cannot+impose that choice.++This section is intended to make thoroughly clear what is believed to+be a consequence of the rest of this License.++  8. If the distribution and/or use of the Program is restricted in+certain countries either by patents or by copyrighted interfaces, the+original copyright holder who places the Program under this License+may add an explicit geographical distribution limitation excluding+those countries, so that distribution is permitted only in or among+countries not thus excluded.  In such case, this License incorporates+the limitation as if written in the body of this License.++  9. The Free Software Foundation may publish revised and/or new versions+of the General Public License from time to time.  Such new versions will+be similar in spirit to the present version, but may differ in detail to+address new problems or concerns.++Each version is given a distinguishing version number.  If the Program+specifies a version number of this License which applies to it and "any+later version", you have the option of following the terms and conditions+either of that version or of any later version published by the Free+Software Foundation.  If the Program does not specify a version number of+this License, you may choose any version ever published by the Free Software+Foundation.++  10. If you wish to incorporate parts of the Program into other free+programs whose distribution conditions are different, write to the author+to ask for permission.  For software which is copyrighted by the Free+Software Foundation, write to the Free Software Foundation; we sometimes+make exceptions for this.  Our decision will be guided by the two goals+of preserving the free status of all derivatives of our free software and+of promoting the sharing and reuse of software generally.++			    NO WARRANTY++  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,+REPAIR OR CORRECTION.++  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE+POSSIBILITY OF SUCH DAMAGES.++		     END OF TERMS AND CONDITIONS++	    How to Apply These Terms to Your New Programs++  If you develop a new program, and you want it to be of the greatest+possible use to the public, the best way to achieve this is to make it+free software which everyone can redistribute and change under these terms.++  To do so, attach the following notices to the program.  It is safest+to attach them to the start of each source file to most effectively+convey the exclusion of warranty; and each file should have at least+the "copyright" line and a pointer to where the full notice is found.++    <one line to give the program's name and a brief idea of what it does.>+    Copyright (C) <year>  <name of author>++    This program is free software; you can redistribute it and/or modify+    it under the terms of the GNU General Public License as published by+    the Free Software Foundation; either version 2 of the License, or+    (at your option) any later version.++    This program is distributed in the hope that it will be useful,+    but WITHOUT ANY WARRANTY; without even the implied warranty of+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+    GNU General Public License for more details.++    You should have received a copy of the GNU General Public License along+    with this program; if not, write to the Free Software Foundation, Inc.,+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.++Also add information on how to contact you by electronic and paper mail.++If the program is interactive, make it output a short notice like this+when it starts in an interactive mode:++    Gnomovision version 69, Copyright (C) year name of author+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.+    This is free software, and you are welcome to redistribute it+    under certain conditions; type `show c' for details.++The hypothetical commands `show w' and `show c' should show the appropriate+parts of the General Public License.  Of course, the commands you use may+be called something other than `show w' and `show c'; they could even be+mouse-clicks or menu items--whatever suits your program.++You should also get your employer (if you work as a programmer) or your+school, if any, to sign a "copyright disclaimer" for the program, if+necessary.  Here is a sample; alter the names:++  Yoyodyne, Inc., hereby disclaims all copyright interest in the program+  `Gnomovision' (which makes passes at compilers) written by James Hacker.++  <signature of Ty Coon>, 1 April 1989+  Ty Coon, President of Vice++This General Public License does not permit incorporating your program into+proprietary programs.  If your program is a subroutine library, you may+consider it more useful to permit linking proprietary applications with the+library.  If this is what you want to do, use the GNU Lesser General+Public License instead of this License.
+ Readme.txt view
@@ -0,0 +1,22 @@+An interpreter (v0.8) for the Argh! programming language
+
+-- Contents of this package --
+
+The following files are included:
+
+- Readme.txt (this file)
+- Argh.hs (the source)
+- GPL.txt (the GNU General Public License text)
+- /doc (Haddock documentation)
+
+-- Information --
+
+Argh! is an esoteric programming language created by Sascha Wilde. An Argh! program is a two-dimensional grid (80x40 cells) and each cell contains an integer that can be interpreted as such or as a command that can be executed. A stack is used to store values and to do calculations. For more information about Argh!, see http://www.sha-bang.de/index.php?page=12_eso (in German).
+
+The source code has been documented using Haddock. Just view that for more information about a function and the interpreter in general.
+
+To start the interpreter, use the "main" function.
+
+Simeon Visser
+February 2007
+<svisser@cs.uu.nl>
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple
+main = defaultMain
+ arghwxhaskell.cabal view
@@ -0,0 +1,28 @@+-- Initial arghwxhaskell.cabal generated by cabal init.  For further 
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+name:                arghwxhaskell
+version:             0.8.1.0
+synopsis:            An interpreter for the Argh! programming language in wxHaskell.
+description:         An interpreter for the Argh! esoteric programming language in
+                     wxHaskell. The program allows one to load, edit, save, validate
+                     and run Argh! programs. It currently supports all commands
+                     except 'e' and 'E'.
+homepage:            https://wiki.haskell.org/Argh!
+license:             GPL-2
+license-file:        GPL.txt
+author:              Simeon Visser
+maintainer:          -
+-- copyright:           
+category:            Language
+build-type:          Simple
+extra-source-files:  Readme.txt
+cabal-version:       >=1.10
+
+executable arghwxhaskell
+  main-is:             Argh.hs
+  -- other-modules:       
+  -- other-extensions:    
+  build-depends:       base >=4.8 && <4.9, directory >=1.2 && <1.3, wx >=0.92 && <0.93
+  -- hs-source-dirs:      
+  default-language:    Haskell98