{-# OPTIONS_GHC -fno-warn-tabs #-}
{-# OPTIONS_HADDOCK show-extensions #-}
{-# LANGUAGE TypeOperators #-}
{-|
Module      : StackA
Description : Stack Automaton
Copyright   : (c) Jorge Santiago Alvarez Cuadros, 2016
License     : GPL-3
Maintainer  : sanjorgek@ciencias.unam.mx
Stability   : experimental
Portability : portable

Stack Automaton
-}
module Math.Model.Automaton.Stack
(
	Delta(..)
	,liftD
	,StackA(..)
	,checkString
) where
import Data.List
import Data.Monoid
import qualified Data.Map.Lazy as Map
import qualified Data.Foldable as Fold
import Data.Delta
import Data.State
import Data.Sigma

{-|
Delta for stack machine, takes a state, a symbol in string input and a symbol in
stack head and returns next state and update stack
-}
type Delta a = (:->:) a (Symbol, Symbol) [Symbol]

{-|
Takes a list of tuples and lift a Delta

>>>let delta = liftD [(0,'1','A',1,[AA]),(0,'0',blank,0,[A])]
-}
liftD::(Ord a) => [(a, Symbol, Symbol, a, [Symbol])]-> Delta a
liftD xs = let
		(as,bs,cs,ds,es) = unzip5 xs
		f = map (Q)
		p = zip bs cs
		k = zip (f as) p
		r = zip (f ds) es
	in Map.fromList (zip k r)

-- |Stack machine only needs a delta and a init state
data StackA a = S (Delta a) (State a)

{-|
Executes a stack machine over a word

>>>checkString autStack 'aaabbbcccccc'
True
-}
checkString::(Ord a) => StackA a -> Wd -> Bool
checkString (S d s) ws = let
		q = checkString' d s [z0] ws
		f = not.isError
	in f q
	where
		check dt s = if Map.member s dt then dt Map.! s else (QE,[])
		checkString' _ QE _ _ = QE
		checkString' _ q [] [] = q
		checkString' _ _ (_:_) [] = QE
		checkString' _ q [] (_:_) = QE
		checkString' dt q (x:xs) (y:ys) = let 
				(qn, st) = check dt (q, (y, x))
			in checkString' dt qn (st++xs) ys