Path: blob/main/third_party/ply/test/testyacc.py
6162 views
# testyacc.py12import unittest3try:4import StringIO5except ImportError:6import io as StringIO78import sys9import os10import warnings1112sys.path.insert(0,"..")13sys.tracebacklimit = 01415import ply.yacc16import imp1718def make_pymodule_path(filename):19path = os.path.dirname(filename)20file = os.path.basename(filename)21mod, ext = os.path.splitext(file)2223if sys.hexversion >= 0x3020000:24modname = mod+"."+imp.get_tag()+ext25fullpath = os.path.join(path,'__pycache__',modname)26else:27fullpath = filename28return fullpath2930def pymodule_out_exists(filename):31return os.path.exists(make_pymodule_path(filename))3233def pymodule_out_remove(filename):34os.remove(make_pymodule_path(filename))353637def check_expected(result,expected):38resultlines = []39for line in result.splitlines():40if line.startswith("WARNING: "):41line = line[9:]42elif line.startswith("ERROR: "):43line = line[7:]44resultlines.append(line)4546expectedlines = expected.splitlines()47if len(resultlines) != len(expectedlines):48return False49for rline,eline in zip(resultlines,expectedlines):50if not rline.endswith(eline):51return False52return True5354def run_import(module):55code = "import "+module56exec(code)57del sys.modules[module]5859# Tests related to errors and warnings when building parsers60class YaccErrorWarningTests(unittest.TestCase):61def setUp(self):62sys.stderr = StringIO.StringIO()63sys.stdout = StringIO.StringIO()64try:65os.remove("parsetab.py")66pymodule_out_remove("parsetab.pyc")67except OSError:68pass6970if sys.hexversion >= 0x3020000:71warnings.filterwarnings('ignore',category=ResourceWarning)7273def tearDown(self):74sys.stderr = sys.__stderr__75sys.stdout = sys.__stdout__76def test_yacc_badargs(self):77self.assertRaises(ply.yacc.YaccError,run_import,"yacc_badargs")78result = sys.stderr.getvalue()79self.assert_(check_expected(result,80"yacc_badargs.py:23: Rule 'p_statement_assign' has too many arguments\n"81"yacc_badargs.py:27: Rule 'p_statement_expr' requires an argument\n"82))83def test_yacc_badid(self):84self.assertRaises(ply.yacc.YaccError,run_import,"yacc_badid")85result = sys.stderr.getvalue()86self.assert_(check_expected(result,87"yacc_badid.py:32: Illegal name 'bad&rule' in rule 'statement'\n"88"yacc_badid.py:36: Illegal rule name 'bad&rule'\n"89))9091def test_yacc_badprec(self):92try:93run_import("yacc_badprec")94except ply.yacc.YaccError:95result = sys.stderr.getvalue()96self.assert_(check_expected(result,97"precedence must be a list or tuple\n"98))99def test_yacc_badprec2(self):100self.assertRaises(ply.yacc.YaccError,run_import,"yacc_badprec2")101result = sys.stderr.getvalue()102self.assert_(check_expected(result,103"Bad precedence table\n"104))105106def test_yacc_badprec3(self):107run_import("yacc_badprec3")108result = sys.stderr.getvalue()109self.assert_(check_expected(result,110"Precedence already specified for terminal 'MINUS'\n"111"Generating LALR tables\n"112113))114115def test_yacc_badrule(self):116self.assertRaises(ply.yacc.YaccError,run_import,"yacc_badrule")117result = sys.stderr.getvalue()118self.assert_(check_expected(result,119"yacc_badrule.py:24: Syntax error. Expected ':'\n"120"yacc_badrule.py:28: Syntax error in rule 'statement'\n"121"yacc_badrule.py:33: Syntax error. Expected ':'\n"122"yacc_badrule.py:42: Syntax error. Expected ':'\n"123))124125def test_yacc_badtok(self):126try:127run_import("yacc_badtok")128except ply.yacc.YaccError:129result = sys.stderr.getvalue()130self.assert_(check_expected(result,131"tokens must be a list or tuple\n"))132133def test_yacc_dup(self):134run_import("yacc_dup")135result = sys.stderr.getvalue()136self.assert_(check_expected(result,137"yacc_dup.py:27: Function p_statement redefined. Previously defined on line 23\n"138"Token 'EQUALS' defined, but not used\n"139"There is 1 unused token\n"140"Generating LALR tables\n"141142))143def test_yacc_error1(self):144try:145run_import("yacc_error1")146except ply.yacc.YaccError:147result = sys.stderr.getvalue()148self.assert_(check_expected(result,149"yacc_error1.py:61: p_error() requires 1 argument\n"))150151def test_yacc_error2(self):152try:153run_import("yacc_error2")154except ply.yacc.YaccError:155result = sys.stderr.getvalue()156self.assert_(check_expected(result,157"yacc_error2.py:61: p_error() requires 1 argument\n"))158159def test_yacc_error3(self):160try:161run_import("yacc_error3")162except ply.yacc.YaccError:163e = sys.exc_info()[1]164result = sys.stderr.getvalue()165self.assert_(check_expected(result,166"'p_error' defined, but is not a function or method\n"))167168def test_yacc_error4(self):169self.assertRaises(ply.yacc.YaccError,run_import,"yacc_error4")170result = sys.stderr.getvalue()171self.assert_(check_expected(result,172"yacc_error4.py:62: Illegal rule name 'error'. Already defined as a token\n"173))174175def test_yacc_inf(self):176self.assertRaises(ply.yacc.YaccError,run_import,"yacc_inf")177result = sys.stderr.getvalue()178self.assert_(check_expected(result,179"Token 'NUMBER' defined, but not used\n"180"There is 1 unused token\n"181"Infinite recursion detected for symbol 'statement'\n"182"Infinite recursion detected for symbol 'expression'\n"183))184def test_yacc_literal(self):185self.assertRaises(ply.yacc.YaccError,run_import,"yacc_literal")186result = sys.stderr.getvalue()187self.assert_(check_expected(result,188"yacc_literal.py:36: Literal token '**' in rule 'expression' may only be a single character\n"189))190def test_yacc_misplaced(self):191self.assertRaises(ply.yacc.YaccError,run_import,"yacc_misplaced")192result = sys.stderr.getvalue()193self.assert_(check_expected(result,194"yacc_misplaced.py:32: Misplaced '|'\n"195))196197def test_yacc_missing1(self):198self.assertRaises(ply.yacc.YaccError,run_import,"yacc_missing1")199result = sys.stderr.getvalue()200self.assert_(check_expected(result,201"yacc_missing1.py:24: Symbol 'location' used, but not defined as a token or a rule\n"202))203204def test_yacc_nested(self):205run_import("yacc_nested")206result = sys.stdout.getvalue()207self.assert_(check_expected(result,208"A\n"209"A\n"210"A\n",211))212213def test_yacc_nodoc(self):214run_import("yacc_nodoc")215result = sys.stderr.getvalue()216self.assert_(check_expected(result,217"yacc_nodoc.py:27: No documentation string specified in function 'p_statement_expr' (ignored)\n"218"Generating LALR tables\n"219))220221def test_yacc_noerror(self):222run_import("yacc_noerror")223result = sys.stderr.getvalue()224self.assert_(check_expected(result,225"no p_error() function is defined\n"226"Generating LALR tables\n"227))228229def test_yacc_nop(self):230run_import("yacc_nop")231result = sys.stderr.getvalue()232self.assert_(check_expected(result,233"yacc_nop.py:27: Possible grammar rule 'statement_expr' defined without p_ prefix\n"234"Generating LALR tables\n"235))236237def test_yacc_notfunc(self):238run_import("yacc_notfunc")239result = sys.stderr.getvalue()240self.assert_(check_expected(result,241"'p_statement_assign' not defined as a function\n"242"Token 'EQUALS' defined, but not used\n"243"There is 1 unused token\n"244"Generating LALR tables\n"245))246def test_yacc_notok(self):247try:248run_import("yacc_notok")249except ply.yacc.YaccError:250result = sys.stderr.getvalue()251self.assert_(check_expected(result,252"No token list is defined\n"))253254def test_yacc_rr(self):255run_import("yacc_rr")256result = sys.stderr.getvalue()257self.assert_(check_expected(result,258"Generating LALR tables\n"259"1 reduce/reduce conflict\n"260"reduce/reduce conflict in state 15 resolved using rule (statement -> NAME EQUALS NUMBER)\n"261"rejected rule (expression -> NUMBER) in state 15\n"262263))264265def test_yacc_rr_unused(self):266run_import("yacc_rr_unused")267result = sys.stderr.getvalue()268self.assert_(check_expected(result,269"no p_error() function is defined\n"270"Generating LALR tables\n"271"3 reduce/reduce conflicts\n"272"reduce/reduce conflict in state 1 resolved using rule (rule3 -> A)\n"273"rejected rule (rule4 -> A) in state 1\n"274"reduce/reduce conflict in state 1 resolved using rule (rule3 -> A)\n"275"rejected rule (rule5 -> A) in state 1\n"276"reduce/reduce conflict in state 1 resolved using rule (rule4 -> A)\n"277"rejected rule (rule5 -> A) in state 1\n"278"Rule (rule5 -> A) is never reduced\n"279))280281def test_yacc_simple(self):282run_import("yacc_simple")283result = sys.stderr.getvalue()284self.assert_(check_expected(result,285"Generating LALR tables\n"286))287def test_yacc_sr(self):288run_import("yacc_sr")289result = sys.stderr.getvalue()290self.assert_(check_expected(result,291"Generating LALR tables\n"292"20 shift/reduce conflicts\n"293))294295def test_yacc_term1(self):296self.assertRaises(ply.yacc.YaccError,run_import,"yacc_term1")297result = sys.stderr.getvalue()298self.assert_(check_expected(result,299"yacc_term1.py:24: Illegal rule name 'NUMBER'. Already defined as a token\n"300))301302def test_yacc_unused(self):303self.assertRaises(ply.yacc.YaccError,run_import,"yacc_unused")304result = sys.stderr.getvalue()305self.assert_(check_expected(result,306"yacc_unused.py:62: Symbol 'COMMA' used, but not defined as a token or a rule\n"307"Symbol 'COMMA' is unreachable\n"308"Symbol 'exprlist' is unreachable\n"309))310def test_yacc_unused_rule(self):311run_import("yacc_unused_rule")312result = sys.stderr.getvalue()313self.assert_(check_expected(result,314"yacc_unused_rule.py:62: Rule 'integer' defined, but not used\n"315"There is 1 unused rule\n"316"Symbol 'integer' is unreachable\n"317"Generating LALR tables\n"318))319320def test_yacc_uprec(self):321self.assertRaises(ply.yacc.YaccError,run_import,"yacc_uprec")322result = sys.stderr.getvalue()323self.assert_(check_expected(result,324"yacc_uprec.py:37: Nothing known about the precedence of 'UMINUS'\n"325))326327def test_yacc_uprec2(self):328self.assertRaises(ply.yacc.YaccError,run_import,"yacc_uprec2")329result = sys.stderr.getvalue()330self.assert_(check_expected(result,331"yacc_uprec2.py:37: Syntax error. Nothing follows %prec\n"332))333334def test_yacc_prec1(self):335self.assertRaises(ply.yacc.YaccError,run_import,"yacc_prec1")336result = sys.stderr.getvalue()337self.assert_(check_expected(result,338"Precedence rule 'left' defined for unknown symbol '+'\n"339"Precedence rule 'left' defined for unknown symbol '*'\n"340"Precedence rule 'left' defined for unknown symbol '-'\n"341"Precedence rule 'left' defined for unknown symbol '/'\n"342))343344345346unittest.main()347348349