DelphiWebScript 00, введение
DWScript - это объектно-ориентированный скриптовый язык общего назначения.
DWScript написан на Delphi и для использования в Delphi - программах.
Синтаксис языка очень похож на Delphi, а также поддерживает синтаксис и возможности, аналогичные Prism и FreePascal, а также массу языковых расширений.
Скрипты могут быть выполнены из приложений Delphi (безопасно, в "песочнице"). Также скрипты могут быть скомпилированы и выполнены с помощью JavaScript-движка Smart Mobile Studio. Для Win32 доступен экспериментальный JIT-компилятор.
Возможности:
- классы, интерфейсы, записи;
- статические и динамические массивы;
- безопасное выполнение в песочнице, автоматическое управление памятью;
- сильная типизация;
- получение информации о типе;
- полная поддержка мета-классов;
- поддержка указателей на функции и методы;
- контрактное программирование;
- обобщенные хелперы;
- обобщенный синтаксис «case of» и «in […]»;
- области видомости, объявление переменных в произвольном месте;
- перегрузка операторов;
- составные операторы присваивания;
- широкие возможности вмешательства в процесс выполнения, объявления, интроспекции и отладки;
- inline - реализации методов класса;
- частичные классы;
- применение выражений в свойствах;
- автоматическое выведение типов Delphi с помощью RTTI;
- совместимость с COM/OLE (через COM - коннектор);
- совместимость с RTTI (через RTTI - коннектор);
- ассемблер asm (32 бита, с помощью NASM);
- возможность генерации кода JavaScript (компиляция в JavaScript);
- и т.п.
Пример кода:
type
THelloWorld = class
procedure Put; // Реализацию можно поместить прямо тут. Inline - реализация!
begin
PrintLn('Привет!');
end
end;
var HelloWorld := new THelloWorld; // Строгая типизация, автоматический вывод типа
HelloWorld.Put;
// Не нужно освобождать объект, ибо автоматическое управление памятью
type THelloWorld = class procedure Put; // Реализацию можно поместить прямо тут. Inline - реализация! begin PrintLn('Привет!'); end end; var HelloWorld := new THelloWorld; // Строгая типизация, автоматический вывод типа HelloWorld.Put; // Не нужно освобождать объект, ибо автоматическое управление памятью
Структура кода
Структура кода по сути является стандартной паскалевской, со следующими особенностями:
- переменные, константы и процедуры могут быть определены по месту.
- begin/end являются необязательными для главного кода программы.
- ключевые слова var, const и type должны указываться явно перед любыми объявлениями переменных или типов в главной программе (блоки var/const разрешены в procedure, перед первым begin).
- методы могут быть определены по месту объявления (в объявлении класса).
Переменные гарантированно инициализацируются.
Объявление переменной может содержать присваивание, тип переменной может быть выведен, например:
var i := 20;
эквивалентно следующему:
var i : Integer;
i:=20;
и следующему:
var i : Integer := 20;
Базовые типы:
- Integer : 64-битное целое;
- Float : число с плавающей запятой, двойной точности;
- Boolean : True/False.
- String : строка - изменяемая, копируется при записи, индексируется с 1, UTF-16.
Строки могут быть ограничены одиночными ' или двойными " кавычками.
В строке с одинарными кавычками можно разместить одинарную кавычку, удвоив ее: '123''456'.
В строке с двойными кавычками можно разместить двойную кавычку, удвоив ее: "321""654".
Строки в двойных кавычках могут занимать несколько строк:
Print("Здравствуй,
Мир!");
Символы Юникода могут заданы с помощью #, за которым следует число (десятичное или шестнадцатеричное). Символы, указанные таким образом, всегда понимаются как кодированные в Unicode. Следующий код
Print('Здравствуй,'#13#$0D'Мир!');
- Напечатает "Здравствуй,", затем CR + LF (код ASCII 13 и 10), затем "Мир!", то же самое можно закодировать с двойными кавычками, вот так:
Print("Здравствуй,
Мир!");
Наконец, можно определить строки с отступом, с помощью # "или # ', тогда компилятор игнорирует обычные отступы и дополнительно игнорирует пустую первую строку, так что также можно написать
Print(#"
Здравствуй,
Мир!");
Опциональные типы:
- Variant;
- поддержка COM: OleVariant, ComVariant, ComVariantArray;
- RttiVariant : специализированный интерфейс для типов Delphi RTTI;
- TComplex : комплексное число двойной точности (dwsMathComplexFunctions);
- Vector : double-precision 4D - гомогенный вектор двойной точности (dwsMath3DFunctions);
- Matrix :4D - матрица двойной точности (dwsMath3DFunctions)
Комментарии
Поддерживаются стили как Pascal, так и C/C++:
- ** обозначают однострочный комментарий;
- (* и *) - многострочный комментарий;
- { и } - многострочный комментарий;
- /* и */ - многострочный комментарий.
Комменатрии не могут быть вложенными.
Классы
Все классы наследуются от корневого класса TObject и в общем следуют синтаксису Delphi. Классы являются ссылочными типами.
Поддерживаются именованные конструкторы, методы класса, метаклассы, виртуальные методы, свойства и деструкторы. Свойства могут быть типа массив и могут иметь индекс.
Видомость членов: private, protected, public и published:
- в режиме скрипта (или в главной программе), private и protected понимаются как strict private и strict protected
- в режиме билда (в модулях), private и protected понимаются в классическом варианте (из раздела реализации модуля есть доступ к private/protected членам)
Классы могут реализовать интерфейсы, в том числе и частично.
Также в классе можно можно объявить методы с опцией "method", как в языке Oxygene, в дополнение к "procedure" и "function".
Дополнительно классы могут быть помечены как "external", в этом случае предполагается, что такие классы не реализованы в скрипте и, в отличии от интерфейсов, в них могут быть определены поля.
Конструкторы
Поддерживается классический синтаксис конструкторов, но можно также определить конструктор по умолчанию и для создания экземпляра использовать ключевой слово "new".
Обе строчки кода эквивалентны:
obj := TMyObject.Create(parameter);
obj := new TMyObject(parameter);
Свойства
Свойства позволяют инкапсулировать работу в синтаксисе, подобном полям, которые реально могут быть методами(getter/setter).
property Name[args : Type] : Type read Getter write Setter; default;
- свойство может иметь аргументы/индексы, такие свойства могут быть помечены как default;
- Getter может быть методом, возвращающим значение, полем, другим свойством или выражением (заключенным в квадратные скобки);
- Setter может быть методом, полем, другим свойством или выражением (заключенным в квадратные скобки, с параметром, который может быть псевдопеременной, которая принимает значение, назначаемое свойству).
Следующая форма "property Name : Type;" объявляет свойство со скрытым полем. Поле может быть инициализировано.
Следующая форма "property Name;" может использоваться для повышения видимости свойства, например, в public из protected.
Свойства также могут иметь префикс "class", в данном случае они ограничены классовым переменными, методами и свойствами, а также могут использоваться прямо в классовом типе (в метаклассе), а не только в экземпляре класса.
Интерфейсы
Интерфейсы поддерживаются с использованием классического синтаксиса Delphi.
Интерфейсы могут определять свойства, которые являются синтаксическим сахаром для их методов.
Интерфейсы моту быть реализованы классами.
Делегаты
Указатели на функции унифицированы, нет разницы между указателями на отдельные функции и методами.
Пример допустимого кода:
type TMyFunction = function (i : Integer) : String; var v : TMyFunction; v := IntToStr; v := someObject.SomeMethod; v := somInterface.SomeMethod;
Прототип функции и метода должны совпадать.
В целях устранения неоднозначности для ссылки на функцию можно использовать оператор '@'.
Статические массивы
Статические массивы поддерживаются как значения указанного типа, массивы имеют фиксированные размеры и размерности, заданные пользователем:
type TZeroToTen = array [0..10] of Integer; type TTenToTwenty = array [10..20] of String;
Многоразмерные массивы поддерживаются в двух формах:
type TCompactForm = array [1..3, 1..5] of Float; type TVerboseForm = array [1..3] of array [1..5] of Float;
Массивы поддерживают специальные функции/методы Low, High, Length и Count. Такие функции/методы можно использовать в двух формах: Low(array) и array.Low.
Для проверки наличия элемента в массиве можно использовать операторы "in" и "not in".
Константные статические массивы могут быть определены с помощью квадратных скобок [ ]:
const a : array [0..2] of String = ['zero', 'one', 'two'];
Также массивы могут быть определены по месту, и допустимы путем присваивания к статическим или динамическим массивам:
var staticArray : array [0..2] of String; var dynamicArray : array of String; ... staticArray := ['zero', 'one', 'two']; dynamicArray := ['one', 'two'];
Константные массивы
Константные массивы ограничиваются квадратными скобками [], а не круглыми скобками(). Изменение синтаксиса было необходимо для поддержки определения встроенных статических массивов и обеспечения операторов, работающих с массивами, и будущих расширений массивов.
const a1: array [0..2] of String = ['zero', 'one', 'two']; var a2: array [0..2] of String; a2: = ['ноль', 'один', 'два'];
Динамические массивы
Динамические массивы поддерживаются как ссылочные типы, они объявляются без указания размеров. Нижняя граница массива всегда равна нулю.
В дополнение к Low, High, Length и Count, они также поддерживают следующие псевдометоды:
- Add(элемент [,...]) / Push(элемент [,...]) : увеличивает Length и добавляет один или больше элементов к концу массива, также можно добавить массив (конкатенация).
- Clear() : очищает массив (эквивалентно SetLength(0)).
- Copy(startIndex[, count]) : создает новый динамический массив , содержащий count элементов , начиная с startIndex, если count не указан, то копируется до конца массива;
- Delete(index [, count]) : удаляет элемент по указанному индексу и уменьшает Length на count (по умолчанию единица).
- IndexOf( [startIndex, ] элемент) : возвращает индекс элемента, возвращает отрицательное значение в случае неудачного поиска.
- Insert(index, элемент) : вставляет элемент по указанному индексу.
- Map([map-функция ]) : создает новый массив путем преобразования элементов массива в соответствии с map-функцией. Функция map принимает один параметр типа элемента массива и возвращает преобразованное значение.
- Peek() : возвращает последний элемент.
- Pop() : возвращает последний элемент и удаляет его из массива.
- Remove([startIndex, ] элемент) : удаляет элемент, если он будет найден, и возвращает его первоначальный индекс, если же не найдено - возвращает отрицательное значение.
- Reverse() : разворачивает порядок элементов.
- SetLength(newLength) : определяет новую длину динамического массива.
- Sort([функция сортировки]) : сортирует массив в соответствии с функцией сортировки, функция сортировки может быть опущена для массивов типов String, Integer и Float.
- Swap(index1, index2) : меняет элементы массива местами.
Для проверки наличия элемента в массиве можно использовать операторы "in" и "not in".
Динамические массивы могут быть инициализированы из inline или константных статических массивов:
var dynamicArray : array of String; ... dynamicArray := ['one', 'two', 'three'];
Перечисления
Перечисления - это простые целочисленные типы, которые могут иметь явные или автоматически назначаемые значения. Перечисления могут быть приведены к типу Integer и обратно.
Перечисления с явно заданной областью видимости поддерживаются с помощью ключевого слова enum:
type MyEnumeration = enum (First, Second, Third, Tenth = 10, Eleventh);
В таком синтаксисе элементы перечисления должны ссылаться на тип области видимости, в форме MyEnumeration.First. Если значения не указаны явно, они начинаются с 0 и увеличиваются на 1 с каждым новым членом.
Другой вариант объявления перечислений использует ключевое слово flags, в данном случае значения не могут указываться явно, они начинаются с 1 и умножаются на 2 для каждого последующего члена, например (1, 2, 4, 8 и т.д.)
type MyFlags = flags (Alpha, Beta, Gamma);
В таком синтаксисе элементы также могут быть доступны путем ссылки на область видимости как MyFlags.Beta.
Последний вариант синтаксиса соответствует классическому синтаксису перечислений Object Pascal:
type TMyEnumeration = (firstEnum, secondEnum, thirdEnum);
type TMyExplicitEnum = (eeOne = 1, eeTwo = 3, eeFive = 5);
В таком классическом синтаксисе элемент перечисления может быть доступен как автономно (eeOne), так и с префиксом типа перечисления (TMyExplicitEnum.eeOne).
Записи
Записи (record's) поддерживаются с использованием классического синтаксиса Delphi.
Также поддерживаются методы и свойства записей, включая 'class' методы.
Оператор If-then-else
Для реализации ветвлений используется оператор if-then или if-then-else. Его синтаксис:
if expression then statement [else statement]
где expression - обычно логическое выражение. Секция section необязательна.
В случае (и только в случае), когда выражение вычисляется как true, выполняется оператор, следующий после then. Если присутствует секция else, то оператор, следующий за else, выполняется в случае, когда expression равно false.
Кроме того, if-then-else может использоваться как выражение. В примере
a := if i > 0 then 42 else 7;
переменной 'a' будет присвоено значение 42 в случае, когда 'i' больше нуля. Иначе буцдет присвоено значение 7.
Циклы
Четыре вида циклов:
- for in do : цикл по элементам последовательности
- for to/downto do : цикл по переменной integer
- repeat until : цикл с финальным условием
- while do : цикл с начальным условием
Все эти виды циклов также могут управляться следующими операторами:
- break : завершает текущий цикл
- continue : переходит на следующую итерацию цикла
Замечание: операторы break и continue являются зарезервированными словами. Они - не функции, как в классическом Delphi. Это означает, что они всегда и непротиворечивым образом являются инструкциями управления циклом, и не могут быть перегружены пользовательскими функциями или переменными.
Оператор exit также завершает выполнения и цикл, и всей функции.
Оператор Exit
Оператор exit немедленно завершает выполнение функции, в которой он встретился. Может принимать необязательный параметр или операнд, который определяет возвращаемое значение для текущей функции.
Следующие три строчки эквивалентны:
exit(value);
exit value;
Result:=value; exit;
Если exit используется внутри блока try..finally, перед выходом из функции будет выполнен код в блоке finally.
Замечание: exit является оператором, а не функцией, как в классическом Delphi. Это значит, что он всегда и недвусмысленно определяет завершение, и не может быть перегружен пользовательскими функциями или переменными.
Контрактное программирование
Контрактное программирование поддерживается с синтаксисом, походим на синтаксис языка Oxygene, процедура может иметь секции "require" и "ensure", секции "ensure" также поддерживает ключевое слово "old".
Модель памяти
Гибрид Автоматический Подсчет Ссылок и Сборщик Мусора (ARC + GC)
Скриптовый движок использует комбинированную модель памяти, которая основывается на автоматическом подсчете ссылок, чтобы своевременно освобождать динамические объекты(экземпляры классов, строки, динамические массивы).
Циклы подсчета ссылок обрабатываются автоматически специальным сборщиком мусора, поэтому отсутствует необходимость в слабых ссылках.
Сборщик мусора не является основным средством управления памятью, (используется подсчет ссылок), он запускается изредка, поскольку его назначение - забота о циклах.
Ручное управление
Поддерживается вызов деструкторов объектов.
Обращение к членам разрушенных объектов вызовет гарантированное исключение и считается "безопасным", не повреждающим память.
Уничтожение объектов может использоваться для немедленного освобождения памяти больших объектов.
Директивы компиляции
- Условная компиляция: $IFDEF, $IF, $ELSE, и т.д.
- Директивы включения кода: $I, $INCLUDE_ONCE, $FILTER, и т.д.
- Директивы сообщений об ошибках и других сообщений: $HINT, $FATAL, и т.д.
- Условная компиляция: $IFDEF, $IF, $ELSE, и т.д.
- Директивы включения кода: $I, $INCLUDE_ONCE, $FILTER, и т.д.
- Директивы сообщений об ошибках и других сообщений: $HINT, $FATAL, и т.д.
Управление сообщениями
- {$WARNINGS ON|OFF} : разрешение или запрещение предупреждений компилятора.
- {$HINTS ON|OFF|NORMAL|STRICT|PEDANTIC} : управление подсказками компилятора.
- ON : разрешает подсказки, на уровне, определенном в Config.HintsLevel.
- OFF : запрещает подсказки
- NORMAL : разрешает подсказки обычного уровня
- STRICT : разрешает подсказки обычного строгого уровня
- PEDANTIC : разрешает подсказки обычного строгого уровня педант.
- {$WARNINGS ON|OFF} : разрешение или запрещение предупреждений компилятора.
- {$HINTS ON|OFF|NORMAL|STRICT|PEDANTIC} : управление подсказками компилятора.
- ON : разрешает подсказки, на уровне, определенном в Config.HintsLevel.
- OFF : запрещает подсказки
- NORMAL : разрешает подсказки обычного уровня
- STRICT : разрешает подсказки обычного строгого уровня
- PEDANTIC : разрешает подсказки обычного строгого уровня педант.
Команды сообщений
- {$HINT 'message'} : генерирует сообщение message как подсказку.
- {$WARNING 'message'} : генерирует сообщение message как предупреждение.
- {$ERROR 'message'} : генерирует сообщение message как ошибку (предотвращает выполнение).
- {$FATAL 'message'} : генерирует сообщение message как фатальную ошибку (прерывает компиляцию).
- {$HINT 'message'} : генерирует сообщение message как подсказку.
- {$WARNING 'message'} : генерирует сообщение message как предупреждение.
- {$ERROR 'message'} : генерирует сообщение message как ошибку (предотвращает выполнение).
- {$FATAL 'message'} : генерирует сообщение message как фатальную ошибку (прерывает компиляцию).
Включение исходного кода
- {$I 'filename'} : включает указанный файл в исходный код "дословно".
- {$INCLUDE 'filename'} : включает указанный файл в исходный код "дословно".
- {$INCLUDE_ONCE 'filename'} : включает указанный файл в исходный код "дословно", только если он еще не был включен ранее(напрямую или через включение).
- {$F 'filename'} : включает указанный файл в исходный код после применения к нему фильтра.
- {$FILTER 'filename'} : включает указанный файл в исходный код после применения к нему фильтра.
- {$I 'filename'} : включает указанный файл в исходный код "дословно".
- {$INCLUDE 'filename'} : включает указанный файл в исходный код "дословно".
- {$INCLUDE_ONCE 'filename'} : включает указанный файл в исходный код "дословно", только если он еще не был включен ранее(напрямую или через включение).
- {$F 'filename'} : включает указанный файл в исходный код после применения к нему фильтра.
- {$FILTER 'filename'} : включает указанный файл в исходный код после применения к нему фильтра.
Специальные включения
Можно использовать либо $I, либо $INCLUDE, они включают строковый литерал с соответствующей информацией.
- {$I %FUNCTION%} : включает строковый литерал, содержащий имя функции или метод, где размещена данная директива.
- {$I %FILE%} : включает строковый литерал, содержащий имя файла, где размещена данная директива.
- {$I %LINE%} : включает строковый литерал, содержащий номер строки, где размещена данная директива.
- {$I %DATE%} : включает строковый литерал, содержащий дату компиляции (yyyy-mm-dd).
- {$I %TIME%} : включает строковый литерал, содержащий время компиляции (hh:nn:ss).
Можно использовать либо $I, либо $INCLUDE, они включают строковый литерал с соответствующей информацией.
- {$I %FUNCTION%} : включает строковый литерал, содержащий имя функции или метод, где размещена данная директива.
- {$I %FILE%} : включает строковый литерал, содержащий имя файла, где размещена данная директива.
- {$I %LINE%} : включает строковый литерал, содержащий номер строки, где размещена данная директива.
- {$I %DATE%} : включает строковый литерал, содержащий дату компиляции (yyyy-mm-dd).
- {$I %TIME%} : включает строковый литерал, содержащий время компиляции (hh:nn:ss).
Комментариев нет:
Отправить комментарий