import re
import unittest
import logging

logger = logging.getLogger(__name__)

'''
THINKABOUTIT
maybe we are missing the point of structural programming
by implementing {key => value} ans [value]
who does exactly {"key":value} and [value]
maybe we should just let straight json here
that mean no string int bool declaration too
RULE
variable start with lowercase, then [index] (param) {key} and . are authorised
function and namespace start with uppercase
the only way to reach an odd name like Peach or 23l337 will use {}
lambda are string, and a relative functor is generated on the fly
TODO
monad as a list of lambda
closure as {predicate=>[...],routine=>[...],return=>...}
predicate
list comprehension
function lib
user function
TODONT
quine, you cant serialise Lib, but scope yes, just use $
WISHLIST
sql sugar synthax %SELECT FROM WHERE%()
regex sugar synthax /^[^\.]+$/gmi()
filename sugar synthax #./#
bitsynthax <...>
'''


def pparse(fsm, expr, scope, lib):
        logger.debug('pparse(%s, %s, %s, %s)' % (fsm, expr, scope, lib))
        stateName = ['begin']
        ctx = []
        fn = []
        mayend = fsm[stateName[0]].end()
        while stateName:
                logger.debug('pparse(...) # %s' % stateName)
                mayend = fsm[stateName[0]].end()
                expr, scope, lib, fn = fsm[stateName[0]].val(expr.strip(), scope, lib, fn)
                stateName = [nextState
                         for nextState in fsm[stateName[0]].next()
                         if nextState in fsm
                         if fsm[nextState].validate(expr.strip())]
        if not mayend:
                logger.error('pparse(...) ! Synthax error in expression [%s]' % expr)
                raise Exception('Synthax error in expression [%s]' % expr)
        logger.debug('pparse(...) -> (%s, %s)' % (expr, ctx))
        return expr.strip(), fn


def parse(fsm, expr, scope, lib):
        logger.debug('parse(%s, %s, %s, %s)' % (fsm, expr, scope, lib))
        expr, fns = pparse(fsm, expr, scope, lib)
        if expr:
                logger.error('parse(...) ! Synthax error on %s cant end like that' % expr)
                raise Exception('Synthax error on %s cant end like that' % expr)
        # resolve
        for fn in fns:
                scope = fn(scope)
        logger.debug('parse(...) -> (%s)' % scope)
        return scope


_nameregex = r'^([a-z_][A-Za-z0-9_]*)'
_dotregex = r'^\.'
_indexregex = r'^\[([0-9]+)\]'
_indexrefregex = r'^\[([a-z_][A-Za-z0-9_]*)\]'
_stringregex = r"^'([^']*)'"
_numberregex = r"^([0-9]+(\.[0-9]+)?)"
_boolregex = r"^(True)|(False)"
_namedotindexregex = r"[a-z][A-Za-z0-9_]*((\[[0-9]+\])|(\.[a-z][A-Za-z0-9_]+))*"
_valregex = r"('[^']*')|([0-9]+(\.[0-9]+)?)|(%s)|(True)|(False)" % _namedotindexregex
_dictbeginregex = r"^(\{)"
_dictvalregex = r"^([a-z_][a-zA-Z0-9_]*)=>"
_bindregex = r"^([a-z_][a-zA-Z0-9_]*)[\n\r\t ]*=>"
_dictcomaregex = r"^(,)"
_dictendregex = r"^(\})"
_listbeginregex = r"^(\[)"
_listvalregex = r"^(%s)"
_listcomaregex = r"^(,)"
_listendregex = r"^(\])"

_nope = lambda ctx: []


class Base(object):
        def validate(self, expr):
                raise NotImplementedError("Unimplemented")

        def next(self):
                raise NotImplementedError("Unimplemented")

        def end(self):
                raise NotImplementedError("Unimplemented")

        def val(self, expr, scope, lib, fn=[]):
                raise NotImplementedError("Unimplemented")

