Все больше и больше утыкаюсь в ограничения возможностей Free Pascal'я. Сегодня решил начать осуществлять свою давнюю задумку - препроцессор.
Итак, в чем заключается задумка. Есть файлы, написанные на моем расширенном паскале, имеют расширение dpp. Препроцессор просматривает папки, ищет такие файлы, и на их основе генерирует pas-файлы, которые уже можно просто скомпилировать free pascal'ем.
Препроцессор файлы в основном не трогает, и обрабатывает лишь известные ему конструкции. При этом, на результат его деятельности наложено одно ограничение: любой код, который он генерирует, должен умещаться на одну строку и быть добавлен в конец какой-то существующей строки.
Сделано это странное ограничение для того, чтобы компилятор Free Pascal когда сообщал об ошибках, указывал бы номера строки и столбца ошибки совпадающие с соответствующими строками и столбцами в dpp-файла.
Моя утилитка dpp будет open source и ей сможет пользоваться любой желающий.
Это все была теория использования. О том, как утилитка действует, я расскажу в следующий раз, а сейчас перечислю некоторые фишки, которые хочу с помощью нее реализовать:
1) Событийную систему. К сожалению, мне не удалось на чистом fpc написать красиво отправку сообщения, поэтому ввожу такую конструкцию
#(5, 3, 'hello', Obj)-> Notifier
Она отправляет сообщение в Notifier с параметрами 5, 3, 'hello', Obj.
2) Автоматические создание и освобождение классов. Две конструкции
#autoclass(FMyClass: TMyClass) TMyExtendedClass.Create('hello')
Описывается внутри описания класса. Создает у класса поле FMyClass, которое будет автоматически создаваться во всех конструкторах вызовом TMyExtendedClass.Create('hello') и автоматически освобождаться в каждом деструкторе. По сути, время жизни поля привязывается к времени жизни хозяина - частоиспользуемая схема.
#stackclass(MyClass: TMyClass) TMyExtendedClass.Create('hello', Param1)
Описывается внутри описания метода. Автоматически создает в начале метода, автоматически уничтожает в конце
3) Система сериализации классов (для генерации кода по загрузке/сохранению). Тут немного сложнее, основные конструкции примерно такие:
#streaminterface
#streamimplementation(TMyClass)
Создает все необходимые функции по сохранению/загрузке класса TMyClass
#streamfield(FImportantValue: Integer)
Создает поле у класса, которое необходимо сохранять
4) Продвинутое RTTI.
#RTTIclass(MyRTTIVar) from TMyClass
Записывает в MyRTTIVar RTTI-информацию о классе TMyClass
5) Вставка в код название текущего файла/текущего метода/содержимого текущей строки/номера текущей строки. Очень удобно для логов.
#currentfilename_______________
#currentmethodname_____________
#currentline___________________
#currentlinenumber_____________
6) Собственно, печать в лог с указанием всей нужной инфы из пункта 5
#log 'error ' + IntToStr(ErrorId) + '!'
Пока что готов только пункт 1 :)
Комментариев нет:
Отправить комментарий