Кажется, в вопросе между языком и библиотекой существует некоторая двусмысленность. Термины «внутренний DSL» и «внешний DSL» полезны, и я думаю, что это связано с Мартином Фаулером .
«Внешний» DSL может быть автономным инструментом командной строки. Передается строка источника, он как-то анализирует и что-то делает с этим. Нет никаких реальных ограничений на то, как синтаксис и семантика могут работать. Его также можно сделать доступным в виде библиотеки, состоящей в основном из eval
-подобного метода; типичный пример - создание SQL-запроса в виде строки и вызов метода execute
в библиотеке СУБД; не очень приятный или удобный способ использования, и ужасно, если распространять вокруг программы в больших масштабах.
«Внутренний» DSL - это библиотека, которая написана таким образом, чтобы воспользоваться преимуществами языка хоста (общего назначения), чтобы создать впечатление, что новый язык может быть встроен в существующий. В синтаксически богатых языках (C ++, C #) это означает использование перегрузки операторов способами, которые серьезно расширяют (или игнорируют) обычные значения символов операторов. Есть много примеров в C ++; некоторые в C # также - Инструментарий парсера иронии имитирует BNF довольно сдержанно, что хорошо работает.
Наконец, есть простая старая библиотека: классы, методы, свойства с хорошо подобранными именами.
Внешний DSL позволил бы вам полностью игнорировать проблемы межъязыковой интеграции, поскольку единственной библиотечно-подобной частью был бы метод eval
. Но изобрести собственную цепочку инструментов нетривиально. Люди всегда забывают об огромной важности отладки, осмысления, выделения синтаксиса и т. Д.
Внутренний DSL, вероятно, бессмысленное занятие, если вы хотите сделать это хорошо на C # и Java. Проблема заключается в том, что если вы воспользуетесь особенностями одного языка хоста, вы не обязательно сможете повторить трюк на другом языке. например В Java нет перегрузки операторов.
Что оставляет старую простую библиотеку. Если вы хотите охватить C # и Java (по крайней мере), то вы несколько застряли с точки зрения выбора языка реализации. Вы действительно хотите написать библиотеку дважды? Одна возможность - написать библиотеку на Java, а затем использовать IKVM для кросс-компиляции в сборки .NET. Это гарантирует вам идентичный интерфейс на обеих этих платформах.
С другой стороны, API будет выражаться в функциях с наименьшим общим знаменателем - то есть, в функциях Java :). Нет свойств, только методы getX / setX. Держитесь подальше от дженериков, потому что в этом отношении две системы совершенно разные Кроме того, даже стандартный способ именования отличается между этими двумя (camelCase
против PascalCase
), поэтому один набор пользователей будет чувствовать запах крысы.