class Begin(Base):
        def __init__(self, beginWith=[]):
                self.beginWith = beginWith

        def validate(self, expr):
                return True

        def next(self):
                return self.beginWith

        def end(self):
                return False

        def val(self, expr, scope, lib, fn=[]):
                """
                """
                assert isinstance(expr, str)
                #assert isinstance(scope, dict)
                assert isinstance(lib, dict)
                return expr, scope, lib, fn

class Scope(Base):
        def validate(self, expr):
                return re.match(r'^\$',expr)
                
        def next(self):
                return ['dot','index','lambdacall']

        def end(self):
                return True

        def val(self,expr,scope,lib,fn=[]):
                """
                [(scope)->(..)]
                """
                assert isinstance(expr, str)
                assert isinstance(lib, dict)
                #assert isinstance(scope,dict)
                exprMatch = self.validate(expr)
                expr = expr.replace(exprMatch.group(0),'',1)
                fn.append(lambda param : scope)
                return expr,scope,lib,fn

class Name(Base):
        def validate(self, expr):
                return re.match(_nameregex, expr)

        def next(self):
                return ['dot', 'index', 'lambdacall']

        def end(self):
                return True

        def val(self, expr, scope, lib, fn=[]):
                assert isinstance(expr, str)
                assert isinstance(lib, dict)
                assert isinstance(scope,dict)
                logger.debug('Name(%s, %s, %s, %s)' % (expr, scope, lib, fn))
                exprMatch = self.validate(expr)
                key = exprMatch.group(1)
                # closure
                def closure(param):
                        if key in param:
                                ctx = param[key]
                        else:
                                ctx = []
                        return ctx
                fn.append(closure)
                expr = expr.replace(exprMatch.group(0), '', 1)
                logger.debug('Name(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
                return expr, scope, lib, fn


class Dot(Base):
        def validate(self, expr):
                return re.match(r'\.', expr)

        def next(self):
                return ['name']

        def end(self):
                return False

        def val(self, expr, scope, lib, fn=[]):
                assert isinstance(expr, str)
                assert isinstance(scope, dict)
                assert isinstance(lib, dict)
                logger.debug('Dot(%s, %s, %s, %s)' % (expr, scope, lib, fn))
                exprMatch = self.validate(expr)
                # closure
                def closure(param):
                        assert isinstance(param, dict)
                        return param

                fn.append(closure)
                expr = expr.replace(exprMatch.group(0), '', 1)
                logger.debug('Dot(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
                return expr, scope, lib, fn


class Index(Base):
        '''
        if the ctx is a list,
        and index is an itegral
        it will yield ctx[index]
        '''

        def validate(self, expr):
                return re.match(r'^\[', expr)
        def next(self):
                return ['dot', 'lambdacall','index']

        def end(self):
                return True

        def val(self, expr, scope, lib, fn=[]):
                assert isinstance(expr, str)
                assert isinstance(scope, dict)
                assert isinstance(lib, dict)
                # ssert isinstance(ctx, list)
                # TODO support term between [] here
                logger.debug('Index(%s, %s, %s, %s)' % (expr, scope, lib, fn))
                exprMatch = self.validate(expr)
                expr = expr.replace(exprMatch.group(0),'',1)
                expr, fns = pparse(fsm, expr, scope, lib)
                expr = expr.replace(re.match(r'^\]',expr).group(0),'',1)
                # closure
                def closure(param):
                        assert isinstance(param, list)
                        index = scope
                        for _fn in fns:
                                index = _fn(index)
                        assert isinstance(index,int)
                        if len(param) > index:
                                ret = param[index]
                        else:
                                ret = []
                        return ret
                fn.append(closure)
                logger.debug('Index(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
                return expr, scope, lib, fn


class Key(Base):
        '''
        if the ctx is a list,
        and indexref is a name
        then index will take value from indexref
        then if index is integrale
        yield ctx[index]

        it is not possible to use name.sub or name[5] as index ref
        '''

        def validate(self, expr):
                return re.match(r'^\{', expr)

        def validateEnd(self,expr):
                return re.match(r'^\}',expr)

        def next(self):
                return ['dot', 'lambdacall','index']

        def end(self):
                return True

        def val(self, expr, scope, lib, fn=[]):
                assert isinstance(expr, str)
                assert isinstance(scope, dict)
                assert isinstance(lib, dict)
                # assert isinstance(ctx, list)
                # TODO support term between [] here
                logger.debug('Index(%s, %s, %s, %s)' % (expr, scope, lib, fn))
                exprMatch = self.validate(expr)
                expr = expr.replace(exprMatch.group(0),'',1)
                expr, fns = pparse(fsm, expr, scope, lib)
                expr = expr.replace(self.validateEnd(expr),'',1)
                # closure
                def closure(param):
                        if not isinstance(param, dict):
                                return []
                        key = scope
                        for _fn in fns:
                                key = _fn(key)
                        assert isinstance(key, str)
                        if key in param:
                                ret = param[key]
                        else:
                                ret = []
                        return ret
                fn.append(closure)
                expr = expr.replace(exprMatch.group(0), '', 1)
                logger.debug('Index(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
                return expr, scope, lib, fn

class String(Base):
        def validate(self, expr):
                return re.match(_stringregex, expr)

        def next(self):
                return []

        def end(self):
                return True

        def val(self, expr, scope, lib, fn=[]):
                assert isinstance(expr, str)
                assert isinstance(lib, dict)
                logger.debug('String(%s, %s, %s, %s)' % (expr, scope, lib, fn))
                exprMatch = self.validate(expr)
                ret = exprMatch.group(1)
                fn.append(lambda param: ret)
                expr = expr.replace(exprMatch.group(0), '', 1)
                logger.debug('String(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
                return expr, scope, lib, fn


class Number(Base):
        def validate(self, expr):
                return re.match(_numberregex, expr)

        def next(self):
                return []

        def end(self):
                return True

        def val(self, expr, scope, lib, fn=[]):
                assert isinstance(expr, str)
                # assert isinstance(db, dict)
                assert isinstance(lib, dict)
                logger.debug('Number(%s, %s, %s, %s)' % (expr, scope, lib, fn))
                exprMatch = self.validate(expr)
                # closure
                def closure(param):
                        if exprMatch.group(2):
                                ctx = float(exprMatch.group(1))
                        else:
                                ctx = int(exprMatch.group(1))
                        return ctx
                fn.append(closure)
                expr = expr.replace(exprMatch.group(0), '', 1)
                logger.debug('Number(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
                return expr, scope, lib, fn


class Bool(Base):
        def validate(self, expr):
                return re.match(_boolregex, expr)

        def next(self):
                return []

        def end(self):
                return True

        def val(self, expr, scope, lib, fn=[]):
                assert isinstance(expr, str)
                # assert isinstance(db, dict)
                assert isinstance(lib, dict)
                logger.debug('Bool(%s, %s, %s, %s)' % (expr, scope, lib, fn))
                exprMatch = self.validate(expr)
                ret = exprMatch.group(1) == 'True'
                # closure
                def closure(param):
                        return ret
                fn.append(lambda _dontcare : ret)
                expr = expr.replace(exprMatch.group(0), '', 1)
                logger.debug('Bool(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
                return expr, scope, lib, fn


class Bind(Base):
        def validate(self, expr):
                return re.match(_bindregex, expr)

        def next(self):
                return []

        def end(self):
                return True
        def val(self, expr, scope, lib, fn=[]):
                assert isinstance(expr, str)
                assert isinstance(scope, dict)
                assert isinstance(lib, dict)
                logger.debug('Bind(%s, %s, %s, %s)' % (expr, scope, lib, fn))
                exprMatch = self.validate(expr)
                key = exprMatch.group(1)
                expr = expr.replace(exprMatch.group(0), '', 1)
                expr, fns = pparse(fsm, expr, scope, lib)
                # closure
                def closure(_db):
                        param = scope
                        for fn in fns:
                                param = fn(param)
                        return {key: param}
                #fn.append(closure)
                fn.append(lambda _dontcare : scope)
                fn += fns
                fn.append(lambda param : {key : param})
                logger.debug('Bind(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
                return expr, scope, lib, fn


class DictBegin(Base):
        def validate(self, expr):
                return re.match(_dictbeginregex, expr)

        def next(self):
                return ['dictval', 'dictend']

        def end(self):
                return False

        def val(self, expr, scope, lib, fn=[]):
                assert isinstance(expr, str)
                assert isinstance(scope, dict)
                assert isinstance(lib, dict)
                logger.debug('DictBegin(%s, %s, %s, %s)' % (expr, scope, lib, fn))
                exprMatch = self.validate(expr)
                expr = expr.replace(exprMatch.group(0), '', 1)
                fn.append(lambda _db: {})
                logger.debug('DictBegin(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
                return expr, scope, lib, fn

class DictVal(Base):
        '''
        recursive dictionary is only possible by declarring dictionary first then refer it.
        '''

        def validate(self, expr):
                return True

        def next(self):
                return ['dictcoma', 'dictend']

        def end(self):
                return False

        def val(self, expr, scope, lib, fn=[]):
                assert isinstance(expr, str)
                assert isinstance(scope, dict)
                assert isinstance(lib, dict)
                logger.debug('DictVal(%s, %s, %s, %s)' % (expr, scope, lib, fn))
                expr, fns = pparse(fsmbind, expr, scope, lib)
                # closure
                def closure(_db):
                        assert isinstance(_db, dict)
                        param = scope
                        for fn in fns:
                                param = fn(param)
                        assert isinstance(param, dict)
                        assert not [True for key in param.keys() if key in _db]
                        _db.update(param)
                        return _db

                fn.append(closure)
                logger.debug('DictVal(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
                return expr, scope, lib, fn


class DictComa(Base):
        def validate(self, expr):
                return re.match(_dictcomaregex, expr)

        def end(self):
                return False
        def val(self, expr, scope, lib, fn=[]):
                assert isinstance(expr, str)
                assert isinstance(scope, dict)
                assert isinstance(lib, dict)
                logger.debug('DictComa(%s, %s, %s, %s)' % (expr, scope, lib, fn))
                exprMatch = self.validate(expr)
                expr = expr.replace(exprMatch.group(0), '', 1)
                logger.debug('DictComa(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
                return expr, scope, lib, fn

        def next(self):
                return ['dictval']


class DictEnd(Base):
        def validate(self, expr):
                return re.match(_dictendregex, expr)

        def next(self):
                return []

        def end(self):
                return True

        def val(self, expr, scope, lib, fn=[]):
                assert isinstance(expr, str)
                assert isinstance(scope, dict)
                assert isinstance(lib, dict)
                logger.debug('DictEnd(%s, %s, %s, %s)' % (expr, scope, lib, fn))
                exprMatch = self.validate(expr)
                expr = expr.replace(exprMatch.group(0), '', 1)
                logger.debug('DictEnd(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
                return expr, scope, lib, fn


class LList(Base):
        def validate(self, expr):
                return re.match(r'\[', expr)

        def validateEnd(self, expr):
                return re.match(r'\]', expr)

        def next(self):
                return ['listval']

        def end(self):
                return False

        def val(self, expr, scope, lib, fn=[]):
                assert isinstance(expr, str)
                assert isinstance(scope, dict)
                assert isinstance(lib, dict)
                logger.debug('LList(%s, %s, %s, %s)' % (expr, scope, lib, fn))
                exprMatch = self.validate(expr)
                expr = expr.replace(exprMatch.group(0), '', 1)
                fn.append(lambda db: [])
                logger.debug('LList(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
                return expr, scope, lib, fn


class LListVal(Base):
        def validate(self, expr):
                return True

        def next(self):
                return ['listcoma', 'listend']

        def end(self):
                return False

        def val(self, expr, scope, lib, fn=[]):
                assert isinstance(expr, str)
                assert isinstance(scope, dict)
                assert isinstance(lib, dict)
                logger.debug('LListVal(%s, %s, %s, %s)' % (expr, scope, lib, fn))
                expr, fns = pparse(fsm, expr, scope, lib)
                # closure
                def closure(_db):
                        assert isinstance(_db, list)
                        param = scope
                        for fn in fns:
                                param = fn(param)
                        _db.append(param)
                        return _db
                fn.append(closure)
                logger.debug('LListVal(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
                return expr, scope, lib, fn


class LListComa(Base):
        def validate(self, expr):
                return re.match(r',', expr)

        def next(self):
                return ['listval']

        def end(self):
                return False

        def val(self, expr, scope, lib, fn=[]):
                assert isinstance(expr, str)
                assert isinstance(scope, dict)
                assert isinstance(lib, dict)
                logger.debug('LListComa(%s, %s, %s, %s)' % (expr, scope, lib, fn))
                exprMatch = self.validate(expr)
                expr = expr.replace(exprMatch.group(0), '', 1)
                logger.debug('LListComa(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
                return expr, scope, lib, fn


class LListEnd(Base):
        def validate(self, expr):
                return re.match(r'\]', expr)

        def next(self):
                return ['lambdacall']

        def end(self):
                return True

        def val(self, expr, scope, lib, fn=[]):
                assert isinstance(expr, str)
                assert isinstance(scope, dict)
                assert isinstance(lib, dict)
                logger.debug('LListEnd(%s, %s, %s, %s)' % (expr, scope, lib, fn))
                exprMatch = self.validate(expr)
                expr = expr.replace(exprMatch.group(0), '', 1)
                logger.debug('LListEnd(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
                return expr, scope, lib, fn

def _makeLLambda(expr, scope, lib):
        #(lambda)
        if isinstance(expr,str):
                lambdaExpr = expr
                exprMatch = re.match(r'^\(', expr.strip())
                expr = expr.replace(exprMatch.group(0), '', 1).strip()
                expr, fnlst = pparse(fsm, expr, scope, lib)
                expr = expr.replace(re.match(r'^\)', expr.strip()).group(0), '', 1).strip()
                lambdaExpr = lambdaExpr.replace(expr, '',1)
                return expr,fnlst
        #['(lambda1)','(lambda2)'] => lambda2(lambda1(..))
        elif isinstance(expr,list):
                fnlst = []
                for subexpr in expr:
                        if not isinstance(subexpr,str):
                                raise Exception('monad error')
                        rest,_fnlst = _makeLLambda(subexpr,scope,lib)
                        fnlst += _fnlst
                return '',fnlst



class LLambda(Base):
	def validate(self, expr):
		return re.match(r'\(', expr)

	def next(self):
		return ['lambdacall']

	def end(self):
		return True

	def val(self, expr, scope, lib, fn=[]):
		assert isinstance(expr, str)
		assert isinstance(scope, dict)
		assert isinstance(lib, dict)
		logger.debug('LLambda(%s, %s, %s, %s)' % (expr, scope, lib, fn))
		rest, _fnlst = _makeLLambda(expr, scope, lib)
		expr = expr.replace(rest,'',1)
		fn.append(lambda param : expr )
		logger.debug('LLambda(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
		return rest, expr, lib, fn


class LLambdaCall(Base):
	def validate(self, expr):
		return re.match(r'^\(', expr)

	def next(self):
		return []

	def end(self):
		return True

	def val(self, expr, scope, lib, fn=[]):
		assert isinstance(expr, str)
		assert isinstance(scope, dict)
		assert isinstance(lib, dict)
		exprMatch = self.validate(expr)
		expr = expr.replace(exprMatch.group(0), '', 1)
		expr, fns = pparse(fsm, expr, scope, lib)
		exprEndMatch = re.match(r"^\)", expr)
		expr = expr.replace(exprEndMatch.group(0), '', 1)
		def closure(_lambdaExpr):
			param = scope
			for _fn in fns:
				param = _fn(param)
                        rest, _fnlst = _makeLLambda(_lambdaExpr, param, lib)
			ret = param
			for _fn in _fnlst:
				ret = _fn(param)
			return ret
		fn.append(closure)
		return expr, scope, lib, fn


class NameSpace(Base):
	def validate(self, expr):
		return re.match(r"^([A-Z][a-zA-Z0-9_]*)::", expr)

	def next(self):
		return ['function']

	def end(self):
		return False

	def val(self, expr, scope, lib, fn=[]):
		assert isinstance(expr, str)
		assert isinstance(scope, dict)
		assert isinstance(lib, dict)
		logger.debug('NameSpace(%s, %s, %s, %s)' % (expr, scope, lib, fn))
		exprMatch = self.validate(expr)
		ns = exprMatch.group(1)
		if ns not in lib:
			raise Exception("undefined namespace %s in scope %s" % (ns, lib.keys()))
		lib = lib[ns]
		expr = expr.replace(exprMatch.group(0), '', 1)
		logger.debug('NameSpace(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
		return expr, scope, lib, fn


class Function(Base):
	def validate(self, expr):
		return re.match(r"^([A-Z][a-zA-Z0-9_]*)\(", expr)

	def next(self):
		return []

	def end(self):
		return True

	def val(self, expr, scope, lib, fn=[]):
		assert isinstance(expr, str)
		#assert isinstance(scope, dict)
		assert isinstance(lib, dict)
		logger.debug('Function(%s, %s, %s, %s)' % (expr, scope, lib, fn))
		exprMatch = self.validate(expr)
		fnname = exprMatch.group(1)
		if fnname not in lib:
			raise Exception('undefined function %s in scope %s' % (fnname, lib.keys()))
		expr = expr.replace(exprMatch.group(0), '', 1)
		expr, fns = pparse(fsm, expr, scope, lib)
		exprEndMatch = re.match(r"^\)", expr)
		expr = expr.replace(exprEndMatch.group(0), '', 1)
		# closure
		def closure(_db):
			_fn = lib[fnname]
			param = scope
			for fn in fns:
				param = fn(param)
			ret = _fn(param)
			return ret
		#fn.append(closure)
		fn.append(lambda _dontcare : scope)
		fn += fns
		fn.append(lib[fnname])
		logger.debug('Function(...) -> (%s, %s, %s, %s)' % (expr, scope, lib, fn))
		return expr, scope, lib, fn


fsm = {
	'begin': Begin(['scope',
			'namespace',
			'function',
			'bool',
			'string',
			'number',
			'name',
			'dictbegin',
			'listbegin',
			'lambda']),
	'scope' : Scope(),
	'name': Name(),
	'dot': Dot(),			#name.subname
	'index': Index(),		#name[index]
	'key' : Key(),			#name{key}
	'string': String(),		#'string'
	'number': Number(),		#42
	'bool': Bool(),			#True False
	'dictbegin': DictBegin(),	#{
	'dictval': DictVal(),		#name => value
	'dictcoma': DictComa(),		#,
	'dictend': DictEnd(),		#}
	'listbegin': LList(),		#[
	'listval': LListVal(),		#value
	'listcoma': LListComa(),	#,
	'listend': LListEnd(),		#]
	'namespace': NameSpace(),	#UpperCaseStartingName::
	'function': Function(),		#UpperCaseStartingName(value)
	'lambda': LLambda(),		#(expression)
	'lambdacall': LLambdaCall()	#lowercasestartingname(value)
}

fsmbind = {
	'begin': Begin(['bind']),
	'bind': Bind()
}


class test(unittest.TestCase):
	def setUp(self):
		# from http://www.json-generator.com/
		self.db = {
			"_id": "56004f237312c964d528fc54",
			"index": 0,
			"guid": "8d780a2d-ac24-4be3-8ef6-eca6cbbee423",
			"isActive": True,
			"balance": "$1,510.18",
			"picture": "http://placehold.it/32x32",
			"age": 28,
			"eyeColor": "blue",
			"name": "Bridgett Beach",
			"gender": "female",
			"company": "MANTRIX",
			"email": "bridgettbeach@mantrix.com",
			"phone": "+1 (936) 470-2164",
			"address": "141 Russell Street, Yettem, Marshall Islands, 3033",
			"about": "Veniam ipsum eu veniam ipsum ullamco. Occaecat incididunt pariatur ex pariatur est qui officia sint laborum minim nulla occaecat consequat reprehenderit. Anim irure pariatur ipsum amet eiusmod et nisi. In adipisicing sit pariatur elit ut consectetur qui. Incididunt officia et sit tempor fugiat pariatur fugiat non adipisicing ad ex irure culpa.\r\n",
			"registered": "2015-03-06T01:58:40 +05:00",
			"latitude": -50.749588,
			"longitude": 34.268301,
			"tags": ["do", "aliquip", "cillum", "ullamco", "fugiat", "eu", "amet"],
			"friends": [
				{"id": 0, "name": "Deborah Randall"},
				{"id": 1, "name": "English Steele"},
				{"id": 2, "name": "Mckinney Norman"}
			],
			"greeting": "Hello, Bridgett Beach! You have 8 unread messages.",
			"favoriteFruit": "strawberry",
			"answerno": "('no')",
			"cat": "($)",
			"asstr": "(Str($))",
			"fourtytwo" : ["(42)"]
		}
		self.scope = {
			'Str': lambda param: str(param),
			'Test': lambda param: param,
			'Ns': {
				'Hello': lambda who: 'hello ' + str(who)
			}
		}

	def test_raise(self):
		self.raiselst = [
		(".name","cant start with a dot"),
		(".[0]","cant start with a dot"),
		("name..name","two dot in a row"),
		("name.",""),
		("name name",""),
		("name.[0]",""),
		("name[name]",""),
		("name[0",""),
		("123asd",""),
		("'unfinished string",""),
		("True.False","")
		]
		for expr,msg in self.raiselst:
			self.assertRaises(Exception, parse, fsm, expr, self.db, self.scope)

	def test_equal(self):
		self.equalLst = [
		("['a',1,True,['b',2,False]]", ['a', 1, True, ['b', 2, False]], "list ception"),
		("friends[index].name", self.db['friends'][self.db['index']]['name'],"inderef"),
		("True", True,"boolean true"),
		("False", False,"boolean false"),
		("'a string deh'", "a string deh","string literal"),
		("'256'", "256","number in a string literal"),
		("256", 256,"number literal"),
		("index", self.db['index'],"reference to a number"),
		("guid", self.db['guid'],"reference to a string"),
		("isActive", self.db['isActive'],"reference to a bool"),
		("tags", self.db['tags'],"reference to a list"),
		("tags[3]", self.db['tags'][3],"index in a list"),
		("friends[0]", self.db['friends'][0],"index in a reference to a list"),
		("friends[1].name", self.db['friends'][1]['name'],"item in dict in list in dict")
		]
		for expr,result,msg in self.equalLst:
			self.assertEqual(result, parse(fsm, expr, self.db, self.scope),msg)

	def test_dict(self):
		expr, result = ("{a=>'a',b=>12,c=>True,d=>index}", {'a': 'a', 'b': 12, 'c': True, 'd': self.db['index']})
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_dict_string(self):
		expr, result = ("{a=>'a'}", {'a': 'a'})
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_dict_num(self):
		expr, result = ("{a=>12}", {'a': 12})
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_dict_bool(self):
		expr, result = ("{a=>True}", {'a': True})
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_dict_name(self):
		expr, result = ("{a=>index}", {'a': self.db['index']})
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_dict_name_index_name(self):
		expr, result = ("{a=>friends[0].name}", {'a': self.db['friends'][0]['name']})
		# self.assertRaises(Exception, parse, fsm, expr, self.db, self.scope)
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_dict_ception(self):
		expr = "{a=>'a',b=>True,c=>3,d=>['word',{a=>2}],e=>{a=>1}}"
		result = {'a': 'a', 'b': True, 'c': 3, 'd': ['word', {'a': 2}], 'e': {'a': 1}}
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_dict_invalid(self):
		expr = "{"
		self.assertRaises(Exception, parse, fsm, expr, self.db, self.scope)

	def test_dict_invalid2(self):
		expr = "}"
		self.assertRaises(Exception, parse, fsm, expr, self.db, self.scope)

	def test_dict_invalid3(self):
		expr = "=>"
		self.assertRaises(Exception, parse, fsm, expr, self.db, self.scope)

	def test_dict_invalid4(self):
		expr = "{asdfaf"
		self.assertRaises(Exception, parse, fsm, expr, self.db, self.scope)

	def test_dict_invalid5(self):
		expr = "azdaf}"
		self.assertRaises(Exception, parse, fsm, expr, self.db, self.scope)

	def test_dict_invalid8(self):
		expr = "{aasd=>Sdf"
		self.assertRaises(Exception, parse, fsm, expr, self.db, self.scope)

	def test_dict_invalid9(self):
		expr = "{12=>id}"
		self.assertRaises(Exception, parse, fsm, expr, self.db, self.scope)

	def test_dict_invalidA(self):
		expr = "{a=>id,a=>2}"
		self.assertRaises(Exception, parse, fsm, expr, self.db, self.scope)

	def test_list(self):
		expr, result = ("[index,0,'a',True]", [self.db['index'], 0, "a", True])
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_list_name(self):
		expr, result = ("[friends]", [self.db['friends']])
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_list_name_restriction(self):
		expr, result = ("[friends[0].name]", [self.db['friends'][0]['name']])
		# self.assertRaises(Exception, parse, fsm, expr, self.db, self.scope)
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_list_invalid(self):
		expr = "["
		self.assertRaises(Exception, parse, fsm, expr, self.db, self.scope)

	def test_function_bool(self):
		expr, result = ("Test(False)", False)
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_function_string(self):
		expr, result = ("Test('world')", "world")
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_function_name(self):
		expr, result = ("Test(index)", 0)
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_function_number(self):
		expr, result = ("Test(12)", 12)
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_function_namespace(self):
		expr, result = ("Ns::Hello('world')", "hello world")
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_function_undefinied(self):
		expr = "Hello('')"
		self.assertRaises(Exception, parse, fsm, expr, self.db, self.scope)

	def test_function_invalid(self):
		expr = "Hello()"
		self.assertRaises(Exception, parse, fsm, expr, self.db, self.scope)

	def test_function_invalid2(self):
		expr = "Hello("
		self.assertRaises(Exception, parse, fsm, expr, self.db, self.scope)

	def test_function_return_bool(self):
		expr = "Test(True)"
		result = parse(fsm, expr, self.db, self.scope)
		self.assertTrue(isinstance(result, bool))

	def test_lambda_declaration(self):
		expr, result = ("('word')", "('word')")
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_lambda_call(self):
		expr, result = ("answerno('')", "no")
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

	def test_lambda_undeclared_call(self):
		expr, result = ("asstr(52)","52")
		self.assertEqual(result,parse(fsm,expr,self.db,self.scope))

        def test_lambda_list(self):
                expr, result = ("[($),(2)]", ['($)','(2)'])
                self.assertEqual(result,parse(fsm,expr,self.db,self.scope))

        def test_lambda_list_call(self):
                expr, result = ("fourtytwo(52)", 42)
                self.assertEqual(result,parse(fsm,expr,self.db,self.scope))

	def test_lambda_call_with_param(self):
		expr, result = ("cat('this')", "this")
		self.assertEqual(result, parse(fsm, expr, self.db, self.scope))

        def test_scope(self):
                expr, result = ("$", self.db)
                self.assertEqual(result,parse(fsm,expr,self.db,self.scope))

	def test_lambda_declaration_invalid(self):
		expr = "()("
		self.assertRaises(Exception, parse, fsm, expr, self.db, self.scope)

	def test_ascii_art(self):
		expr = """
{
  id => 'paramecia',
  tail => [
		'word',
		'word',
		'word'
		]
}
"""
		expect = {
			'id': 'paramecia',
			'tail': [
				'word',
				'word',
				'word'
			]
		}
		result = parse(fsm, expr, self.db, self.scope)
		self.assertEqual(expect, result)


if __name__ == '__main__':
	# logging.basicConfig(filename=__name__+'.log', filemode='w',level=logging.DEBUG)
	import sys
	#root = logging.getLogger()
	#root.setLevel(logging.DEBUG)
	#ch = logging.StreamHandler(sys.stdout)
	#ch.setLevel(logging.DEBUG)
	#formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
	#ch.setFormatter(formatter)
	#root.addHandler(ch)
	unittest.main()
