Compiler.ScriptCompiler.pas 21 KB

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