Каков наилучший подход к пошаговой компиляции при построении DSL с использованием Eclipse?
Как указано в документации по Eclipse, у меня есть org.eclipse.core.resources.IncrementalProjectBuilder
который компилирует каждый исходный файл и отдельно у меня также есть org.eclipse.ui.editors.text.TextEditor
который может редактировать каждый исходный файл. Каждый исходный файл компилируется в свой собственный модуль компиляции, но он может ссылаться на типы из других (уже скомпилированных) исходных файлов.
Две задачи, для которых это важно:
- Компиляция (чтобы убедиться, что используемые типы действительно существуют)
- Автозаполнение (для поиска типа, чтобы мы могли видеть, какие свойства / методы присутствуют в нем)
Чтобы достичь этого, я хочу сохранить представление всех скомпилированных типов в памяти (ниже называемое моим "хранилищем типов").
Мой вопрос в два раза:
Задача первая, указанная выше, выполняется редактором, а задача вторая - редактором. Чтобы они оба имели доступ к этому хранилищу типов, должен ли я создать статическое хранилище, к которому они оба могут иметь доступ, или Eclipse предоставляет более удобный способ решения этой проблемы? Обратите внимание, что затмение, а не я, создает экземпляры строителей и редакторов, когда они необходимы.
Открывая Eclipse, я не хочу перестраивать весь проект только для того, чтобы я мог заново заполнить свое хранилище типов. Мое лучшее решение на данный момент - сохранить эти данные где-нибудь, а затем снова заполнить мой магазин этим (возможно, при открытии проекта). Так ли это делают другие инкрементные компиляторы? Я считаю, что подход Java заключается в использовании специального синтаксического анализатора, который эффективно извлекает эти данные из файлов классов.
Любые идеи будут по достоинству оценены. Это мой первый DSL.
1 ответ
Это интересный вопрос, который не имеет простого решения. Я постараюсь описать потенциальное решение, а также немного подробнее описать, как JDT выполняет инкрементную компиляцию.
Сначала немного о JDT:
Да, JDT читает файлы классов для некоторой информации, но только для библиотек, которые не имеют исходного кода. И эта информация действительно используется только для помощи в редактировании (помощник по контенту, навигация и т. Д.).
JDT вычисляет инкрементную компиляцию, отслеживая зависимости между модулями компиляции по мере их компиляции. Эта информация о состоянии сохраняется на диске, извлекается и обновляется после каждой компиляции.
В качестве более полного примера, скажем, что после полной сборки JDT определяет, что A.java зависит от B.java, который зависит от C.java.
Если в C.java есть структурное изменение (структурное изменение - это изменение, которое может повлиять на внешние файлы (например, добавление / удаление не закрытого поля или метода)), то B.java будет перекомпилирован. A.java не будет перекомпилирован, поскольку в B.java не было структурных изменений.
После небольшого разъяснения о том, как работает JDT, вот несколько возможных ответов на ваши вопросы:
- Да. Это должно быть сделано через статически доступные глобальные объекты. JDT делает это через объекты JavaCore и JavaModelManager. Если вы не хотите использовать глобальные синглтоны, вы можете получить доступ к вашему хранилищу типов, доступному через экземпляр активатора Bundle вашего плагина. Проект e4 допускает внедрение зависимостей, что, вероятно, даже лучше (но на самом деле не является частью основных API Eclipse).
- Я думаю, что сохранение информации в файловой системе - ваш лучший выбор. Единственный реальный способ определения инкрементных зависимостей компиляции - это полная сборка, поэтому вам нужно где-то сохранить информацию. Опять же, вот как это делает JDT. Информация хранится в ваших рабочих пространствах
.metadata
каталог где-нибудь в плагине org.eclipse.core.resources. Вы можете взглянуть наorg.eclipse.jdt.internal.core.builder.State
класс, чтобы увидеть реализацию.
Так что, возможно, это не тот ответ, который вы ищете, но я думаю, что это наиболее перспективный способ решения вашей проблемы.