-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathscript.pas
More file actions
212 lines (178 loc) · 6.15 KB
/
Copy pathscript.pas
File metadata and controls
212 lines (178 loc) · 6.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
unit script;
{$mode objfpc}{$H+}
interface
uses
uPSCompiler,
uPSComponent,
uPSRuntime,
uPSUtils,
classes,
SysUtils;
type
TPascalScriptHandler = class
private
FScript : TPSScript;
FCompiled : Boolean;
FScriptLines : TStringList;
procedure scriptoncompile(sender : tpsscript);
procedure scriptonexecute(sender : tpsscript);
procedure afterexec(sender : tpsscript);
procedure CompileLoadedScript;
protected
procedure MyLocalMethod(i : integer);
public
constructor Create(aScriptString : string);
constructor CreateFromFile(afilename : string);
destructor Destroy; override;
function ExecuteStringFunction(fname : string) : string; // kinda deprecated in favour of variant version but still works
function ExecuteBooleanFunction(fname : string) : boolean; // kinda deprecated in favour of variant version but still works
function ExecuteIntegerFunction(fname : string) : Integer; // kinda deprecated in favour of variant version but still works
function ExecuteVariantFunction(fname : string) : Variant;
procedure Execute;
property Compiled : Boolean read FCompiled;
end;
var
rpm : word;
map : word;
tps : byte;
floatvalue : extended;
implementation
uses
logoutput;
procedure printfunc(aval : integer);
begin
log(inttostr(aval));
end;
constructor TPascalScriptHandler.Create(aScriptString : string);
begin
// string version of constructor. Script is contained entirely within the
// constructor parameter.
inherited Create;
FScriptLines := tstringlist.create;
FScriptLines.Add(aScriptString);
FScript := TPSScript.Create(nil);
FScript.Script := FScriptLines;
CompileLoadedScript;
end;
constructor TPascalScriptHandler.CreateFromFile(afilename : string);
begin
// file version of constructor. Script is loaded from a file given by the
// filename. Filename must contain the entire path.
inherited Create;
FScriptLines := tstringlist.create;
FScriptLines.LoadFromFile(afilename);
FScript := TPSScript.Create(nil);
FScript.Script := FScriptLines;
CompileLoadedScript;
end;
destructor TPascalScriptHandler.Destroy;
begin
FScript.Free;
FScriptLines.Free;
inherited Destroy;
end;
procedure TPascalScriptHandler.MyLocalMethod(i : integer);
begin
log('MyLocalMethod called with ' + inttostr(i) + ' as a parameter');
end;
procedure TPascalScriptHandler.CompileLoadedScript;
var
i : integer;
begin
// setup event handlers to enable transfer of globals into and out of script
// and definition of language extensions.
FScript.OnCompile:= @scriptoncompile;
FScript.OnExecute:= @scriptonexecute;
FScript.OnAfterExecute := @afterexec;
// compile the script. Report any failures to the log file.
FCompiled := True;
if not FScript.Compile then
begin
log('Failed to compile script: ' + inttostr(FScript.CompilerMessageCount) + ' errors');
for i := 0 to FScript.compilermessagecount - 1 do
log(FScript.CompilerMessages[i].MessageToString);
log(FScriptLines[0]);
FCompiled := false;
end
else
log('successfully compiled script ' + leftstr(FScriptLines[0], pos(';', FScriptLines[0])));
end;
procedure TPascalScriptHandler.scriptoncompile(sender : tpsscript);
begin
// the oncompile notification is a cue to add in variables and other definitions
// that you want the script to be able to access.
// variables (global in our app in this example)
sender.AddRegisteredVariable('rpm', 'word');
sender.AddRegisteredVariable('map', 'word');
sender.AddRegisteredVariable('tps', 'byte');
sender.AddRegisteredVariable('floatvalue', 'extended');
// these two global procedures can be called from the script
Sender.AddFunction(@printfunc, 'procedure print(aval : integer)');
sender.AddFunction(@Log,'procedure Log(str: string)');
end;
procedure TPascalScriptHandler.afterexec(sender : tpsscript);
var
i : integer;
begin
// after execution.
// grab any updated values from the script and update the globals with them.
rpm := VGetInt(Sender.GetVariable('rpm'));
map := VGetInt(Sender.GetVariable('map'));
tps := VGetInt(Sender.GetVariable('tps'));
floatvalue := VGetReal(Sender.GetVariable('floatvalue'));
end;
procedure TPascalScriptHandler.scriptonexecute(sender : tpsscript);
var
i : integer;
v : PIFVariant;
begin
// just as execution begins, grab the globals and tell the script engine what
// their current values are.
VSetInt(Sender.GetVariable('rpm'), rpm);
VSetInt(Sender.GetVariable('map'), map);
VSetInt(Sender.GetVariable('tps'), tps);
VSetReal(Sender.GetVariable('floatvalue'), floatvalue);
end;
function TPascalScriptHandler.ExecuteStringFunction(fname : string) : string;
begin
// call a function which returns a string. No support for parameters here but is is possible to add them.
if (FScript <> nil) then
Result := FScript.ExecuteFunction([], fname)
else
log('There is no script object to execute');
end;
function TPascalScriptHandler.ExecuteBooleanFunction(fname : string) : boolean;
begin
// call a function which returns a boolean. No support for parameters here but is is possible to add them.
if (FScript <> nil) then
Result := FScript.ExecuteFunction([], fname)
else
log('There is no script object to execute');
end;
function TPascalScriptHandler.ExecuteIntegerFunction(fname : string) : Integer;
begin
// call a function which returns an integer. No support for parameters here but is is possible to add them.
Result := 0;
if (FScript <> nil) then
Result := FScript.ExecuteFunction([], fname)
else
log('There is no script object to execute');
end;
function TPascalScriptHandler.ExecuteVariantFunction(fname : string) : Variant;
begin
// call a function which returns any type. No support for parameters here but is is possible to add them.
// this method replaces all of the others, although it is slightly less efficient due to
// the way variant types work.
Result := 0;
if (FScript <> nil) then
Result := FScript.ExecuteFunction([], fname)
else
log('There is no script object to execute');
end;
procedure TPascalScriptHandler.Execute;
begin
if (FScript <> nil) then
if (not FScript.Execute) then
log('Execution of script failed');
end;
end.