from TextTools import TextTools
import pprint, string
from simpleparse import bootstrap, generator

class DefnTester:
	def __init__(self, processingfunc, defntype, aset=None, bset=None, rset=None ):
		self.processingfunc = processingfunc
		self.defntype = defntype
		if len( aset ) == len(bset) == len(rset):
			self.aset = aset or []
			self.bset = bset or []
			self.rset = rset or []
		else:
			print "incorrect lengths", len(aset), len(bset), len(rset)
			raise blah
	def test( self, defn, target, verbose=None):
		print '''Passed defn''', `defn`
		s = generator._BaseGenerator( defn, self.defntype )
		#try:
		ptree = bootstrap.parse( defn, self.defntype )
		#except TypeError:
		#	print `defn`
		#	raise TypeError
		if verbose:
			print '''Defn Parse Tree'''
			pprint.pprint( ptree )
		prstree = self.processingfunc( s.parsetree, s)
		if verbose:
			print '''  New Parser Tree'''
			pprint.pprint( prstree )
			print '''  Result Parsed Tree'''
		res = TextTools.tag( target, tuple( prstree ) )
		if verbose:
			pprint.pprint( res )
		return res
	def autotest( self, verbose = None ):
		rsults = map( self.test, self.aset, self.bset, [verbose]*len(self.aset))
		rsults = map( None, range(len(rsults)), rsults, self.rset )
		print '''Starting %s Tests'''%self.defntype
		for num, a,b in rsults:
			if a != b:
				print '''  %s test %s failed: %s -> %s'''%(self.defntype, num, a, b)
			else:
				print '''  %s test %s succeeded'''%(self.defntype,num)
				
dset1 = '''\ntest  := 'mabel'/greg\ngreg  := 'greg'\n'''

def testparts( ):
	DefnTester( generator.rangeval, 
	     'range', 
	     [ '[0-9]', '[]-2-3]', '[]-2-3]' ],
	     [ '023', ']023', '023' ],
	     [ (1,[],1), (1,[],1), (0,[],0) ]
	).autotest()
	DefnTester( generator.literal,
	     'literal',
	     [ '"this"', '"this\\042"' ],
	     [ 'this', 'this"' ],
	     [ (1, [], 4), (1, [], 5) ],
	).autotest(  )
	# test literal and range-based element_tokens
	DefnTester( generator.element_token,
	     'element_token',
	     [ '"this"', '"this\\042"', '-"this"' ,'-"this"*', '[0-9]*', '-[0-9]*', '[0-9]*' ],
	     [ 'this', 'this"', 'ssthis', 'ssthis', '012345', 'test023', 'test23' ],
	     [ (1, [], 4), (1, [], 5), (1, [], 1), (1, [], 2), (1, [], 6), (1, [], 4), (1, [], 0) ],
	).autotest(  )
	# now test sequential group based element_tokens
	DefnTester( generator.element_token,
	     'element_token',
	     [ '("this","that")?', '("this","that")', '-("this","that")*', '-("this","that")+', '-("this","that")+', '-("this","that")?', '-("this","that")', '-("this","that")?', '-("this","that")', '("this","that")*', '("this","that")+', '("this","that")+', ],
	     [ 'thisthatthisthat', 'thisthat', 'sobthisthat', 'sobthisthat', 'thisthat', 'sthisthat', 'sthisthat', 'thisthatthisthat', 'thisthatthisthat', 'thisthatthisthatare','thisthatthisthatare', 'sthisthatthisthatare' ],
	     [ (1, [], 8), (1, [], 8), (1, [], 3),(1, [], 3), (0,[],0), (1,[],1), (1,[],1), (1, [], 0), (0, [], 0) , (1, [], 16), (1, [], 16), (0,[],0)],
	).autotest( )
	# now test fo group based element_tokens
	DefnTester( generator.element_token,
	     'element_token',
	     [ '("this"/"that")?', '("this"/"that")', '-("this"/"that")*' , '-("this"/"that")+', '-("this"/"that")+', '-("this"/"that")?', '-("this"/"that")', '-("this"/"that")?', '-("this"/"that")', '("this"/"that")*', '("this"/"that")+', '("this"/"that")+', ],
	     [ 'thisthatthisthat', 'thisthat', 'sobthisthat' , 'sobthisthat', 'thisthat', 'sthisthat', 'sthisthat', 'thisthatthisthat', 'thisthatthisthatas', 'thisthatthisthatare','thisthatthisthatare', 'sthisthatthisthatare' ],
	     [ (1, [], 4), (1, [], 4), (1,[],3), (1,[],3), (0,[],0), (1,[],1), (1,[],1), (1,[],0), (0,[],0), (1,[],16), (1,[],16), (0,[],0)],
	).autotest( verbose = 1 )
