чтение / разбор общих файлов lisp из lisp без доступа ко всем пакетам или загрузка всего - PullRequest
0 голосов
/ 19 мая 2019

Я занимаюсь проектом, который включает в себя анализ историй обычных репозиториев на lisp. Мне нужно разобрать их в списки списков или что-то в этом роде. В идеале я бы хотел сохранить как можно больше исходного синтаксиса исходного файла. Например, в случае текста #+sbcl <something>, который, я думаю, означает «Если наш текущий lisp - sbcl, прочитайте <something>, в противном случае пропустите его», я хотел бы получить что-то вроде (#+ 'sbcl <something>).

Первоначально я написал LALR-парсер на Python, который работал, но по многим причинам он не идеален. У меня много трудностей с получением правильного вывода, и у меня есть тонны особых случаев, которые нужно добавить.

Я подумал, что на самом деле я должен использовать сам lisp, поскольку в него уже встроен парсер lisp. Если бы я мог просто прочитать файл в sexps, я бы мог его записать во что-нибудь (подойдет cl-json) для дальнейшей обработки по линии.

К сожалению, когда я пытаюсь прочитать https://github.com/fukamachi/woo/blob/master/src/woo.lisp,, я получаю ошибку

There is no package with the name WOO.EV.TCP

, который, конечно, идет из строки 80 этого файла, поскольку этот пакет определен в src/ev/tcp.lisp, а мы его не читали.

В принципе, возможно ли просто прочитать файл в sexps, не заботясь о том, определены ли пакеты или они содержат соответствующие символы? Если так, то как? Я попытался просмотреть документацию по читателю HyperSpec, но не вижу ничего, что звучит уместно.

Я на практике не пишу общий lisp, но потенциально возможно возможно взломать, обработав неопределенное условие пакета, создав пустой пакет с таким именем и обработав Условие условного обозначения имени в пакете, просто заключая данный символ. Я думаю . Я не знаю, как на самом деле это сделать, я не знаю, сработает ли это, я не знаю, сколько будет особых случаев. Случайно, первое условие называется no-such-package, но второе (по крайней мере, в sbcl) называется simple-error, поэтому я даже не знаю, как определить, является ли этот конкретный simple-error символом такого-не-такого -in-that-package error, не говоря уже о том, как извлечь соответствующие имена из условия, исправить его и перезапустить. Мне бы очень хотелось услышать от обычного эксперта по LISP, что это правильное решение, прежде чем я попытаюсь сделать это таким образом, потому что это потребует много знаний.

Мне также кажется, что я мог бы это исправить, просто собрав файл перед его чтением. Например. превращая woo.ev.tcp:start-listening-socket в, скажем, woo.ev.tcp===start-listening-socket. Мне не особенно нравится это решение, и не ясно, что я не столкнусь с множеством более отвратительных особых случаев, но оно может сработать, если нет лучшего ответа.

Ответы [ 2 ]

2 голосов
/ 19 мая 2019

Я почти уверен, что по ряду причин нет простого переносимого способа сделать это.

(Пока ограничимся только проблемой несуществующего пакета).

Прежде всего, нет никакого портативного доступа к биту считывателя, который решает, что токены будут символами, а затем ищет маркеры пакетов & c: это просто происходит в соответствии с правилами в 2.3 . Таким образом, вы не можете легко вмешаться в это.

Во-вторых, в любом состоянии недостаточно информации, которую читатель может дать понять, чтобы справиться с ними.

Есть несколько возможных путей выхода из этой части проблемы.

Если вы чувствовали себя достаточно героически, вы могли бы научить читателя, что все символы, запускающие токен, фактически являются вещами, которыми вы управляете, а затем написать программу чтения токенов, которая каким-то образом обрабатывает весь пакет, возвращая некоторый объект, который не символ Но для этого вам нужно иметь дело с числами, и если вы думаете, что это просто, ну, это не так.

Если вы почувствовали себя менее героически, вы могли бы написать более примитивного считывателя токенов, который просто даже не пытался бы справиться с чем-либо, кроме захвата всех необходимых символов, и возвращает какой-то объект, который оборачивает строку. Это позволило бы избежать проблемы с целым числом за счет потери большого количества информации.

Если вас не волнует переносимость, найдите реализацию, поймите, как это делает читатель, и разберитесь с ней. Существует больше реализаций с открытым исходным кодом или доступных источников, чем я могу легко сосчитать (возможно, я не очень хорош в подсчете), так что это довольно хороший подход. Это, конечно, то, что я бы сделал.


Но это только начало проблем. Читатель CL волосат и в своей стандартной конфигурации (конфигурация, которая используется для таких вещей, как compile-file, если люди не договорились об ином) может запускать совершенно произвольный код во время чтения, включая код, который модифицирует сам читатель, некоторые из которых могут сделать это в зависимости от реализации. И люди используют это: есть причина, по которой Лисп называют «программируемым языком программирования», и люди его программируют.

0 голосов
/ 20 мая 2019

Я решил решить эту проблему, используя sed (на самом деле Python re.sub, но кто рассчитывает?), Потому что это будет работать для моего фактического варианта использования, и было легко.

Для будущих читателей: Различные люди, которые говорят, что это вообще невозможно, вероятно, правы.Другие вопросы, опубликованные @Svante, выглядят как хорошие простые способы решения части проблемы.Другие части проблемы можно было бы решить более элегантно, заменив макросы считывателя для #., #+, #- и т. Д. На те, которые просто составляют список, что звучит менее героично, чем предложения @tfb, но яу меня нет времени на это дерьмо.

...