Как исправить ошибку синтаксического анализа с тем, что кажется допустимым s-выражением в Python?

У меня возникла непредвиденная ошибка при синтаксическом анализе (строкового) s-выражения во вложенный массив/списки, представляющие AST. Выражение s взято из (SerAPI https://github.com/ejgallego/coq-serapi), но мне кажется, что это нормально:

sexp = b'(Answer 3(ObjList((CoqGoal((fg_goals(((name 3)(ty(App(Ind(((Mutind(MPfile(DirPath((Id Logic)(Id Init)(Id Coq))))(DirPath())(Id eq))0)(Instance())))((Ind(((Mutind(MPfile(DirPath((Id Datatypes)(Id Init)(Id Coq))))(DirPath())(Id bool))0)(Instance())))(App(Const((Constant(MPfile(DirPath((Id Nat)(Id Init)(Id Coq))))(DirPath())(Id odd))(Instance())))((App(Construct((((Mutind(MPfile(DirPath((Id Datatypes)(Id Init)(Id Coq))))(DirPath())(Id nat))0)2)(Instance())))((Construct((((Mutind(MPfile(DirPath((Id Datatypes)(Id Init)(Id Coq))))(DirPath())(Id nat))0)1)(Instance())))))))(Construct((((Mutind(MPfile(DirPath((Id Datatypes)(Id Init)(Id Coq))))(DirPath())(Id bool))0)1)(Instance()))))))(hyp()))))(bg_goals())(shelved_goals())(given_up_goals()))))))\n'

Когда я пытаюсь проанализировать это, я получаю следующее сообщение об ошибке:

train(policy,optimizer,env,gamma,nb_episodes=nb_episodes,ema_alpha=ema_alpha)
  File "main.py", line 88, in train
    state, reward, done, _ = env.step('Example test_oddb1: Nat.odd 1 = true.')
  File "/Users/korkejudith/home_simulation_research/coq-serapi-python/python_api/coq_env.py", line 120, in step
    state = self.state_embedder(state)
  File "/Users/korkejudith/home_simulation_research/coq-serapi-python/python_api/ai_mathematician.py", line 33, in __call__
    psexp = loads(str(sexp))
  File "/Users/korkejudith/miniconda3/envs/rltp/lib/python3.6/site-packages/sexpdata.py", line 243, in loads
    obj = parse(string, **kwds)
  File "/Users/korkejudith/miniconda3/envs/rltp/lib/python3.6/site-packages/sexpdata.py", line 675, in parse
    return Parser(string, **kwds).parse()
  File "/Users/korkejudith/miniconda3/envs/rltp/lib/python3.6/site-packages/sexpdata.py", line 655, in parse
    (i, sexp) = self.parse_sexp(0)
  File "/Users/korkejudith/miniconda3/envs/rltp/lib/python3.6/site-packages/sexpdata.py", line 641, in parse_sexp
    (i, subsexp) = self.parse_sexp(i + 1)
  File "/Users/korkejudith/miniconda3/envs/rltp/lib/python3.6/site-packages/sexpdata.py", line 642, in parse_sexp
    append(Quoted(subsexp[0]))
IndexError: list index out of range

Я пробовал другую версию строки, но ни одна из них не работает. Кто-нибудь знает, что может пойти не так?


Код для воспроизведения ошибки с разными версиями, которые мне не удалось:

from sexpdata import loads, dumps

def buffer_test():
    print('buffer_test')
    sexp = ''' b'(Answer 3(ObjList((CoqGoal((fg_goals(((name 3)(ty(Prod(Name(Id n))(Ind(((Mutind(MPfile(DirPath((Id Datatypes)(Id Init)(Id Coq))))(DirPath())(Id nat))0)(Instance())))(App(Ind(((Mutind(MPfile(DirPath((Id Logic)(Id Init)(Id Coq))))(DirPath())(Id eq))0)(Instance())))((Ind(((Mutind(MPfile(DirPath((Id Datatypes)(Id Init)(Id Coq))))(DirPath())(Id nat))0)(Instance())))(App(Const((Constant(MPfile(DirPath((Id Nat)(Id Init)(Id Coq))))(DirPath())(Id add))(Instance())))((Construct((((Mutind(MPfile(DirPath((Id Datatypes)(Id Init)(Id Coq))))(DirPath())(Id nat))0)1)(Instance())))(Rel 1)))(Rel 1)))))(hyp()))))(bg_goals())(shelved_goals())(given_up_goals()))))))\n'
    '''
    print(f'sexp = {sexp}')
    psexp = loads(sexp)

def buffer_str_test():
    print('buffer_str_test')
    sexp = str(''' b'(Answer 3(ObjList((CoqGoal((fg_goals(((name 3)(ty(Prod(Name(Id n))(Ind(((Mutind(MPfile(DirPath((Id Datatypes)(Id Init)(Id Coq))))(DirPath())(Id nat))0)(Instance())))(App(Ind(((Mutind(MPfile(DirPath((Id Logic)(Id Init)(Id Coq))))(DirPath())(Id eq))0)(Instance())))((Ind(((Mutind(MPfile(DirPath((Id Datatypes)(Id Init)(Id Coq))))(DirPath())(Id nat))0)(Instance())))(App(Const((Constant(MPfile(DirPath((Id Nat)(Id Init)(Id Coq))))(DirPath())(Id add))(Instance())))((Construct((((Mutind(MPfile(DirPath((Id Datatypes)(Id Init)(Id Coq))))(DirPath())(Id nat))0)1)(Instance())))(Rel 1)))(Rel 1)))))(hyp()))))(bg_goals())(shelved_goals())(given_up_goals()))))))\n'
    ''')
    print(f'sexp = {sexp}')
    psexp = loads(sexp)

def str_str_test():
    print('str_str_test')
    sexp = str(''' (Answer 3(ObjList((CoqGoal((fg_goals(((name 3)(ty(Prod(Name(Id n))(Ind(((Mutind(MPfile(DirPath((Id Datatypes)(Id Init)(Id Coq))))(DirPath())(Id nat))0)(Instance())))(App(Ind(((Mutind(MPfile(DirPath((Id Logic)(Id Init)(Id Coq))))(DirPath())(Id eq))0)(Instance())))((Ind(((Mutind(MPfile(DirPath((Id Datatypes)(Id Init)(Id Coq))))(DirPath())(Id nat))0)(Instance())))(App(Const((Constant(MPfile(DirPath((Id Nat)(Id Init)(Id Coq))))(DirPath())(Id add))(Instance())))((Construct((((Mutind(MPfile(DirPath((Id Datatypes)(Id Init)(Id Coq))))(DirPath())(Id nat))0)1)(Instance())))(Rel 1)))(Rel 1)))))(hyp()))))(bg_goals())(shelved_goals())(given_up_goals()))))))\n'
    ''')
    print(f'sexp = {sexp}')
    psexp = loads(sexp)

def str_test():
    print('str_test')
    sexp = ''' (Answer 3(ObjList((CoqGoal((fg_goals(((name 3)(ty(Prod(Name(Id n))(Ind(((Mutind(MPfile(DirPath((Id Datatypes)(Id Init)(Id Coq))))(DirPath())(Id nat))0)(Instance())))(App(Ind(((Mutind(MPfile(DirPath((Id Logic)(Id Init)(Id Coq))))(DirPath())(Id eq))0)(Instance())))((Ind(((Mutind(MPfile(DirPath((Id Datatypes)(Id Init)(Id Coq))))(DirPath())(Id nat))0)(Instance())))(App(Const((Constant(MPfile(DirPath((Id Nat)(Id Init)(Id Coq))))(DirPath())(Id add))(Instance())))((Construct((((Mutind(MPfile(DirPath((Id Datatypes)(Id Init)(Id Coq))))(DirPath())(Id nat))0)1)(Instance())))(Rel 1)))(Rel 1)))))(hyp()))))(bg_goals())(shelved_goals())(given_up_goals()))))))'
    '''
    print(f'sexp = {sexp}')
    psexp = loads(sexp)

if __name__ == '__main__':
    print('running main')
    buffer_test()
    buffer_str_test()
    str_str_test()
    str_test()
    print('sucessful main')

Я также открыл эту gitissue:

https://github.com/jd-boyd/sexpdata/issues/18


кросспост:

https://www.reddit.com/r/Python/comments/bg87nx/how_does_one_fix_a_parsing_error_with_what_seems/

https://www.quora.com/unanswered/How-does-one-fix-a-parsing-error-with-what-seems-a-valid-s-expression-in-Python< /а>


person Charlie Parker    schedule 22.04.2019    source источник
comment
Не зная про sexpdata, мне кажется, что дело может быть в строковом типе. Например, ''' b' кажется мне большой путаницей.   -  person fabianegli    schedule 23.04.2019


Ответы (1)


Вам нужно исправить sexp, чтобы он стал обычной строкой.


Неверный код, указанный в трассировке стека

        elif c == "'":
            (i, subsexp) = self.parse_sexp(i + 1)
            append(Quoted(subsexp[0]))
            sexp.extend(subsexp[1:])

предполагает, что каким-то образом в вашем выражении есть апостроф. (Отладка ясно показала бы это.) Откуда это могло взяться?

  File "/Users/korkejudith/home_simulation_research/coq-serapi-python/python_api/ai_mathematician.py", line 33, in __call__
    psexp = loads(str(sexp))

Это виновник. В Python 3 str(bytes) соответствует repr.

person ivan_pozdeev    schedule 22.04.2019
comment
хм, ладно, почему-то я неправильно преобразовываю его в строку. Как мне правильно преобразовать его в строку? - person Charlie Parker; 23.04.2019
comment
хорошо, так что sexp.decode('utf-8'), кажется, работает для меня. Но как выбрать кодировку? Я как бы случайно выбрал один. - person Charlie Parker; 23.04.2019
comment
@CharlieParker Вам нужно выбрать его в зависимости от того, какие символы могут появляться в байтовой строке и как они должны быть закодированы (например, в случае национальных символов). Если не может появиться ничего, кроме символов ASCII, вы также можете использовать ascii. - person ivan_pozdeev; 23.04.2019
comment
Привет, сопровождающий sexpdata здесь; проблема действительно заключается в заключении строк в кавычки, она просто усугубляется тем фактом, что апостроф — это сокращение шепелявости для цитирования списков и символов ( '(foo) эквивалентно (quote (foo))), поэтому, увидев b'(foo)', sexpdata пытался разобрать его как символ b, за которым следует '(foo) , за которым следует ' и выдает загадочную ошибку. У меня есть исправление, которое скоро будет объединено. - person immerrr; 24.04.2019
comment
На самом деле, написание этого комментария заставило меня подумать, что нам, вероятно, следует удалить реализацию сокращенной записи в кавычки, потому что она действительно принадлежит LISP, а не синтаксическому анализу s-выражения как таковому. - person immerrr; 24.04.2019
comment
@immerrr, так что мне делать с моим кодом/строкой? прямо сейчас кодирование в utf-8 заставляет синтаксический анализатор работать. - person Charlie Parker; 25.04.2019
comment
Как правильно указал Иван, вам нужно заменить str(sexp) на sexp.decode('utf-8'), так как это правильный способ преобразования bytes в string в Python. - person immerrr; 26.04.2019