import unittest import minimalpcp as mp # Unittest for minimalpcp.py (minimal demo precedence climbing parser) # See minimalpcp.py and minimalpcp.pdf. # ==================================================================== # Licence (2-clause BSD License) (see minimalpcp). # Copyright 2017 JoeCreu # The items in test 2 ('test_02_minimalpcp_aasa_1992') are from Annika # Aasa, 'User Defined Syntax', Göteborg (1992), pp. 69 to 79. # The order of precedences (binding powers) has been inverted (Aasa # uses smaller numbers for higher precedences). Here, greater binding # power numbers always mean higher precedence. # 'test_03_minimalpcp_predef_data' uses the test data contained in # minimalpcp.py # Python versions 3.* and 2.7.* should work. # JoeCreu, 2017-04-23 # Usage: # python3 minimalpcp_test.py -v # The test items are of the form # self.assertEqual(mp.parse([string_to_be_parsed], # [syntax]), # [parse_result]) # [syntax] is a Python dictionary of "operator:binding powers"-pairs; # where "binding-powers" is itself a tuple (left binding power, right # binding power). [parse_result] is a string containing the parse tree # in the form of a lisp-like nested list structure. class testminimalpcp(unittest.TestCase) : def test_01_minimalpcp_literal(self): self.assertEqual(mp.parse("a + b",{"+":(6,7)}),"(+ a b)") self.assertEqual(mp.parse("a + 3 * b",{"+":(6,7),"*":(8,9)}), "(+ a (* 3 b))") self.assertEqual(mp.parse("a + not b !", {"+":(6,7),"not":(100,3),"!":(11,100)}), "(+ a (not $PREDUMMY (! b $POSTDUMMY)))") self.assertEqual(mp.parse("not A and B", {"and":(1,2),"not":(100,3),"!":(11,100)}), "(and (not $PREDUMMY A) B)") self.assertEqual(mp.parse("not A * B", {"*":(5,6),"not":(100,3),"!":(11,100)}), "(not $PREDUMMY (* A B))") self.assertEqual(mp.parse("2 ^ not A * B", {"*":(5,6),"^":(8,7),"not":(100,3)}), "(^ 2 (not $PREDUMMY (* A B)))") self.assertEqual(mp.parse("2 ^ not A and B", {"and":(4,5),"^":(8,7),"not":(100,6)}), "(and (^ 2 (not $PREDUMMY A)) B)") self.assertEqual(mp.parse("2 and not A ^ B", {"and":(4,5),"^":(8,7),"not":(100,6)}), "(and 2 (not $PREDUMMY (^ A B)))") self.assertEqual(mp.parse("a ! * b !", {"*":(6,7),"!":(5,100)}), "(! (* (! a $POSTDUMMY) b) $POSTDUMMY)") self.assertEqual(mp.parse("not A and not not B", {"and":(4,5),"^":(8,7),"not":(100,6)}), "(and (not $PREDUMMY A) " + "(not $PREDUMMY (not $PREDUMMY B)))") def test_02_minimalpcp_aasa_1992(self) : self.assertEqual(mp.parse("2 * 3 ! + 4", {"+":(2,2),"*":(3,3),"!":(5,100)}), "(+ (* 2 (! 3 $POSTDUMMY)) 4)") self.assertEqual(mp.parse("3 + $ 4", {"+":(2,2),"$":(100,1),"#":(100,3)}), "(+ 3 ($ $PREDUMMY 4))") self.assertEqual(mp.parse("$ 2 + 5", {"+":(2,2),"$":(100,1),"#":(100,3)}), "($ $PREDUMMY (+ 2 5))") self.assertEqual(mp.parse("# 6 + 7", {"+":(2,2),"$":(100,1),"#":(100,3)}), "(+ (# $PREDUMMY 6) 7)") self.assertEqual(mp.parse("# $ 2 + 7", {"+":(2,2),"$":(100,1),"#":(100,3)}), "(# $PREDUMMY ($ $PREDUMMY (+ 2 7)))") self.assertEqual(mp.parse("7 ? + 8", {"?":(1,100),"+":(2,2),"!":(3,100),"*":(4,4)}), "(+ (? 7 $POSTDUMMY) 8)") self.assertEqual(mp.parse("3 ? !", {"?":(1,100),"+":(2,2),"!":(3,100),"*":(4,4)}), "(! (? 3 $POSTDUMMY) $POSTDUMMY)") self.assertEqual(mp.parse("9 + 6 ? * 8", {"?":(1,100),"+":(2,2),"!":(3,100),"*":(4,4)}), "(* (? (+ 9 6) $POSTDUMMY) 8)") self.assertEqual(mp.parse("3 * 4 ?", {"?":(1,100),"+":(2,2),"!":(3,100),"*":(4,4)}), "(? (* 3 4) $POSTDUMMY)") self.assertEqual(mp.parse("4 ? * 3", {"?":(1,100),"+":(2,2),"!":(3,100),"*":(4,4)}), "(* (? 4 $POSTDUMMY) 3)") self.assertEqual(mp.parse("5 + 4 ? * 3", {"?":(1,100),"+":(2,2),"!":(3,100),"*":(4,4)}), "(* (? (+ 5 4) $POSTDUMMY) 3)") def test_03_minimalpcp_predef_data(self): self.assertEqual(mp.parse(mp.ts1,mp.iopsA), "(* 12 x)") self.assertEqual(mp.parse(mp.ts2,mp.iopsA), "(* 3 (not $PREDUMMY (! a $POSTDUMMY)))") self.assertEqual(mp.parse(mp.ts3,mp.iopsA), "(= res (- (+ (* 4 3) (^ n 12)) x2))") self.assertEqual(mp.parse(mp.ts4,mp.iopsA), "(= res (- (+ (* (* 4 3) a) (^ n (^ 3 2))) x2))") self.assertEqual(mp.parse(mp.ts5,mp.iopsA), "(:= f (-> x (and A B)))") self.assertEqual(mp.parse(mp.ts6,mp.iopsA), "(:= f (-> x (and (not $PREDUMMY A) (not $PREDUMMY " + "(! B $POSTDUMMY)))))") if __name__ == "__main__" : unittest.main()