написание переносимого предметно-ориентированного языка - PullRequest
5 голосов
/ 04 октября 2009

Я хотел бы знать хорошие стратегии для развертывания предметно-ориентированного языка, который должен работать как минимум на двух языках (Java, C #) и, возможно, на большем (Python и, возможно, Javascript).

Некоторый фон. Мы разработали и внедрили предметно-ориентированный язык, в настоящее время написанный на C #. Он развертывается через серию вызовов методов, аргументами которых являются либо общеязыковые примитивы (string, double и т. Д.), Collections (IEnumerable, HashSet, ...) или объекты в доменной библиотеке (CMLMolecule, Point3, RealSquareMatrix). Библиотека хорошо протестирована, и объекты должны соответствовать стабильно развернутой XML-схеме, поэтому изменения будут эволюционными и управляемыми (по крайней мере, это надежда).

Мы надеемся, что этот язык будет использоваться широким и частично компьютерно-грамотным сообществом, привыкшим взламывать свои собственные решения без центрального контроля. В идеале DSL создаст степень инкапсуляции и обеспечит необходимую им функциональность. Библиотеки будут управлять детальными алгоритмами, которые многочисленны и разнообразны, но довольно хорошо известны. Существует много общего с требованиями DSL в доменных языках против библиотеки функций .

Буду признателен за идеи о лучшей архитектуре (очевидно, что после ее развертывания мы не сможем легко вернуться). Выбор включает как минимум:

  • Создание IDL (например, через CORBA). W3C сделал это для XML DOM - я ненавидел это - и это кажется излишним
  • ручное создание похожих подписей для каждой платформы и лучшее стремление их синхронизировать.
  • Создание анализируемого языка (например, CSS).
  • декларативное программирование в XML (см. XSLT). Это мое предпочтительное решение, так как его можно искать, манипулировать и т. Д.

Производительность не важна. Ясность цели есть.

EDIT Был обсужден вопрос о том, являются ли вызовы приложений частью DSL. Я обнаружил введение Мартина Фаулера в DSL (http://martinfowler.com/dslwip/Intro.html)), где он утверждает, что простые вызовы методов (или цепочечные вызовы) можно назвать DSL. Так что ряд такой:

point0 = line0.intersectWith(plane);
point1 = line1.intersectWith(plane);
midpoint = point0.midpoint(point1);

можно считать DSL

Ответы [ 7 ]

7 голосов
/ 04 октября 2009

Кажется, в вопросе между языком и библиотекой существует некоторая двусмысленность. Термины «внутренний 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), поэтому один набор пользователей будет чувствовать запах крысы.

3 голосов
/ 08 октября 2009

Если вы хотите переформулировать свой язык, используя ANTLR , вы можете создать свой переводчик DSL на нескольких языках, не поддерживая их вручную, включая все языки, которые вы упомянули, и другие.

Antlr является генератором синтаксического анализатора / лексера и имеет большое количество целевых языков. Это позволяет вам описать свой язык один раз, не поддерживая несколько его копий.

Посмотреть весь список целевых языков здесь .

2 голосов
/ 08 октября 2009

Хотя я не хочу слишком много рекламировать свой собственный проект, я хотел бы упомянуть PIL, независимый от платформы язык , промежуточный язык, над которым я работаю, чтобы обеспечить поддержку нескольких программных платформ. (например, Java, Python, ...), специально для внешних DSL. Общая идея заключается в том, что вы генерируете код в PIL (подмножество Java), который компилятор PIL может затем перевести на один из многих других языков, в настоящее время только Java или Python, но в будущем будет добавлено больше.

Я представил доклад об этом на конференции Software and Language Engineering около 2 дней назад, вы можете найти ссылку на публикацию на веб-сайте PIL ( pil-lang.org ), если вы ' заинтересован.

1 голос
/ 04 октября 2009

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

Я исследую DSL для реализации правил в механизме правил в C #, некоторые из них действительно сложны и могут значительно измениться в будущем, поэтому возможность выхода из C # действительно полезна. Конечно, это нарушает кросс-платформенную совместимость, но на самом деле это просто способ взломать крайние случаи без необходимости изменения DSL.

0 голосов
/ 15 октября 2009

Я хотел бы расширить ответ Дариена. Я думаю, что ANTLR привносит в таблицу что-то, что предоставляют немногие другие инструменты лексера / парсера (по крайней мере, насколько мне известно). Если вы хотите создать DSL, который в конечном итоге генерирует код Java и C #, ANTLR действительно сияет.

ANTLR предоставляет четыре основных компонента:

  • Грамматика Лексера (разбить входные потоки на токены)
  • грамматика синтаксического анализатора (организовать токены в абстрактное синтаксическое дерево)
  • Tree Grammar (пройтись по абстрактному синтаксическому дереву и передать метаданные в шаблонизатор)
  • StringTemplate (механизм шаблонов, основанный на принципах функционального программирования)

Ваш лексер, синтаксический анализатор и древовидная грамматика могут оставаться независимыми от вашего окончательно сгенерированного языка. Фактически, механизм StringTemplate поддерживает логические группы определений шаблонов. Он даже обеспечивает наследование интерфейса групп шаблонов. Это означает, что вы можете использовать сторонние анализаторы ANTLR для создания, скажем, python, assembly, c или ruby, когда все, что вы изначально предоставили, были выходные данные java и C #. Язык вывода вашего DSL может быть легко расширен, поскольку требования со временем меняются.

Чтобы получить максимальную отдачу от ANTLR, вам нужно прочитать следующее:

Полное руководство по ANTLR: создание доменных языков

Шаблоны языковой реализации: создание собственных доменных и общих языков программирования

0 голосов
/ 04 октября 2009

Возможно интерпретировать JavaScript изнутри Java-программы напрямую с помощью обработчика сценариев и, по-видимому, также из C #. Python может быть запущен на JVM и .NET.

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

0 голосов
/ 04 октября 2009

Лучше всего написать библиотеку на C (или на каком-нибудь языке, например rpython, который будет генерировать C-код), а затем использовать SWIG или аналогичный для генерации привязок к языку для C #, Java Python и т. Д.

Обратите внимание, что этот подход не поможет, если вы используете Javascript в браузере - вам придется писать библиотеку javascript отдельно. Если вы используете javascript через Rhino, вы сможете просто использовать привязки Java.

...