Использование RemObjects Pascal Script

(Эта статья является моим вольным переводом статьи PS01 - Using the RemObjects Pascal Script с сайта RemObjects Software. Внесены незначительные исправления в текст и добавлены примеры - Снег Север).

В этой статье сделан обзор пакета компонентов RemObjects Pascal Script и объясняется, как сделать и исполнить некоторые простые скрипты.

Концептуально Pascal Script состоит из двух различных частей:

  • Компилятора (uPSCompiler.pas)
  • Модуля времени выполнения (uPSRuntime.pas)

Эти две части независимы друг от друга. Вы можете использовать их непосредственно или использовать компонент TPSScript, который находится в модуле uPSComponent.pas и объединяет их в одном удобном для применения классе.

Для применения компонентной версии Pascal Script вы должны поместить его на вашу форму или модуль баз данных, настроить (назначить) свойство Script, вызвать метод Compile, а затем вызвать метод Execute. Сообщения об ошибках и предупреждениях компилятора можно найти в индексированном свойстве CompilerMessages, ошибки времени выполнения можно узнать, прочитав свойство ExecErrorToString.

Следующий пример компилирует и выполняет пустой скрипт ("begin end."):

var

  Messages: string;

  compiled: boolean;

begin

  ce.Script.Text := 'begin end.';

  Compiled := Ce.Compile;

  for i := 0 to ce.CompilerMessageCount -1 do

    Messages := Messages +

                ce.CompilerMessages[i].MessageToString +

                #13#10;

  if Compiled then

    Messages := Messages + 'Succesfully compiled'#13#10;

  ShowMessage('Compiled Script: '#13#10+Messages);

  if Compiled then begin

    if Ce.Execute then

      ShowMessage('Succesfully Executed')

    else

      ShowMessage('Error while executing script: '+

                  Ce.ExecErrorToString);

  end;

end;

 (sample00)

 

По умолчанию компонент добавляет только несколько стандартных функций к скриптовому движку (их перечень можно увидеть в начале модуля uPSComponents.pas).

В дополнение к стандартным функциям, имеется несколько библиотек, включенных в Pascal Script:

TPSDllPlugin

Позволяет скрипту использовать функции dll, примерный синтаксис вызова:
function FindWindow(C1, C2: PChar): Longint; external 'FindWindowA@user32.dll stdcall';

TPSImport_Classes

Библиотека импорта классов для TObject и модуля Classes.

TPSImport_DateUtils

Библиотека импорта функций даты и времени.

TPSImport_ComObj

Доступ к COM-объектам в ваших скриптах.

TPSImport_DB

Библиотека импорта для db.pas.

TPSImport_Forms

Библиотека импорта для Forms & Menus.

TPSImport_Controls

Библиотека импорта для Controls.pas и Graphics.pas.

TPSImport_StdCtrls

Библиотека импорта для ExtCtrls и Buttons.

Для использования этих библиотек, положите их на форму (модуль баз данных), в свойстве Plugins компонента TPSCompiler нажмите кнопку [...], добавьте новый элемент и назначьте свойство Plugin соответствующему компоненту. В дополнение к стандартным библиотекам вы можете легко добавлять новую функциональность к скриптовому движку. Для этого создайте новый метод, который вы желаете добавить к скриптовому движку, например:

procedure TForm1.ShowNewMessage(const Message: string);

begin

  ShowMessage('ShowNewMessage invoked:'#13#10+Message);

end;

Затем назначьте обработчик для события OnCompile event и используйте метод AddMethod компонента TPSCompiler чтобы добавить новый метод:

procedure TForm1.CECompile(Sender: TPSScript);

begin

  Sender.AddMethod(Self, @TForm1.ShowNewMessage,

                   'procedure ShowNewMessage(const Message: string);');

end;

Пример скрипта, который использует эту функцию, может выглядеть так:

begin

  ShowNewMessage('Show This !');

end.

(sample01)

 

Расширенная функциональность

Pascal Script включает в себя препроцессор, который позволяет вам использовать команды препроцессора (defines) ({$IFDEF}, {$ELSE}, {$ENDIF}) и включать другие файлы в ваш скрипт ({$I filename.inc}). Для включения этой возможности, поставьте свойству UsePreprocessor значение «true» и свойству MainFileName – имя скрипта из свойства Script. Свойство Defines устанавливает значения по умолчанию, а событие OnNeedFile вызывается, когда необходим включаемый файл.   

function TForm1.ceNeedFile(Sender: TObject;

  const OrginFileName: String;

  var FileName, Output: String): Boolean;

var

  path: string;

  f: TFileStream;

begin

  Path := ExtractFilePath(ParamStr(0)) + FileName;

  try

    F := TFileStream.Create(Path, fmOpenRead or fmShareDenyWrite);

  except

    Result := false;

    exit;

  end;

  try

    SetLength(Output, f.Size);

    f.Read(Output[1], Length(Output));

  finally

  f.Free;

  end;

  Result := True;

end;

 (sample02)

Когда эти свойства установлены, свойство-массив CompilerMessages будет включать имя файла, в котором эти сообщения инициируются.

 

Дополнительно вы можете вызывать скриптовые функции в Delphi. Следующий пример используется как скрипт:

function TestFunction(Param1: Double; Data: String): Longint;

begin

  ShowNewMessage('Param1: '+FloatToStr(param1)

                 +#13#10+'Data: '+Data);

  Result := 1234567;

end;

 

begin

end.

Перед тем, как эта скриптовая функция может быть вызвана, нужно проверить типы ее параметров и результата, что можно сделать в событии OnVerifyProc.

procedure TForm1.CEVerifyProc(Sender: TPSScript;

                              Proc: TPSInternalProcedure;

                              const Decl: String;

                              var Error: Boolean);

begin

  if Proc.Name = 'TESTFUNCTION' then begin

    if not ExportCheck(Sender.Comp, Proc,

               [btS32, btDouble, btString], [pmIn, pmIn]) then begin

      Sender.Comp.MakeError('', ecCustomError, 'Function header for TestFunction does not match.');

      Error := True;

    end

    else begin

      Error := False;

    end;

  end

  else

    Error := False;

end;

Функция ExportCheck проверяет соответствие параметров. В этом случае, btu8 это boolean (тип результата), btdouble – первый параметр и btString – второй параметр. [pmIn, pmIn] указывают, что оба параметра это IN (входные) параметры. Для вызова этой скриптовой функции, вам необходимо декларировать событие для этой функции и вызвать его.

type

  TTestFunction = function (Param1: Double;

                            Data: String): Longint of object;

//...

var

  Meth: TTestFunction;

...

  Meth := TTestFunction(ce.GetProcMethod('TESTFUNCTION'));

  if @Meth = nil then

    raise Exception.Create('Unable to call TestFunction');

  ShowMessage('Result: '+IntToStr(Meth(pi, DateTimeToStr(Now))));

 (sample03)

 

Можно также добавлять переменные в скриптовый движок и затем использовать их в скриптах. Для этого необходимо применить функцию AddRegisteredVariable. Это можно сделать в событии OnCompile:

procedure TForm1.CECompile(Sender: TPSScript);

begin

  ce.AddRegisteredVariable('MYVAR', 'Longint');

end;

Значение этой переменной можно дать в событии OnExecute:

procedure TForm1.ceExecute(Sender: TPSScript);

begin

  VSetInt(CE.GetVariable('MYVAR'), 1234567);

end;

 

Для того, чтобы узнать значение этой переменной после выполнения скрипта, вы можете использовать событие OnAfterExecute:

VGetInt(CE.GetVariable('MYVAR'))

Можно также зарегистрировать внешние переменные для скрипта. Этот процесс состоит из двух шагов – во-первых, в событии OnCompile добавляются переменные и их типы с помощь функции AddRegisteredPTRVariable.

procedure TMyForm.CECompile(Sender: TPSScript);

begin

  Sender.AddRegisteredPTRVariable('Memo2', 'TMemo');

  Sender.AddRegisteredPTRVariable('MyVar1', 'Longint');

end;

Это зарегистрирует переменные MyClass и MyVar. Во-вторых, назначим ссылки на эти переменные в событии OnExecute:

procedure TMyForm.CEExecute(Sender: TPSScript);

begin

  CE.SetPointerToData('MyVar1', @MyVar1, CE.FindBaseType(bts32));

  CE.SetPointerToData('Memo2', @Memo2, CE.FindNamedType('TMemo'));

end;

Вам также надо добавить и  зарегистрировать в компиляторе компоненты TPSImport_Classes, TPSImport_Controls и TPSImport_StdCtrls.

(sample04)

 

В Pascal Script есть два вида типов переменных – базовые типы, которые являются простыми типами (см. Таблицу ниже) и классовые типы. Базовые типы регистрируются модулем uPSUtils.pas и могут быть найдены с помощью функции FindBaseType. Классовые типы находят по имени, используя FindNamedType. Изменения в этих переменных непосредственно изменяет актуальную переменную.

Базовые типы:

btU8

Byte

btS8

Shortint

btU16

Word

btS16

Smallint

btU32

Longword

btS32

Longint

btS64

Int64

btSingle

Single

btDouble

Double

btExtended

Extended

btVariant

Variant

btString

String

btWideString

WideString

btChar

Char

btWideChar

WideChar

Компонентная версия Pascal Script также поддерживает выполнение скриптовых функций. Это делается с помощью метода ExecuteFunction.

ShowMessage(CE.ExecuteFunction([1234.5678, 4321,

                                      'test'],

                                     'TestFunction'));

Это выполнит функцию с именем 'TestFunction' с 3-мя параметрами - float, integer и string. Результат будет отправлен обратно в ShowMessage.

(sample05)

Замечания:

  • Для некоторых функций и констант может понадобиться добавить uPSCompiler.pas, uPSRuntime.pas и/или uPSUtils.pas в секцию uses вашего модуля.
  • Скриптовый движок никогда не вызывает непосредственно Application.ProcessMessages, и это может «подвесить» ваше приложение. Чтобы избежать этого, добавьте Application.ProcessMessages в событие TPSScript.OnLine.
  • Можно импортировать свои собственные классы в скриптовый движок. Pascal Script включает инструмент для создания библиотек импорта в директории \Bin.
  • Для примеров использования компилятора и модуля времени выполнения раздельно, смотрите примеры из групп Import и Kylix.
  • Пример Debug требует SynEdit http://synedit.sourceforge.net/.
Вернуться к списку статей Вернуться на главную страницу SourceForge.net Logo