def test_production_inset(self): P = Production('a', ['b', 'c']) Q = Production('a', ('b', 'c')) s = set() s.add(P) s.add(Q) self.assertEqual(len(s), 1)
def test_grammar_extrasymbol(self): with self.assertRaisesRegex( ValueError, 'neither terminals or nonterminals.*\(S -> s t,\)'): Grammar({'S'}, {'s'}, (Production('S', ('s', )), Production(('S', ), ('s', 't'))), 'S')
def test_grammar_wrong_cf(self): with self.assertRaisesRegex(ValueError, 'not a nonterminal.*\(T -> s,\)'): Grammar( {'S'}, {'s'}, ( Production('S', ('s', )), Production('T', ('s', )) ), 'S' )
def test_derivation_byprods(self): G = Grammar.from_string(""" S -> A B A -> a B -> b """) d = Derivation(G) p = Production('S', ('A', 'B')), Production('A', ('a', )) self.assertEqual(d.leftmost(p).sentential_form(), ('a', 'B'))
def parse(N, deriv, rest): if rest[0] == '#': return True, 'ε', deriv elif N == "T": s, r = match("t", rest) if s: return True, r, deriv.leftmost( G.P.index(Production(N, ("t", )))) elif N == "E": s, r = parse("Eh", deriv, rest) if s: pass
def new_rules(N): head, tail, tails = N + "h", N + "t", N + "ts" prods = set((Production(N, (head, tails)), Production(N, (head, )), Production(tails, (tail, tails)), Production(tails, (tail, )))) for rhs in G.alternatives(N): if rhs[0] == N: prods.add(Production(tail, rhs[1:])) else: prods.add(Production(head, rhs)) return prods, set([head, tail, tails])
def make_parse_source(G): code_ifs = [] code_defs = [] code_defs.append("#Code generated with global_parser_generator.py") code_defs.append("import sys") code_defs.append("from liblet import Grammar,Production,Derivation") code_defs.append("rest=''\npos=0\nderiv=None") code_defs.append( "def logn(f):\n\tdef scope(*args):\n\t\tprint('Call function :',f.__name__,' with args {}'.format(args))" ) code_defs.append("\t\treturn f(*args)\n\treturn scope") code_defs.append( "\ndef end_match():\n\tglobal rest,pos,deriv\n\tif rest and pos==len(rest):print(deriv)" ) code_defs.append( "\ndef match(t,cont):\n\tglobal rest,pos\n\tif rest and t==rest[pos]:\n\t\tpos+=1\n\t\tcont()" ) for A in G.N: code_ifs.append("def parse_{}(cont):".format(A)) for a, α in enumerate(G.alternatives(A)): d = G.P.index(Production(A, α)) code_defs.append( 'def {}_alt{}(cont):\n\tglobal pos,deriv\n\tp=pos\n\tcopy=deriv\n\tderiv=deriv.leftmost({})' .format(A, a, d)) #definition of nested funcitons labeled "t"^t for t in range(1, len(α)): code_defs.append('{}def {}():'.format('\t' * t, 't' * (len(α) - t))) for t, X in enumerate(reversed(α)): if X in G.T: code_defs.append("{}match('{}', {})".format( '\t' * (len(α) - t), X, 't' * t if t else 'cont')) else: code_defs.append("{}parse_{}({})".format( '\t' * (len(α) - t), X, 't' * t if t else 'cont')) code_defs.append("\tpos=p\n\tderiv=copy") code_ifs.append('\t{}_alt{}(cont)'.format(A, a, d)) code_ifs.append('if __name__==\'__main__\':') code_ifs.append("\ts=\"\"\"") for p in G.P: code_ifs.append("\t{}".format(p)) code_ifs.append("\t\"\"\"") code_ifs.append('\trest=sys.argv[1]') code_ifs.append("\tderiv=Derivation(Grammar.from_string(s))") code_ifs.append('\tparse_{}(end_match)'.format(G.S)) return '\n'.join(code_defs) + '\n' + '\n'.join(code_ifs)
def make_parse_source(G): code_ifs = [] code_defs = [] code_defs.append('import sys') code_defs.append("#Code generated with generate_all_globals.py") code_defs.append('rest=\'\'') code_defs.append('pos=0') code_defs.append('deriv=[]') code_defs.append('def match(t):') code_defs.append('\tglobal rest,pos') code_defs.append('\tif t==rest[pos]:\n\t\tpos+=1\n\t\treturn True') code_defs.append('\telse:return False') for A in G.N: code_ifs.append("def parse_{}():\n\tglobal deriv".format(A)) for n, α in enumerate(G.alternatives(A)): code_defs.append( "def alt_{}_{}(rule):\n\tglobal pos,deriv\n\tp=pos\n\tind=len(deriv)\n\tderiv.append(rule)" .format(A, n)) for X in α: if X in G.T: code_defs.append("\tsucc = match('{}')".format(X)) code_defs.append( "\tif not succ:\n\t\tpos=p\n\t\tderiv=deriv[:ind]\n\t\treturn False" ) else: code_defs.append("\tsucc= parse_{}()".format(X)) code_defs.append( "\tif not succ:\n\t\tpos=p\n\t\treturn False") code_defs.append("\treturn True") code_ifs.append("\tsucc_alt= alt_{}_{}({})".format( A, n, G.P.index(Production(A, α)))) code_ifs.append("\tif succ_alt: return True") code_ifs.append("\treturn False") code_ifs.append('if __name__==\'__main__\':') code_ifs.append('\trest=sys.argv[1]+\'#\'') code_ifs.append( '\tif parse_{}():print(deriv)\n\telse:print(\'Invalid Expression\')'. format(G.S)) return '\n'.join(code_defs) + '\n' + '\n'.join(code_ifs)
def make_parse_source(G): code_ifs = [] code_defs = [] code_defs.append("#Code generated with cont_parser_generator.py") code_defs.append("import sys") code_defs.append("from liblet import Grammar,Production,Derivation") code_defs.append("def end_match(deriv,rest):\n\tif not rest:print(deriv)") code_defs.append( "def match(deriv,t,rest,cont):\n\tif rest and t==rest[0]:cont(deriv,rest[1:])" ) for A in G.N: code_ifs.append("def parse_{}(deriv,rest,cont):".format(A)) for a, α in enumerate(G.alternatives(A)): code_defs.append('def {}_alt{}(deriv, rest,cont):'.format(A, a)) for t in range(1, len(α)): code_defs.append('{}def {}(deriv, rest):'.format( '\t' * t, 't' * (len(α) - t))) for t, X in enumerate(reversed(α)): if X in G.T: code_defs.append("{}match(deriv, '{}', rest, {})".format( '\t' * (len(α) - t), X, 't' * t if t else 'cont')) else: code_defs.append("{}parse_{}(deriv,rest,{})".format( '\t' * (len(α) - t), X, 't' * t if t else 'cont')) d = G.P.index(Production(A, α)) code_ifs.append('\t{}_alt{}(deriv.leftmost({}), rest,cont)'.format( A, a, d)) code_ifs.append('if __name__==\'__main__\':') code_ifs.append("\ts=\"\"\"") for p in G.P: code_ifs.append("\t{}".format(p)) code_ifs.append("\t\"\"\"") code_ifs.append('\trest=sys.argv[1]') code_ifs.append( '\tparse_{}(Derivation(Grammar.from_string(s)),rest,end_match)'.format( G.S)) return '\n'.join(code_defs) + '\n' + '\n'.join(code_ifs)
def test_production_lto(self): self.assertIs( Production('a', ('b', )).__lt__(object()), NotImplemented)
def test_production_wrong_rhs(self): with self.assertRaises(ValueError): Production('a', [1])
def test_production_nonempty_rhs(self): with self.assertRaisesRegex(ValueError, 'nonempty'): Production('a', [])
def test_production_such_that_rhs_len(self): self.assertTrue( Production.such_that(rhs_len=2)(Production('X', ('x', 'y'))))
def test_production_such_that_rhs_is_suffix_of(self): self.assertTrue( Production.such_that(rhs_is_suffix_of=('a', 'x'))(Production( 'X', ('x', ))))
def test_production_wrong_lhs(self): with self.assertRaises(ValueError): Production(1, ['a'])
def test_production_such_that_rhs(self): self.assertTrue( Production.such_that(rhs='x')(Production('X', ('x', ))))
def test_production_from_string_cf(self): with self.assertRaisesRegex(ValueError, 'forbidden in a context-free'): Production.from_string("A B -> c", True)
def test_production_aε(self): with self.assertRaisesRegex(ValueError, 'contains ε but has more than one symbol'): Production('A', ('a', ε))
def test_production_eqo(self): self.assertFalse(Production('a', ('b', )) == object())
def test_production_totalorder(self): self.assertTrue(Production('a', ('b', )) > Production('a', ('a', )))
def test_production_unpack(self): lhs, rhs = Production('a', ['b']) self.assertEqual(('a', ('b', )), (lhs, rhs))