Compiler.ScriptCompiler.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. unit Compiler.ScriptCompiler;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2025 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. Script (=[Code]) compiler
  8. }
  9. interface
  10. uses
  11. Classes, Generics.Collections, uPSUtils;
  12. type
  13. TScriptCompilerOnLineToLineInfo = procedure(const Line: Integer; var Filename: String; var FileLine: Integer) of object;
  14. TScriptCompilerOnUsedLine = procedure(const Filename: String; const Line: Integer; const Position: Cardinal; const IsProcExit: Boolean) of object;
  15. TScriptCompilerOnUsedVariable = procedure(const Filename: String; const Line, Col, Param1, Param2, Param3: Integer; const Param4: AnsiString) of object;
  16. TScriptCompilerOnError = procedure(const Msg: String; const ErrorFilename: String; const ErrorLine: Integer) of object;
  17. TScriptCompilerOnWarning = procedure(const Msg: String) of object;
  18. TScriptCompiler = class
  19. private
  20. FExecIs64Bit: Boolean;
  21. FNamingAttribute: String;
  22. FObsoleteFunctionWarnings: TDictionary<String, String>;
  23. FExports, FUsedLines: TList;
  24. FFunctionsFound: TStringList;
  25. FScriptText: AnsiString;
  26. FOnLineToLineInfo: TScriptCompilerOnLineToLineInfo;
  27. FOnUsedLine: TScriptCompilerOnUsedLine;
  28. FOnUsedVariable: TScriptCompilerOnUsedVariable;
  29. FOnError: TScriptCompilerOnError;
  30. FOnWarning: TScriptCompilerOnWarning;
  31. function FindExport(const Name, Decl: String; const IgnoreIndex: NativeInt): NativeInt;
  32. function GetExportCount: NativeInt;
  33. procedure PSPositionToLineCol(Position: Cardinal; var Line, Col: Integer);
  34. procedure TriggerWarning(const Position: Cardinal; const WarningType, WarningMessage: String);
  35. public
  36. constructor Create;
  37. destructor Destroy; override;
  38. procedure AddExport(const Name, Decl: String; const AllowNamingAttribute, Required: Boolean; const RequiredFilename: String; const RequiredLine: Integer);
  39. function CheckExports: Boolean;
  40. function Compile(const ScriptText: String; var CompiledScriptText, CompiledScriptDebugInfo: tbtString): Boolean;
  41. property ExportCount: NativeInt read GetExportCount;
  42. function ExportFound(const Name: String): Boolean;
  43. function FunctionFound(const Name: String): Boolean;
  44. function IsObsoleteFunction(const Name: String): String;
  45. property ExecIs64Bit: Boolean write FExecIs64Bit;
  46. property NamingAttribute: String write FNamingAttribute;
  47. property OnLineToLineInfo: TScriptCompilerOnLineToLineInfo write FOnLineToLineInfo;
  48. property OnUsedLine: TScriptCompilerOnUsedLine write FOnUsedLine;
  49. property OnUsedVariable: TScriptCompilerOnUsedVariable write FOnUsedVariable;
  50. property OnError: TScriptCompilerOnError write FOnError;
  51. property OnWarning: TScriptCompilerOnWarning write FOnWarning;
  52. end;
  53. implementation
  54. uses
  55. SysUtils, Generics.Defaults,
  56. uPSCompiler, uPSC_dll,
  57. UnsignedFunc,
  58. Compiler.ScriptClasses, Compiler.ScriptFunc;
  59. type
  60. TScriptExport = class
  61. Name, Decl: String;
  62. AllowNamingAttribute: Boolean;
  63. Required: Boolean;
  64. RequiredFilename: String;
  65. RequiredLine: LongInt;
  66. Exported: Boolean;
  67. end;
  68. {---}
  69. function PSPascalCompilerOnExternalProc(Sender: TPSPascalCompiler; Decl: TPSParametersDecl; const Name, FExternal: tbtstring): TPSRegProc;
  70. var
  71. S: String;
  72. P: Integer;
  73. begin
  74. S := String(FExternal) + ' ';
  75. P := Pos(' setuponly ', S);
  76. if P > 0 then begin
  77. Delete(S, P+1, Length('setuponly '));
  78. Insert('setup:', S, Pos('@', S)+1);
  79. end
  80. else begin
  81. P := Pos(' uninstallonly ', S);
  82. if P > 0 then begin
  83. Delete(S, P+1, Length('uninstallonly '));
  84. Insert('uninstall:', S, Pos('@', S)+1);
  85. end;
  86. end;
  87. if Pos('@uninstall:files:', S) <> 0 then begin
  88. Sender.MakeError('', ecCustomError, '"uninstallonly" cannot be used with "files:"');
  89. Result := nil;
  90. Exit;
  91. end;
  92. Result := DllExternalProc(Sender, Decl, Name, tbtstring(TrimRight(S)));
  93. end;
  94. function PSPascalCompilerOnApplyAttributeToProc(Sender: TPSPascalCompiler; aProc: TPSProcedure; Attr: TPSAttribute): Boolean;
  95. var
  96. ScriptCompiler: TScriptCompiler;
  97. AttrValue: String;
  98. ScriptExport: TScriptExport;
  99. B: Boolean;
  100. begin
  101. ScriptCompiler := TScriptCompiler(Sender.ID);
  102. if CompareText(String(Attr.AType.Name), ScriptCompiler.FNamingAttribute) = 0 then begin
  103. if aProc.ClassType <> TPSInternalProcedure then begin
  104. with Sender.MakeError('', ecCustomError, tbtstring(Format('"%s" attribute cannot be used on external function or procedure', [ScriptCompiler.FNamingAttribute]))) do
  105. SetCustomPos(Attr.DeclarePos, Attr.DeclareRow, Attr.DeclareCol);
  106. Result := False;
  107. end else if Attr.Count <> 1 then begin
  108. with Sender.MakeError('', ecCustomError, tbtstring(Format('"%s" attribute value not found', [ScriptCompiler.FNamingAttribute]))) do
  109. SetCustomPos(Attr.DeclarePos, Attr.DeclareRow, Attr.DeclareCol);
  110. Result := False;
  111. end else begin
  112. if ScriptCompiler.FindExport(String(TPSInternalProcedure(aProc).Name), '', -1) <> -1 then begin
  113. { Don't allow attributes on functions already matching an export (by their name) so that we don't have to deal with this later. }
  114. with Sender.MakeError('', ecCustomError, tbtstring(Format('"%s" attribute not allowed for function or procedure "%s"', [ScriptCompiler.FNamingAttribute, String(TPSInternalProcedure(aProc).Name)]))) do
  115. SetCustomPos(Attr.DeclarePos, Attr.DeclareRow, Attr.DeclareCol);
  116. Result := False;
  117. end else begin
  118. AttrValue := String(GetString(Attr.Values[0], B));
  119. var I := ScriptCompiler.FindExport(AttrValue, String(Sender.MakeDecl(TPSInternalProcedure(aProc).Decl)), -1);
  120. if I <> -1 then begin
  121. { The name from the attribute and the function prototype are both ok. }
  122. ScriptExport := ScriptCompiler.FExports[I];
  123. if not ScriptExport.AllowNamingAttribute then begin
  124. with Sender.MakeError('', ecCustomError, tbtstring(Format('"%s" attribute value "%s" not allowed', [ScriptCompiler.FNamingAttribute, AttrValue]))) do
  125. SetCustomPos(Attr.DeclarePos, Attr.DeclareRow, Attr.DeclareCol);
  126. Result := False;
  127. end else begin
  128. ScriptExport.Exported := True;
  129. Result := True;
  130. end;
  131. end else if ScriptCompiler.FindExport(AttrValue, '', -1) <> -1 then begin
  132. { The name from the attribute is ok but the function prototype is not. }
  133. with Sender.MakeError('', ecCustomError, tbtstring(Format('Invalid function or procedure prototype for attribute value "%s"', [AttrValue]))) do
  134. SetCustomPos(TPSInternalProcedure(aProc).DeclarePos, TPSInternalProcedure(aProc).DeclareRow, TPSInternalProcedure(aProc).DeclareCol);
  135. Result := False;
  136. end else begin
  137. { The name from the attribute is not ok. }
  138. with Sender.MakeError('', ecCustomError, tbtstring(Format('"%s" attribute value "%s" invalid', [ScriptCompiler.FNamingAttribute, AttrValue]))) do
  139. SetCustomPos(Attr.DeclarePos, Attr.DeclareRow, Attr.DeclareCol);
  140. Result := False;
  141. end;
  142. end;
  143. end;
  144. end else
  145. Result := True;
  146. end;
  147. function PSPascalCompilerOnApplyAttributeToType(Sender: TPSPascalCompiler; aType: TPSType; Attr: TPSAttribute): Boolean;
  148. var
  149. NamingAttribute: String;
  150. begin
  151. NamingAttribute := TScriptCompiler(Sender.ID).FNamingAttribute;
  152. if CompareText(String(Attr.AType.Name), NamingAttribute) = 0 then begin
  153. with Sender.MakeError('', ecCustomError, tbtstring(Format('"%s" attribute cannot be used on types', [NamingAttribute]))) do
  154. SetCustomPos(Attr.DeclarePos, Attr.DeclareRow, Attr.DeclareCol);
  155. Result := False;
  156. end else
  157. Result := True;
  158. end;
  159. function PSPascalCompilerOnUses(Sender: TPSPascalCompiler; const Name: tbtstring): Boolean;
  160. var
  161. NamingAttribute: String;
  162. begin
  163. if Name = 'SYSTEM' then begin
  164. RegisterDll_Compiletime(Sender);
  165. Sender.OnExternalProc := PSPascalCompilerOnExternalProc;
  166. ScriptClassesLibraryRegister_C(Sender);
  167. const ScriptCompiler = TScriptCompiler(Sender.ID);
  168. ScriptFuncLibraryRegister_C(Sender, ScriptCompiler.FObsoleteFunctionWarnings);
  169. NamingAttribute := TScriptCompiler(Sender.ID).FNamingAttribute;
  170. if NamingAttribute <> '' then begin
  171. with Sender.AddAttributeType do begin
  172. OrgName := tbtstring(NamingAttribute);
  173. with AddField do begin
  174. FieldOrgName := 'Name';
  175. FieldType := Sender.FindType('String');
  176. end;
  177. OnApplyAttributeToProc := PSPascalCompilerOnApplyAttributeToProc;
  178. OnApplyAttributeToType := PSPascalCompilerOnApplyAttributeToType;
  179. end;
  180. end;
  181. Result := True;
  182. end else begin
  183. Sender.MakeError('', ecUnknownIdentifier, '');
  184. Result := False;
  185. end;
  186. end;
  187. function PSPascalCompilerOnExportCheck(Sender: TPSPascalCompiler; Proc: TPSInternalProcedure; const ProcDecl: tbtstring): Boolean;
  188. var
  189. ScriptCompiler: TScriptCompiler;
  190. ScriptExport: TScriptExport;
  191. begin
  192. ScriptCompiler := TScriptCompiler(Sender.ID);
  193. ScriptCompiler.FFunctionsFound.Add(String(Proc.Name));
  194. { Try and see if the function name matches an export and if so,
  195. see if one of the prototypes for that name matches. }
  196. var I := ScriptCompiler.FindExport(String(Proc.Name), String(Procdecl), -1);
  197. if I <> -1 then begin
  198. { The function name is a match and the function prototype is ok. }
  199. ScriptExport := ScriptCompiler.FExports[I];
  200. ScriptExport.Exported := True;
  201. Result := True;
  202. end else if ScriptCompiler.FindExport(String(Proc.Name), '', -1) <> -1 then begin
  203. { The function name is a match but the function prototype is not. }
  204. with Sender.MakeError('', ecCustomError, tbtstring(Format('Invalid prototype for ''%s''', [Proc.OriginalName]))) do
  205. SetCustomPos(Proc.DeclarePos, Proc.DeclareRow, Proc.DeclareCol);
  206. Result := False;
  207. end else
  208. Result := True; { The function name is not a match - this is a user function. }
  209. end;
  210. function PSPascalCompilerOnBeforeOutput(Sender: TPSPascalCompiler): Boolean;
  211. var
  212. ScriptCompiler: TScriptCompiler;
  213. ScriptExport: TScriptExport;
  214. Decl: TPSParametersDecl;
  215. Msg: String;
  216. begin
  217. ScriptCompiler := Sender.ID;
  218. Result := True;
  219. { Try and see if required but non found exports match any built in function
  220. names and if so, see if the prototypes also match }
  221. for var I := 0 to ScriptCompiler.FExports.Count-1 do begin
  222. ScriptExport := ScriptCompiler.FExports[I];
  223. if ScriptExport.Required and not ScriptExport.Exported then begin
  224. Decl := Sender.UseExternalProc(tbtstring(ScriptExport.Name));
  225. if Decl <> nil then begin
  226. if CompareText(ScriptExport.Decl, String(Sender.MakeDecl(Decl))) = 0 then
  227. ScriptExport.Exported := True
  228. else begin
  229. if Assigned(ScriptCompiler.FOnError) then begin
  230. Msg := Format('Function or procedure ''%s'' prototype is incompatible', [ScriptExport.Name]);
  231. ScriptCompiler.FOnError(Msg, ScriptExport.RequiredFilename, ScriptExport.RequiredLine);
  232. end;
  233. Result := False;
  234. end;
  235. end;
  236. end;
  237. end;
  238. end;
  239. function PSPascalCompilerOnWriteLine2(Sender: TPSPascalCompiler; Position: Cardinal; IsProcExit: Boolean): Boolean;
  240. begin
  241. const ScriptCompiler: TScriptCompiler = Sender.ID;
  242. if Assigned(ScriptCompiler.FOnUsedLine) then begin
  243. var Line, Col: Integer;
  244. ScriptCompiler.PSPositionToLineCol(Position, Line, Col);
  245. if ScriptCompiler.FUsedLines.IndexOf(Pointer(Line)) = -1 then begin
  246. ScriptCompiler.FUsedLines.Add(Pointer(Line));
  247. var Filename := '';
  248. if Assigned(ScriptCompiler.FOnLineToLineInfo) then
  249. ScriptCompiler.FOnLineToLineInfo(Line, Filename, Line);
  250. ScriptCompiler.FOnUsedLine(Filename, Line, Position, IsProcExit);
  251. Result := True;
  252. end else
  253. Result := False;
  254. end else
  255. Result := True;
  256. end;
  257. procedure PSPascalCompilerOnUseVariable(Sender: TPSPascalCompiler; VarType: TPSVariableType; VarNo: Integer; ProcNo, Position: Cardinal; const PropData: tbtstring);
  258. begin
  259. const ScriptCompiler: TScriptCompiler = Sender.ID;
  260. if Assigned(ScriptCompiler.FOnUsedVariable) then begin
  261. var Line, Col: Integer;
  262. ScriptCompiler.PSPositionToLineCol(Position, Line, Col);
  263. var Filename := '';
  264. if Assigned(ScriptCompiler.FOnLineToLineInfo) then
  265. ScriptCompiler.FOnLineToLineInfo(Line, Filename, Line);
  266. ScriptCompiler.FOnUsedVariable(Filename, Line, Col, Ord(VarType), Integer(ProcNo), VarNo, PropData);
  267. end;
  268. end;
  269. procedure PSPascalCompilerOnUseRegProc(Sender: TPSPascalCompiler; Position: Cardinal; const Name: tbtstring);
  270. var
  271. ScriptCompiler: TScriptCompiler;
  272. WarningMessage: String;
  273. begin
  274. ScriptCompiler := Sender.ID;
  275. if Assigned(ScriptCompiler.FOnWarning) then begin
  276. WarningMessage := ScriptCompiler.IsObsoleteFunction(String(Name));
  277. if WarningMessage <> '' then
  278. ScriptCompiler.TriggerWarning(Position, 'Hint', WarningMessage);
  279. end;
  280. end;
  281. {---}
  282. constructor TScriptCompiler.Create;
  283. begin
  284. FObsoleteFunctionWarnings := TDictionary<String, String>.Create(TIStringComparer.Ordinal);
  285. FExports := TList.Create();
  286. FUsedLines := TList.Create();
  287. FFunctionsFound := TStringList.Create();
  288. end;
  289. destructor TScriptCompiler.Destroy;
  290. begin
  291. FFunctionsFound.Free();
  292. FUsedLines.Free();
  293. for var I := 0 to FExports.Count-1 do
  294. TScriptExport(FExports[I]).Free();
  295. FExports.Free();
  296. FObsoleteFunctionWarnings.Free();
  297. end;
  298. procedure TScriptCompiler.PSPositionToLineCol(Position: Cardinal; var Line, Col: Integer);
  299. function FindNewLine(const S: AnsiString; const Start: Cardinal): Cardinal;
  300. begin
  301. for var I := Start to ULength(S) do
  302. if S[I] = #10 then begin
  303. Result := I - Start + 1;
  304. Exit;
  305. end;
  306. Result := 0;
  307. end;
  308. begin
  309. Inc(Position);
  310. Line := 1;
  311. var LineStartPosition: Cardinal := 1;
  312. var LineLength := FindNewLine(FScriptText, LineStartPosition);
  313. while (LineLength <> 0) and (Position > LineLength) do begin
  314. Inc(Line);
  315. Inc(LineStartPosition, LineLength);
  316. Dec(Position, LineLength);
  317. LineLength := FindNewLine(FScriptText, LineStartPosition);
  318. end;
  319. { Convert Position from the UTF8 encoded ANSI string index to a UTF-16 string index }
  320. Col := Length(UTF8ToString(Copy(FScriptText, LineStartPosition, Position - 1))) + 1;
  321. end;
  322. procedure TScriptCompiler.TriggerWarning(const Position: Cardinal; const WarningType, WarningMessage: String);
  323. begin
  324. var Line, Col: Integer;
  325. PSPositionToLineCol(Position, Line, Col);
  326. var Filename := '';
  327. if Assigned(FOnLineToLineInfo) then
  328. FOnLineToLineInfo(Line, Filename, Line);
  329. var Msg := '';
  330. if Filename <> '' then
  331. Msg := Msg + Filename + ', ';
  332. Msg := Msg + Format('Line %d, Column %d: [%s] %s', [Line, Col, WarningType, WarningMessage]);
  333. FOnWarning(Msg);
  334. end;
  335. procedure TScriptCompiler.AddExport(const Name, Decl: String; const AllowNamingAttribute, Required: Boolean; const RequiredFilename: String; const RequiredLine: LongInt);
  336. var
  337. ScriptExport: TScriptExport;
  338. begin
  339. var I := FindExport(Name, Decl, -1);
  340. if I <> -1 then begin
  341. ScriptExport := FExports[I];
  342. if Required and not ScriptExport.Required then begin
  343. ScriptExport.Required := True;
  344. ScriptExport.RequiredFilename := RequiredFilename;
  345. ScriptExport.RequiredLine := RequiredLine;
  346. end;
  347. ScriptExport.AllowNamingAttribute := ScriptExport.AllowNamingAttribute and AllowNamingAttribute;
  348. Exit;
  349. end;
  350. ScriptExport := TScriptExport.Create();
  351. ScriptExport.Name := Name;
  352. ScriptExport.Decl := Decl;
  353. ScriptExport.AllowNamingAttribute := AllowNamingAttribute;
  354. ScriptExport.Required := Required;
  355. if Required then begin
  356. ScriptExport.RequiredFilename := RequiredFilename;
  357. ScriptExport.RequiredLine := RequiredLine;
  358. end;
  359. FExports.Add(ScriptExport);
  360. end;
  361. function TScriptCompiler.FindExport(const Name, Decl: String; const IgnoreIndex: NativeInt): NativeInt;
  362. var
  363. ScriptExport: TScriptExport;
  364. begin
  365. for var I := 0 to FExports.Count-1 do begin
  366. ScriptExport := FExports[I];
  367. if ((Name = '') or (CompareText(ScriptExport.Name, Name) = 0)) and
  368. ((Decl = '') or (CompareText(ScriptExport.Decl, Decl) = 0)) and
  369. ((IgnoreIndex = -1) or (I <> IgnoreIndex)) then begin
  370. Result := I;
  371. Exit;
  372. end;
  373. end;
  374. Result := -1;
  375. end;
  376. function TScriptCompiler.CheckExports: Boolean;
  377. var
  378. ScriptExport: TScriptExport;
  379. Msg: String;
  380. begin
  381. Result := True;
  382. for var I := 0 to FExports.Count-1 do begin
  383. ScriptExport := FExports[I];
  384. if ScriptExport.Required and not ScriptExport.Exported then begin
  385. if Assigned(FOnError) then begin
  386. { Either the function wasn't present or it was present but matched another export }
  387. if FindExport(ScriptExport.Name, '', I) <> -1 then
  388. Msg := Format('Required function or procedure ''%s'' found but not with a compatible prototype', [ScriptExport.Name])
  389. else
  390. Msg := Format('Required function or procedure ''%s'' not found', [ScriptExport.Name]);
  391. FOnError(Msg, ScriptExport.RequiredFilename, ScriptExport.RequiredLine);
  392. end;
  393. Result := False;
  394. Exit;
  395. end;
  396. end;
  397. end;
  398. function TScriptCompiler.Compile(const ScriptText: String; var CompiledScriptText, CompiledScriptDebugInfo: tbtString): Boolean;
  399. var
  400. PSPascalCompiler: TPSPascalCompiler;
  401. L, Line, Col: LongInt;
  402. Filename, Msg: String;
  403. begin
  404. Result := False;
  405. FScriptText := Utf8Encode(ScriptText);
  406. for var I := 0 to FExports.Count-1 do
  407. TScriptExport(FExports[I]).Exported := False;
  408. FFunctionsFound.Clear;
  409. PSPascalCompiler := TPSPascalCompiler.Create();
  410. try
  411. PSPascalCompiler.ID := Self;
  412. PSPascalCompiler.AllowNoBegin := True;
  413. PSPascalCompiler.AllowNoEnd := True;
  414. PSPascalCompiler.BooleanShortCircuit := True;
  415. PSPascalCompiler.AllowDuplicateRegister := False;
  416. PSPascalCompiler.UTF8Decode := True;
  417. PSPascalCompiler.AttributesOpenTokenID := CSTI_Less;
  418. PSPascalCompiler.AttributesCloseTokenID := CSTI_Greater;
  419. PSPascalCompiler.ExecIs64Bit := FExecIs64Bit;
  420. PSPascalCompiler.OnUses := PSPascalCompilerOnUses;
  421. PSPascalCompiler.OnExportCheck := PSPascalCompilerOnExportCheck;
  422. PSPascalCompiler.OnBeforeOutput := PSPascalCompilerOnBeforeOutput;
  423. DefaultCC := ClStdCall;
  424. FUsedLines.Clear();
  425. PSPascalCompiler.OnWriteLine2 := PSPascalCompilerOnWriteLine2;
  426. PSPascalCompiler.OnUseVariable := PSPascalCompilerOnUseVariable;
  427. PSPascalCompiler.OnUseRegProc := PSPascalCompilerOnUseRegProc;
  428. if not PSPascalCompiler.Compile(FScriptText) then begin
  429. if Assigned(FOnError) then begin
  430. for L := 0 to PSPascalCompiler.MsgCount-1 do begin
  431. if PSPascalCompiler.Msg[L] is TPSPascalCompilerError then begin
  432. PSPositionToLineCol(PSPascalCompiler.Msg[L].Pos, Line, Col);
  433. Filename := '';
  434. if Assigned(FOnLineToLineInfo) then
  435. FOnLineToLineInfo(Line, Filename, Line);
  436. Msg := Format('Column %d:'#13#10'%s', [Col, PSPascalCompiler.Msg[L].ShortMessageToString]);
  437. FOnError(Msg, Filename, Line);
  438. Break;
  439. end;
  440. end;
  441. end;
  442. Exit;
  443. end else begin
  444. if not CheckExports() then
  445. Exit;
  446. if not PSPascalCompiler.GetOutput(CompiledScriptText) then begin
  447. if Assigned(FOnError) then begin
  448. Msg := 'GetOutput failed';
  449. FOnError(Msg, '', 0);
  450. end;
  451. Exit;
  452. end;
  453. if not PSPascalCompiler.GetDebugOutput(CompiledScriptDebugInfo) then begin
  454. if Assigned(FOnError) then begin
  455. Msg := 'GetDebugOutput failed';
  456. FOnError(Msg, '', 0);
  457. end;
  458. Exit;
  459. end;
  460. if Assigned(FOnWarning) then
  461. for L := 0 to PSPascalCompiler.MsgCount-1 do
  462. TriggerWarning(PSPascalCompiler.Msg[L].Pos,
  463. String(PSPascalCompiler.Msg[L].ErrorType),
  464. String(PSPascalCompiler.Msg[L].ShortMessageToString));
  465. end;
  466. Result := True;
  467. finally
  468. PSPascalCompiler.Free();
  469. end;
  470. end;
  471. function TScriptCompiler.ExportFound(const Name: String): Boolean;
  472. var
  473. ScriptExport: TScriptExport;
  474. begin
  475. for var I := 0 to FExports.Count-1 do begin
  476. ScriptExport := FExports[I];
  477. if CompareText(ScriptExport.Name, Name) = 0 then begin
  478. Result := ScriptExport.Exported;
  479. Exit;
  480. end;
  481. end;
  482. Result := False;
  483. end;
  484. function TScriptCompiler.FunctionFound(const Name: String): Boolean;
  485. var
  486. I: Integer;
  487. begin
  488. Result := False;
  489. for I := 0 to FFunctionsFound.Count-1 do begin
  490. if CompareText(FFunctionsFound[I], Name) = 0 then begin
  491. Result := True;
  492. Break;
  493. end;
  494. end;
  495. end;
  496. function TScriptCompiler.GetExportCount: NativeInt;
  497. begin
  498. Result := FExports.Count;
  499. end;
  500. function TScriptCompiler.IsObsoleteFunction(const Name: String): String;
  501. begin
  502. FObsoleteFunctionWarnings.TryGetValue(Name, Result);
  503. end;
  504. end.