dsets = [
('''\ndeclarationset  := (mabel/greg)+\ngreg  := 'greg'\nmabel := 'mabel' ''', 'mabelgregmabel this', (1, [('mabel', 0, 5, []), ('greg', 5, 9, []), ('mabel', 9, 14, [])], 14)),
('''
declarationset  := OCTALESCAPEDCHAR
OCTALESCAPEDCHAR    :=  [0-7],[0-7]?,[0-7]?
''', 
'000',  ((1, [('OCTALESCAPEDCHAR', 0, 3, [])], 3)) ),
('''
declarationset  := CHARNODBLQUOTE
OCTALESCAPEDCHAR    :=  [0-7],[0-7]?,[0-7]?
CHARNODBLQUOTE      :=  -[\134"]+
CHARNOSNGLQUOTE     :=  -[\134']+
''', 
's',  (1, [], 1)),
( generator.bootstrap.declaration, generator.bootstrap.declaration, None ),
]
def testdecls():
	'''
	Test the parsing of declarations
	'''
	print '''Testdecls '''
	for dset, instr, wanted in dsets:
		g = generator._BaseGenerator( dset )
		g.build()
		res = TextTools.tag( instr, g.parserbyname( 'declarationset' ))
		if ( res == wanted):
			print '''success'''
		else:
			print '''fail: '''
			pprint.pprint( (res, wanted) )
def testsecondgen( ):
	'''
	Create a second-generation parser, test against original
	'''
	import bootstrap
	def pbyname(  name, parsernamelist=bootstrap.parsernamelist, parsertuplelist=bootstrap.parsertuplelist ):
		return parsertuplelist[ parsernamelist.index( name ) ]
	proc = generator._BaseGenerator( )
	proc.build()
	return _testgenerations( pbyname, proc.parserbyname )
	
def _testgenerations( sourcea, sourceb ):
	'''
	print the output of two parser sets one after the other
	the results should be functionally identical in most cases.
	'''
	# proc is the second-generation parser we are testing
	pprint.pprint( TextTools.tag( '" "', sourcea( 'literal' ) ) )
	pprint.pprint( TextTools.tag( '" "', sourceb( 'literal' ) ) )
	print 1
	pprint.pprint( TextTools.tag( '[\\0000-9]', sourcea( 'range' ) ) )
	pprint.pprint( TextTools.tag( '[\\0000-9]', sourceb( 'range' ) ) )
	print  2
	pprint.pprint( TextTools.tag( '  \t', sourcea( '<ts>' ) ) )
	pprint.pprint( TextTools.tag( '  \t', sourceb( '<ts>' ) ) )
	print 3
	pprint.pprint( TextTools.tag( 'this', sourcea( 'name' ) ) )
	pprint.pprint( TextTools.tag( 'this', sourceb( 'name' ) ) )
	
	print 4
	pprint.pprint( TextTools.tag( '<this>', sourcea( 'unreportedname' ) ) )
	pprint.pprint( TextTools.tag( '<this>', sourceb( 'unreportedname' ) ) )
	print 5
	pprint.pprint( TextTools.tag( '??', sourcea( 'occurence_indicator' ) ) )
	pprint.pprint( TextTools.tag( '??', sourceb( 'occurence_indicator' ) ) )
	print 6
	pprint.pprint( TextTools.tag( '-', sourcea( 'negpos_indicator' ) ) )
	pprint.pprint( TextTools.tag( '-', sourceb( 'negpos_indicator' ) ) )
	print 7
	pprint.pprint( TextTools.tag( '(this)', sourcea( 'group' ) ) )
	pprint.pprint( TextTools.tag( '(this)', sourceb( 'group' ) ) )
	print 8 
	pprint.pprint( TextTools.tag( '(-this+)*', sourcea( 'group' ) ) )
	pprint.pprint( TextTools.tag( '(-this+)*', sourceb( 'group' ) ) )
	print 9
	pprint.pprint( TextTools.tag( '(-this+)*', sourcea( 'element_token' ) ) )
	pprint.pprint( TextTools.tag( '(-this+)*', sourceb( 'element_token' ) ) )
	print 10
	pprint.pprint( TextTools.tag( '-( -this+, -that?)*', sourcea( 'element_token' ) ) )
	pprint.pprint( TextTools.tag( '-( -this+, -that?)*', sourceb( 'element_token' ) ) )
	print 11
	pprint.pprint( TextTools.tag( 's := test, this t:= why/not', sourcea( 'declarationset' ) ) )
	pprint.pprint( TextTools.tag( 's := test, this t:= why/not', sourceb( 'declarationset' ) ) )

	return sourcea, sourceb
	
def testmeta( x=5 ):
	'''
	Test the meta-generator by creating multiple
	generations of generated generators.
	x is the number of derived generations to create
	'''
	x = x-1
	gen1 = generator._BaseGenerator( )
	gen1.build()
	prevgen = gen1
	newgen = gen1
	for gen in range( x):
		newgen = generator.Generator( bootstrap.declaration, prevgen.parserbyname( 'declarationset' ) )
		newgen.build()
	if newgen is not gen1:
		val = _testgenerations( gen1.parserbyname, newgen.parserbyname )
		print '''Tested %s generations'''%( 1+x)
	else:
		print '''No generations tested'''
	
if __name__ == '__main__':
	testmeta( )
