I would implement the Delphi side a bit differently (see below), but apart from that your solution appears correct.
The quirk, as you've correctly observed, is that DWScript represents static sets as arrays. Note however that this is just a limitation of the compiler frontend which hopefully, someday, will be resolved. See DWScript issue #10: Improve implicit casts from static arrays to sets.
The following script demonstrates in which cases the compiler performs an implicit cast between set and array:
type
TMyEnum = (meOne, meTwo);
type
TMySet = set of TMyEnum;
type
TMyArray = array of TMyEnum;
procedure TestSet(MySet: TMySet);
begin
ShowMessage(integer(MySet).toString);
end;
procedure TestArray(MyArray: TMyArray);
var
MySet: TMySet;
begin
MySet := [];
for var i := 0 to MyArray.Length-1 do
Include(MySet, MyArray[i]);
ShowMessage(integer(MySet).toString);
end;
begin
TestSet([]);
TestArray([]);
TestSet([meOne]);
TestArray([meOne]);
TestSet([meOne, meTwo]);
TestArray([meOne, meTwo]);
var VarSet: TMySet = [meOne, meTwo];
TestSet(VarSet);
// Syntax Error: Argument 0 expects type "array of TMyEnum" instead of "TMySet"
// TestArray(VarSet);
var VarArray: TMyArray = [meOne, meTwo];
TestArray(VarArray);
// Syntax Error: Argument 0 expects type "array of TMyEnum" instead of "TMySet"
// TestArray(VarSet);
// Syntax Error: Incompatible types: "TMySet" and "array [0..1] of TMyEnum" const ConstSet: TMySet = [meOne, meTwo];
// const ConstSet: TMySet = [meOne, meTwo];
// TestSet(ConstSet);
// TestArray(ConstSet);
// Syntax Error: Incompatible types: "array of TMyEnum" and "array [0..1] of TMyEnum"
// const ConstArray: TMyArray = [meOne, meTwo];
// TestSet(ConstArray);
// TestArray(ConstArray);
end;
The above is purely a script side implementation. When you add a Delphi side implementation into the mix it can get problematic.
Consider a simplified implementation of the MessageDlg
function:
Delphi side declaration (via TdwsUnit):
type
TMsgDlgBtn = (mbYes, mbNo, mbOK, mbCancel, etc...);
TMsgDlgButtons = set of TMsgDlgBtn;
function MessageDlg(const Msg: string; Buttons: TMsgDlgButtons): integer;
Delphi side implementation:
Info.ResultAsInteger := MessageDlg(Info.ParamAsString[0], mtInformation, TMsgDlgButtons(Word(Info.ParamAsInteger[1])), -1);
Script side usage:
begin
// Implicit cast from array to set fails:
// Syntax Error: There is no overloaded version of "MessageDlg" that can be called with these arguments
// MessageDlg('Test', [mbOK]);
var Buttons: TMsgDlgButtons = [mbOK];
MessageDlg('Test', Buttons);
end;
Now lets try the same with your solution declaring the set parameter as an array instead:
Delphi side declaration (via TdwsUnit):
type
TMsgDlgBtn = (mbYes, mbNo, mbOK, mbCancel, etc...);
TMsgDlgButtons = array of TMsgDlgBtn;
function MessageDlg(const Msg: string; Buttons: TMsgDlgButtons): integer;
Delphi side implementation:
var
Buttons: TMsgDlgButtons;
i: integer;
ButtonArray: IScriptDynArray;
begin
ButtonArray := Info.Params[1].ScriptDynArray;
Buttons := [];
for i := 0 to ButtonArray.ArrayLength-1 do
Include(Buttons, TMsgDlgBtn(ButtonArray.AsInteger[i]));
Info.ResultAsInteger := MessageDlgEx(Info.ParamAsString[0], mtInformation, Buttons, -1);
end;
Script side usage:
begin
MessageDlg('Test', [mbOK]);
var Buttons: TMsgDlgButtons = [mbOK];
// Note that an implicit cast from set to array is performed
MessageDlg('Test', Buttons);
end;
In my own branch of DWScript I've modified the compiler to perform an implicit cast from an array of enum values to a set: DWScript pull request #4: Enhancement to set type. This works beautifully and resolves all the cases above that otherwise fail.