ISPP.IdentMan.pas 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112
  1. {
  2. Inno Setup Preprocessor
  3. Copyright (C) 2001-2002 Alex Yackimoff
  4. Inno Setup
  5. Copyright (C) 1997-2025 Jordan Russell
  6. Portions by Martijn Laan
  7. For conditions of distribution and use, see LICENSE.TXT.
  8. }
  9. unit ISPP.IdentMan;
  10. interface
  11. uses
  12. SysUtils, Classes, ISPP.Intf, ISPP.Base;
  13. type
  14. EIdentError = class(Exception);
  15. EMacroError = class(EIdentError);
  16. TIdentManager = class;
  17. PIdent = ^TIdent;
  18. TIdent = object
  19. Name: string;
  20. Hash: Integer;
  21. IdentType: TIdentType;
  22. end;
  23. PDefinable = ^TDefinable;
  24. TDefinable = object(TIdent)
  25. Scope: record
  26. LocalLevel: Integer; // 0 means public
  27. IsProtected: Boolean; // False means private, not used if Locality = 0
  28. end;
  29. end;
  30. PVariable = ^TVariable;
  31. TVariable = object(TDefinable)
  32. Dim: Integer;
  33. Value: array[0..0] of TIsppVariant;
  34. end;
  35. TExprPosition = record
  36. FileIndex, Line, Column: Integer;
  37. end;
  38. PMacro = ^TMacro;
  39. TMacro = object(TDefinable)
  40. Expression: string;
  41. DeclPos: TExprPosition;
  42. ParserOptions: TIsppParserOptions;
  43. ParamCount: Integer;
  44. Params: array[0..0] of TIsppMacroParam;
  45. end;
  46. PFunc = ^TFunc;
  47. TFunc = object(TIdent)
  48. Code: TIsppFunction;
  49. Ext: NativeInt;
  50. end;
  51. PActualParams = ^TActualParams;
  52. TActualParams = array of TVariable;
  53. IInternalFuncParams = interface(IIsppFuncParams)
  54. function Get(Index: Integer): PIsppVariant;
  55. function ResPtr: PIsppVariant;
  56. end;
  57. TDefineScope = (dsAny, dsPublic, dsProtected, dsPrivate); // order matters
  58. TIdentManager = class(TObject, IIdentManager)
  59. private
  60. FCustomIdents: IIdentManager;
  61. FFuncSender: NativeInt;
  62. FRefCount: Integer;
  63. FVarMan: TList;
  64. FLocalLevel: Integer;
  65. function FindIndex(const Name: string; AScope: TDefineScope): Integer;
  66. function Find(const Name: string; AScope: TDefineScope): PIdent;
  67. procedure FreeItem(Item: Pointer);
  68. function MacroIdents: IIdentManager;
  69. protected
  70. function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
  71. public
  72. constructor Create(const CustomIdents: IIdentManager; FuncSender: NativeInt);
  73. destructor Destroy; override;
  74. function _AddRef: Integer; stdcall;
  75. function _Release: Integer; stdcall;
  76. procedure BeginLocal;
  77. procedure EndLocal;
  78. function Defined(const Name: string): Boolean;
  79. procedure DefineFunction(const Name: string; Handler: TIsppFunction;
  80. Ext: NativeInt);
  81. procedure DefineMacro(const Name, Expression: string; ExprPos: TExprPosition;
  82. const ParserOptions: TIsppParserOptions; Params: array of TIsppMacroParam;
  83. Scope: TDefineScope);
  84. procedure DefineVariable(const Name: string; Index: Integer;
  85. const Value: TIsppVariant; Scope: TDefineScope);
  86. procedure Delete(const Name: string; Scope: TDefineScope);
  87. procedure DimVariable(const Name: string; Length: Integer; Scope: TDefineScope; var ReDim: Boolean);
  88. function GetIdent(const Name: string; out CallContext: ICallContext): TIdentType;
  89. function TypeOf(const Name: string): Byte;
  90. function DimOf(const Name: String): Integer;
  91. end;
  92. const
  93. TYPE_ERROR = 0;
  94. TYPE_NULL = 1;
  95. TYPE_INTEGER = 2;
  96. TYPE_STRING = 3;
  97. TYPE_MACRO = 4;
  98. TYPE_FUNC = 5;
  99. TYPE_ARRAY = 6;
  100. implementation
  101. uses
  102. Windows, Types, ISPP.Preprocessor, ISPP.CTokenizer, ISPP.Parser,
  103. ISPP.VarUtils, ISPP.Consts, ISPP.Sessions;
  104. const
  105. MaxLocalArraySize = 16;
  106. GL: array[TDefineScope] of string = ('Public', 'Public', 'Protected', 'Private');
  107. function MakeHash(const S: string): Integer;
  108. begin
  109. Result := 0;
  110. for var I := 1 to Length(S) do
  111. Result := ((Result shl 7) or (Result shr 25)) + Ord(UpCase(S[I]));
  112. end;
  113. { TCallContext }
  114. type
  115. TCallContext = class(TInterfacedObject)
  116. private
  117. procedure ErrorDefined(const ArgName: string);
  118. procedure ErrorNotSpecified(const ArgName: string);
  119. procedure ErrorTooMany;
  120. procedure ErrorTooFew;
  121. procedure ErrorWrongType(const ArgName: string);
  122. protected
  123. function GroupingStyle: TArgGroupingStyle;
  124. end;
  125. procedure TCallContext.ErrorDefined(const ArgName: string);
  126. begin
  127. raise EIdentError.CreateFmt(SParamSpecifiedTwice, [ArgName])
  128. end;
  129. procedure TCallContext.ErrorNotSpecified(const ArgName: string);
  130. begin
  131. raise EIdentError.CreateFmt(SRequiredParamMissing, [ArgName])
  132. end;
  133. procedure TCallContext.ErrorTooMany;
  134. begin
  135. raise EIdentError.Create(STooManyActualParams);
  136. end;
  137. procedure TCallContext.ErrorTooFew;
  138. begin
  139. raise EIdentError.Create(SInsufficientParams)
  140. end;
  141. procedure TCallContext.ErrorWrongType(const ArgName: string);
  142. begin
  143. raise EIdentError.CreateFmt(SWrongParamType, [ArgName])
  144. end;
  145. function TCallContext.GroupingStyle: TArgGroupingStyle;
  146. begin
  147. Result := agsParenteses;
  148. end;
  149. { TVarCallContext }
  150. type
  151. TVarCallContext = class(TCallContext, ICallContext)
  152. private
  153. FVariable: PVariable;
  154. FIndex: Integer;
  155. protected
  156. constructor Create(Variable: PVariable);
  157. { ICallContext }
  158. procedure Add(const Name: string; const Value: TIsppVariant);
  159. function Call: TIsppVariant;
  160. function GroupingStyle: TArgGroupingStyle;
  161. procedure Clone(out NewContext: ICallContext);
  162. end;
  163. constructor TVarCallContext.Create(Variable: PVariable);
  164. begin
  165. FVariable := Variable;
  166. FIndex := -1;
  167. end;
  168. procedure TVarCallContext.Add(const Name: string;
  169. const Value: TIsppVariant);
  170. begin
  171. if FVariable.Dim <> 0 then
  172. begin
  173. if (Name = '') or (CompareText(Name, 'INDEX') = 0) then
  174. begin
  175. if FIndex <> -1 then ErrorDefined('Index');
  176. try
  177. FIndex := ToInt(Value).AsInteger;
  178. except on E: Exception do
  179. raise EIdentError(E.Message);
  180. end;
  181. end
  182. else
  183. raise EIdentError.CreateFmt(SUnknownParam, [Name]);
  184. if (FIndex < 0) or (FIndex >= FVariable.Dim) then
  185. raise EIdentError.CreateFmt(SIndexIsOutOfArraySize, [FIndex, FVariable.Name]);
  186. end
  187. else
  188. raise EIdentError.Create(SParameterlessVariable);
  189. end;
  190. function TVarCallContext.Call: TIsppVariant;
  191. begin
  192. if FIndex < 0 then
  193. if FVariable.Dim <> 0 then
  194. raise EIdentError.CreateFmt(SIndexNotSpecifiedForArray, [FVariable.Name])
  195. else
  196. FIndex := 0;
  197. Result.Typ := evLValue;
  198. Result.AsPtr := @(FVariable^.Value[FIndex]);
  199. SimplifyLValue(Result);
  200. end;
  201. function TVarCallContext.GroupingStyle: TArgGroupingStyle;
  202. begin
  203. if FVariable.Dim <> 0 then
  204. Result := agsBrackets
  205. else
  206. Result := agsNone
  207. end;
  208. { TMacroCallContext }
  209. var
  210. MacroStack: TStrings;
  211. procedure PushMacro(const Name: string);
  212. begin
  213. if MacroStack = nil then
  214. MacroStack := TStringList.Create
  215. else ;
  216. {if MacroStack.IndexOf(UpperCase(Name)) >= 0 then
  217. raise EMacroError.CreateFmt(SRecursiveMacroCall, [Name]);}
  218. MacroStack.Add(UpperCase(Name));
  219. end;
  220. procedure PopMacro;
  221. begin
  222. MacroStack.Delete(MacroStack.Count - 1);
  223. if MacroStack.Count = 0 then
  224. begin
  225. MacroStack.Free;
  226. MacroStack := nil
  227. end;
  228. end;
  229. type
  230. { TMacroLocalArrayCallContext }
  231. TMacroCallContext = class;
  232. TMacroLocalArrayCallContext = class(TCallContext, ICallContext)
  233. private
  234. FMacroContext: TMacroCallContext;
  235. FIndex: Integer;
  236. public
  237. constructor Create(MacroContext: TMacroCallContext);
  238. procedure Add(const Name: String; const Value: TIsppVariant);
  239. function Call: TIsppVariant;
  240. function GroupingStyle: TArgGroupingStyle;
  241. procedure Clone(out NewContext: ICallContext);
  242. end;
  243. { TMacroCallContext }
  244. TMacroArgument = record
  245. Value: TVariable;
  246. Defined: Boolean;
  247. end;
  248. PMacroArgArray = ^TMacroArgArray;
  249. TMacroArgArray = array[0..0] of TMacroArgument;
  250. TMacroCallContext = class(TCallContext, ICallContext, IIdentManager)
  251. private
  252. FIdentManager: IIdentManager;
  253. FMacro: PMacro;
  254. FList: PMacroArgArray;
  255. FCurrentParam: Integer;
  256. FLocalVars: TList;
  257. procedure AdjustLocalArray(Index: Integer);
  258. function FindFormalParam(const Name: string): Integer;
  259. protected
  260. constructor Create(const IdentManager: IIdentManager; Macro: PMacro);
  261. destructor Destroy; override;
  262. { IIdentManager}
  263. function GetIdent(const Name: string; out CallContext: ICallContext): TIdentType;
  264. function Defined(const Name: string): Boolean;
  265. function TypeOf(const Name: string): Byte;
  266. function DimOf(const Name: string): Integer;
  267. { ICallContext }
  268. procedure Add(const Name: string; const Value: TIsppVariant);
  269. function Call: TIsppVariant;
  270. procedure Clone(out NewContext: ICallContext);
  271. end;
  272. constructor TMacroLocalArrayCallContext.Create(MacroContext: TMacroCallContext);
  273. begin
  274. FMacroContext := MacroContext;
  275. FIndex := -1;
  276. end;
  277. procedure TMacroLocalArrayCallContext.Add(const Name: String;
  278. const Value: TIsppVariant);
  279. begin
  280. if (Name = '') or (CompareText(Name, 'INDEX') = 0) then
  281. begin
  282. if FIndex <> -1 then ErrorDefined('Index');
  283. try
  284. FIndex := ToInt(Value).AsInteger;
  285. except on E: Exception do
  286. raise EIdentError.Create(E.Message);
  287. end;
  288. end
  289. else
  290. raise EIdentError.CreateFmt(SUnknownParam, [Name]);
  291. if (FIndex < 0) or (FIndex >= MaxLocalArraySize) then
  292. raise EIdentError.Create(SLocalArraysIndexError);
  293. end;
  294. function TMacroLocalArrayCallContext.Call: TIsppVariant;
  295. begin
  296. if FIndex = -1 then FIndex := 0;
  297. FMacroContext.AdjustLocalArray(FIndex);
  298. Result.Typ := evLValue;
  299. Result.AsPtr := FMacroContext.FLocalVars[FIndex];
  300. end;
  301. function TMacroLocalArrayCallContext.GroupingStyle: TArgGroupingStyle;
  302. begin
  303. Result := agsBrackets;
  304. end;
  305. constructor TMacroCallContext.Create(const IdentManager: IIdentManager;
  306. Macro: PMacro);
  307. begin
  308. FIdentManager := IdentManager;
  309. FMacro := Macro;
  310. FList := AllocMem(SizeOf(TMacroArgument) * Macro^.ParamCount);
  311. end;
  312. destructor TMacroCallContext.Destroy;
  313. var
  314. I: Integer;
  315. begin
  316. if Assigned(FLocalVars) then
  317. begin
  318. for I := 0 to FLocalVars.Count - 1 do
  319. Dispose(PIsppVariant(FLocalVars[I]));
  320. FLocalVars.Free;
  321. end;
  322. FreeMem(FList)
  323. end;
  324. procedure TMacroCallContext.Add(const Name: string;
  325. const Value: TIsppVariant);
  326. var
  327. ParamIndex: Integer;
  328. begin
  329. if Name <> '' then
  330. ParamIndex := FindFormalParam(Name)
  331. else
  332. ParamIndex := FCurrentParam;
  333. if ParamIndex >= FMacro.ParamCount then
  334. ErrorTooMany;
  335. if FList[ParamIndex].Defined then
  336. ErrorDefined(FMacro.Params[ParamIndex].Name);
  337. if Value.Typ = evSpecial then //parser is in "skip" state
  338. else
  339. if Value.Typ = evNull then
  340. if pfHasDefault in FMacro.Params[ParamIndex].ParamFlags then
  341. FList[ParamIndex].Value.Value[0] := FMacro.Params[ParamIndex].DefValue
  342. else
  343. ErrorNotSpecified(FMacro.Params[ParamIndex].Name)
  344. else
  345. if (pfByRef in FMacro.Params[ParamIndex].ParamFlags) and
  346. (Value.Typ <> evLValue) then
  347. raise EIdentError.CreateFmt(SLValueRequiredForByRefParam, [FMacro.Params[ParamIndex].Name])
  348. else
  349. if (pfTypeDefined in FMacro.Params[ParamIndex].ParamFlags) and
  350. (GetRValue(Value).Typ <> FMacro.Params[ParamIndex].DefValue.Typ) then
  351. ErrorWrongType(FMacro.Params[ParamIndex].Name)
  352. else
  353. if pfByRef in FMacro.Params[ParamIndex].ParamFlags then
  354. begin
  355. FList[ParamIndex].Value.Value[0] := Value;
  356. SimplifyLValue(FList[ParamIndex].Value.Value[0]);
  357. end
  358. else
  359. begin
  360. if FMacro.Params[ParamIndex].DefValue.Typ = evCallContext then
  361. begin
  362. if (pfFunc in FMacro.Params[ParamIndex].ParamFlags) and
  363. (Value.AsCallContext.GroupingStyle <> agsParenteses) or
  364. not (pfFunc in FMacro.Params[ParamIndex].ParamFlags) and
  365. (Value.AsCallContext.GroupingStyle <> agsBrackets) then
  366. ErrorWrongType(FMacro.Params[ParamIndex].Name);
  367. end;
  368. FList[ParamIndex].Value.Value[0] := GetRValue(Value);
  369. end;
  370. FList[ParamIndex].Defined := True;
  371. FList[ParamIndex].Value.Name := FMacro.Params[ParamIndex].Name;
  372. FList[ParamIndex].Value.Dim := 0;
  373. Inc(FCurrentParam);
  374. end;
  375. function TMacroCallContext.Call: TIsppVariant;
  376. var
  377. I: Integer;
  378. Msg: string;
  379. begin
  380. PushMacro(FMacro.Name);
  381. try
  382. for I := 0 to FMacro.ParamCount - 1 do
  383. if not FList[I].Defined then
  384. if not (pfHasDefault in FMacro.Params[I].ParamFlags) then
  385. ErrorNotSpecified(FMacro.Params[I].Name)
  386. //raise EMacroError.CreateFmt(SNoReqParam, [FMacro.Params[I].Name])
  387. else
  388. begin
  389. FList[I].Value.Name := FMacro.Params[I].Name;
  390. FList[I].Value.Dim := 0;
  391. FList[I].Value.Value[0] := FMacro.Params[I].DefValue;
  392. FList[I].Defined := True;
  393. end;
  394. try
  395. Result := Parse(Self, FMacro.Expression, FMacro.DeclPos.Column,
  396. @FMacro.ParserOptions);
  397. except
  398. on E: EParsingError do
  399. begin
  400. if E.Position > 0 then
  401. begin
  402. if FMacro.DeclPos.FileIndex > 0 then
  403. Msg := Format(SErrorExecutingMacroFile, [FMacro.Name,
  404. PeekPreproc.IncludedFiles[FMacro.DeclPos.FileIndex],
  405. FMacro.DeclPos.Line, E.Position, E.Message])
  406. else
  407. Msg := Format(SErrorExecutingMacro, [FMacro.Name,
  408. FMacro.DeclPos.Line, E.Position, E.Message]);
  409. E.Message := Msg;
  410. E.Position := 0;
  411. end;
  412. raise;
  413. end;
  414. on E: Exception do
  415. begin
  416. E.Message := Format(SErrorExecutingMacroUnexpected, [FMacro.Name, E.Message]);
  417. raise;
  418. end;
  419. end;
  420. VerboseMsg(9, SSuccessfullyCalledMacro, [FMacro.Name]);
  421. finally
  422. PopMacro;
  423. end;
  424. end;
  425. function TMacroCallContext.Defined(const Name: string): Boolean;
  426. var
  427. I: Integer;
  428. begin
  429. Result := True;
  430. if CompareText(Name, SLocal) = 0 then Exit;
  431. for I := 0 to FMacro^.ParamCount - 1 do
  432. if CompareText(FMacro^.Params[I].Name, Name) = 0 then
  433. Exit;
  434. Result := FIdentManager.Defined(Name)
  435. end;
  436. function TMacroCallContext.FindFormalParam(const Name: string): Integer;
  437. begin
  438. for Result := 0 to FMacro.ParamCount - 1 do
  439. if CompareText(FMacro.Params[Result].Name, Name) = 0 then Exit;
  440. raise EMacroError.CreateFmt(SUnknownParam, [Name]);
  441. end;
  442. function TMacroCallContext.GetIdent(const Name: string;
  443. out CallContext: ICallContext): TIdentType;
  444. var
  445. I: Integer;
  446. begin
  447. Result := itVariable;
  448. if CompareText(SLocal, Name) = 0 then
  449. begin
  450. CallContext := TMacroLocalArrayCallContext.Create(Self);
  451. Exit;
  452. end
  453. else
  454. for I := 0 to FMacro^.ParamCount - 1 do
  455. if CompareText(FMacro^.Params[I].Name, Name) = 0 then
  456. begin
  457. if FMacro^.Params[I].DefValue.Typ = evCallContext then
  458. FList[I].Value.Value[0].AsCallContext.Clone(CallContext)
  459. else
  460. CallContext := TVarCallContext.Create(@FList[I].Value);
  461. Exit;
  462. end;
  463. Result := FIdentManager.GetIdent(Name, CallContext)
  464. end;
  465. function TMacroCallContext.TypeOf(const Name: string): Byte;
  466. var
  467. I: Integer;
  468. begin
  469. if CompareText(Name, SLocal) = 0 then
  470. begin
  471. Result := TYPE_ARRAY;
  472. Exit;
  473. end;
  474. for I := 0 to FMacro^.ParamCount - 1 do
  475. if CompareText(FMacro^.Params[I].Name, Name) = 0 then
  476. begin
  477. case GetRValue(FList[I].Value.Value[0]).Typ of
  478. evNull: Result := TYPE_NULL;
  479. evInt: Result := TYPE_INTEGER
  480. else
  481. Result := TYPE_STRING
  482. end;
  483. Exit;
  484. end;
  485. Result := FIdentManager.TypeOf(Name)
  486. end;
  487. {TFuncParam}
  488. type
  489. TFuncParam = class(TInterfacedObject, IIsppFuncParam)
  490. private
  491. FValue: PIsppVariant;
  492. protected
  493. constructor Create(Value: PIsppVariant);
  494. function GetType: TIsppVarType; stdcall;
  495. function GetAsInt64: Int64; stdcall;
  496. function GetAsString(Buf: PChar; BufSize: Cardinal): Integer; stdcall;
  497. end;
  498. constructor TFuncParam.Create(Value: PIsppVariant);
  499. begin
  500. FValue := Value
  501. end;
  502. function TFuncParam.GetAsInt64: Int64;
  503. begin
  504. Result := FValue^.AsInt64
  505. end;
  506. function TFuncParam.GetAsString(Buf: PChar; BufSize: Cardinal): Integer;
  507. begin
  508. StrLCopy(Buf, PChar(FValue^.AsStr), BufSize);
  509. Result := Length(FValue^.AsStr)
  510. end;
  511. function TFuncParam.GetType: TIsppVarType;
  512. begin
  513. Result := FValue^.Typ
  514. end;
  515. { TFuncCallContext }
  516. type
  517. TFuncCallContext = class(TCallContext, ICallContext, IInternalFuncParams,
  518. IIsppFuncResult)
  519. private
  520. FSender: NativeInt;
  521. FFunc: PFunc;
  522. FResult: TIsppVariant;
  523. FParams: TList;
  524. protected
  525. constructor Create(Sender: NativeInt; Func: PFunc);
  526. destructor Destroy; override;
  527. { IIsppFuncParams }
  528. function Get(Index: Integer): IIsppFuncParam; stdcall;
  529. function GetCount: Integer; stdcall;
  530. { IInternalFuncParams }
  531. function IInternalFuncParams.Get = InternalGet;
  532. function InternalGet(Index: Integer): PIsppVariant;
  533. function ResPtr: PIsppVariant;
  534. { IIsppFuncResult }
  535. procedure SetAsInt(Value: Int64); stdcall;
  536. procedure SetAsString(Value: PChar); stdcall;
  537. procedure SetAsNull; stdcall;
  538. procedure Error(Message: PChar); stdcall;
  539. { ICallContext }
  540. procedure Add(const Name: string; const Value: TIsppVariant);
  541. function Call: TIsppVariant;
  542. procedure Clone(out NewContext: ICallContext);
  543. end;
  544. constructor TFuncCallContext.Create(Sender: NativeInt; Func: PFunc);
  545. begin
  546. FSender := Sender;
  547. FFunc := Func;
  548. FParams := TList.Create;
  549. end;
  550. destructor TFuncCallContext.Destroy;
  551. begin
  552. FParams.Free;
  553. end;
  554. procedure TFuncCallContext.Add(const Name: string;
  555. const Value: TIsppVariant);
  556. var
  557. V: PIsppVariant;
  558. begin
  559. if Name <> '' then
  560. raise EIdentError.Create(SFuncsNoSupportNamedParams);
  561. New(V);
  562. CopyExpVar(Value, V^);
  563. FParams.Add(V);
  564. end;
  565. function TFuncCallContext.Call: TIsppVariant;
  566. var
  567. InternalParams: IInternalFuncParams;
  568. Error: TIsppFuncResult;
  569. Ext: NativeInt;
  570. begin
  571. InternalParams := Self;
  572. if FFunc.Ext = -1 then
  573. Ext := FSender
  574. else
  575. Ext := FFunc.Ext;
  576. Error := FFunc.Code(Ext, InternalParams, Self);
  577. case Error.Error of
  578. ISPPFUNC_FAIL: raise EIdentError.CreateFmt(SFuncError, [FFunc^.Name]);
  579. ISPPFUNC_MANYARGS: ErrorTooMany;
  580. ISPPFUNC_INSUFARGS: ErrorTooFew;
  581. ISPPFUNC_INTWANTED: raise EIdentError.Create(SIntegerExpressionExpected);
  582. ISPPFUNC_STRWANTED: raise EIdentError.Create(SStringExpressionExpected);
  583. end;
  584. Result := FResult;
  585. VerboseMsg(9, SSuccessfullyCalledFunction, [FFunc.Name]);
  586. end;
  587. procedure TFuncCallContext.Error(Message: PChar);
  588. begin
  589. raise Exception.Create(Message)
  590. end;
  591. function TFuncCallContext.Get(Index: Integer): IIsppFuncParam;
  592. begin
  593. Result := TFuncParam.Create(FParams[Index]);
  594. end;
  595. function TFuncCallContext.GetCount: Integer;
  596. begin
  597. Result := FParams.Count
  598. end;
  599. function TFuncCallContext.InternalGet(Index: Integer): PIsppVariant;
  600. begin
  601. Result := FParams[Index]
  602. end;
  603. function TFuncCallContext.ResPtr: PIsppVariant;
  604. begin
  605. Result := @FResult
  606. end;
  607. procedure TFuncCallContext.SetAsInt(Value: Int64);
  608. begin
  609. MakeInt(FResult, Value)
  610. end;
  611. procedure TFuncCallContext.SetAsNull;
  612. begin
  613. FResult := NULL
  614. end;
  615. procedure TFuncCallContext.SetAsString(Value: PChar);
  616. begin
  617. MakeStr(FResult, Value)
  618. end;
  619. { TIdentManager }
  620. constructor TIdentManager.Create(const CustomIdents: IIdentManager; FuncSender: NativeInt);
  621. begin
  622. FCustomIdents := CustomIdents;
  623. FVarMan := TList.Create;
  624. FFuncSender := FuncSender;
  625. end;
  626. destructor TIdentManager.Destroy;
  627. var
  628. I: Integer;
  629. begin
  630. for I := 0 to FVarMan.Count - 1 do
  631. FreeItem(FVarMan[I]);
  632. FVarMan.Free;
  633. end;
  634. function TIdentManager.Defined(const Name: string): Boolean;
  635. begin
  636. Result := Find(Name, dsAny) <> nil
  637. end;
  638. procedure TIdentManager.DefineFunction(const Name: string;
  639. Handler: TIsppFunction; Ext: NativeInt);
  640. var
  641. F: PFunc;
  642. begin
  643. if Find(Name, dsAny) <> nil then Exit;
  644. F := AllocMem(SizeOf(TFunc));
  645. F.Name := Name;
  646. F.Hash := MakeHash(Name);
  647. F.IdentType := itFunc;
  648. F.Code := Handler;
  649. F.Ext := Ext;
  650. FVarMan.Add(F);
  651. end;
  652. procedure TIdentManager.DefineMacro(const Name, Expression: string;
  653. ExprPos: TExprPosition; const ParserOptions: TIsppParserOptions;
  654. Params: array of TIsppMacroParam; Scope: TDefineScope);
  655. var
  656. P: PMacro;
  657. ArrSize, I, J: Integer;
  658. begin
  659. if Scope = dsAny then Scope := dsPublic;
  660. Delete(Name, Scope);
  661. ArrSize := SizeOf(TIsppMacroParam) * (Length(Params));
  662. for I := 1 to High(Params) do
  663. for J := 0 to I - 1 do
  664. if CompareText(Params[I].Name, Params[J].Name) = 0 then
  665. raise EIdentError.CreateFmt(SRedeclaredIdentifier, [Params[I].Name]);
  666. P := AllocMem(SizeOf(TMacro) + ArrSize);
  667. try
  668. P^.Name := Name;
  669. P^.Hash := MakeHash(Name);
  670. P^.IdentType := itMacro;
  671. P^.Scope.IsProtected := Scope = dsProtected;
  672. if Scope >= dsProtected then P^.Scope.LocalLevel := FLocalLevel;
  673. P^.Expression := Expression;
  674. P^.DeclPos := ExprPos;
  675. P^.ParserOptions := ParserOptions;
  676. P^.ParamCount := Length(Params);
  677. for I := 0 to High(Params) do
  678. P^.Params[I] := Params[I];
  679. FVarMan.Add(P);
  680. except
  681. FreeMem(P)
  682. end;
  683. VerboseMsg(4, SMacroDefined, [GL[Scope], Name]);
  684. end;
  685. procedure TIdentManager.DefineVariable(const Name: string; Index: Integer;
  686. const Value: TIsppVariant; Scope: TDefineScope);
  687. var
  688. V: PVariable;
  689. Ident: PIdent;
  690. begin
  691. if Scope = dsAny then Scope := dsPublic;
  692. Ident := Find(Name, Scope);
  693. if (Ident <> nil) and (Ident.IdentType = itVariable) and (PVariable(Ident).Dim <> 0) then
  694. begin
  695. V := PVariable(Ident);
  696. if (Index < 0) or (Index >= V.Dim) then
  697. raise EIdentError.CreateFmt(SIndexIsOutOfArraySize, [Index, Name]);
  698. V.Value[Index] := Value;
  699. end
  700. else
  701. begin
  702. if Index <> -1 then
  703. raise EIdentError.CreateFmt(SUndeclaredIdentifier, [Name]);
  704. Delete(Name, Scope);
  705. V := AllocMem(SizeOf(TVariable));
  706. V^.Name := Name;
  707. V^.Hash := MakeHash(Name);
  708. V^.IdentType := itVariable;
  709. V^.Scope.IsProtected := Scope = dsProtected;
  710. if Scope >= dsProtected then V^.Scope.LocalLevel := FLocalLevel;
  711. V^.Dim := 0;
  712. V^.Value[0] := Value;
  713. FVarMan.Add(V);
  714. end;
  715. VerboseMsg(4, SVariableDefined, [GL[Scope], Name]);
  716. end;
  717. procedure TIdentManager.Delete(const Name: string; Scope: TDefineScope);
  718. var
  719. P: PIdent;
  720. S: TDefineScope;
  721. const
  722. VM: array[itVariable..itMacro] of string = ('variable', 'macro');
  723. begin
  724. {if Scope = dsAny then
  725. begin
  726. P := Find(Name, dsPrivate);
  727. if P = nil then P := Find(Name, dsProtected);
  728. if P = nil then P := Find(Name, dsPublic)
  729. end
  730. else}
  731. P := Find(Name, Scope);
  732. if (P <> nil) and (P.IdentType in [itVariable, itMacro]) then
  733. begin
  734. //if PDefinable(P).Scope.Locality <> FLocalLevel then Exit;
  735. S := dsPublic;
  736. with PDefinable(P).Scope do
  737. if LocalLevel <> 0 then
  738. if IsProtected then
  739. S := dsProtected
  740. else
  741. S := dsPrivate;
  742. VerboseMsg(4, SUndefined, [GL[S],
  743. VM[P.IdentType], P.Name]);
  744. FVarMan.Remove(P);
  745. FreeItem(P);
  746. end
  747. end;
  748. procedure TIdentManager.DimVariable(const Name: string; Length: Integer;
  749. Scope: TDefineScope; var ReDim: Boolean);
  750. var
  751. V, VOld: PVariable;
  752. I, ReDimIndex: Integer;
  753. Msg: String;
  754. begin
  755. if Length > 0 then begin
  756. if Scope = dsAny then Scope := dsPublic;
  757. if ReDim then begin
  758. ReDimIndex := FindIndex(Name, Scope);
  759. if (ReDimIndex <> -1) and
  760. ((PIdent(FVarMan[ReDimIndex]).IdentType <> itVariable) or
  761. (PVariable(FVarMan[ReDimIndex]).Dim = 0)) then
  762. ReDimIndex := -1; //not a variable or not an array, #dim normally
  763. ReDim := ReDimIndex <> -1;
  764. end else
  765. ReDimIndex := -1;
  766. V := AllocMem(SizeOf(TVariable) + SizeOf(TIsppVariant) * (Length - 1));
  767. V.Name := Name;
  768. V.Hash := MakeHash(Name);
  769. V.IdentType := itVariable;
  770. V.Dim := Length;
  771. V^.Scope.IsProtected := Scope = dsProtected;
  772. if Scope >= dsProtected then V^.Scope.LocalLevel := FLocalLevel;
  773. if ReDimIndex = -1 then begin
  774. Delete(Name, Scope);
  775. for I := 0 to Length - 1 do
  776. V.Value[I] := NULL;
  777. FVarMan.Add(V);
  778. Msg := SArrayDeclared;
  779. end else begin
  780. VOld := PVariable(FVarMan[ReDimIndex]);
  781. for I := 0 to VOld.Dim - 1 do
  782. if I < Length then
  783. V.Value[I] := VOld.Value[I];
  784. for I := VOld.Dim to Length - 1 do
  785. V.Value[I] := NULL;
  786. FVarMan[ReDimIndex] := V;
  787. FreeItem(VOld);
  788. Msg := SArrayReDimmed;
  789. end;
  790. VerboseMsg(4, Msg, [GL[Scope], Name]);
  791. end else
  792. raise EIdentError.Create(SBadLength);
  793. end;
  794. function TIdentManager.FindIndex(const Name: string; AScope: TDefineScope): Integer;
  795. begin
  796. Result := -1;
  797. var H := MakeHash(Name);
  798. for var I := FVarMan.Count - 1 downto 0 do
  799. if (H = PIdent(FVarMan[I]).Hash) and (
  800. CompareText(PIdent(FVarMan[I]).Name, Name) = 0) then
  801. begin
  802. if (PIdent(FVarMan[I]).IdentType in [itVariable, itMacro]) then
  803. with PDefinable(FVarMan[I])^.Scope do
  804. case AScope of
  805. dsAny:
  806. if not ((LocalLevel = 0) or (LocalLevel = FLocalLevel) or IsProtected) then Continue;
  807. dsPublic:
  808. if LocalLevel <> 0 then Continue;
  809. dsProtected:
  810. if not (IsProtected and (LocalLevel <= FLocalLevel)) then Continue;
  811. else
  812. if IsProtected or (LocalLevel <> FLocalLevel) then Continue;
  813. end;
  814. Result := I;
  815. Exit
  816. end;
  817. end;
  818. function TIdentManager.Find(const Name: string; AScope: TDefineScope): PIdent;
  819. var
  820. I: Integer;
  821. begin
  822. I := FindIndex(Name, AScope);
  823. if I >= 0 then
  824. Result := FVarMan[I]
  825. else
  826. Result := nil;
  827. end;
  828. function TIdentManager.GetIdent(const Name: string;
  829. out CallContext: ICallContext): TIdentType;
  830. var
  831. P: PIdent;
  832. begin
  833. if CompareText(Name, 'DEFINED') = 0 then
  834. Result := itDefinedFunc
  835. else if CompareText(Name, 'TYPEOF') = 0 then
  836. Result := itTypeOfFunc
  837. else if CompareText(Name, 'DIMOF') = 0 then
  838. Result := itDimOfFunc
  839. else
  840. begin
  841. P := Find(Name, dsAny);
  842. if P <> nil then
  843. begin
  844. Result := P.IdentType;
  845. case P.IdentType of
  846. itVariable: CallContext := TVarCallContext.Create(PVariable(P));
  847. itMacro: CallContext := TMacroCallContext.Create(MacroIdents, PMacro(P));
  848. itFunc: CallContext := TFuncCallContext.Create(FFuncSender, PFunc(P));
  849. else
  850. Assert(False)
  851. end;
  852. end
  853. else
  854. Result := itUnknown;
  855. end;
  856. end;
  857. function TIdentManager.QueryInterface(const IID: TGUID; out Obj): HRESULT;
  858. begin
  859. if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE;
  860. end;
  861. function TIdentManager.TypeOf(const Name: string): Byte;
  862. var
  863. P: PIdent;
  864. begin
  865. Result := TYPE_ERROR;
  866. P := Find(Name, dsAny);
  867. if P <> nil then
  868. case P.IdentType of
  869. itVariable:
  870. if PVariable(P).Dim > 0 then
  871. Result := TYPE_ARRAY
  872. else
  873. case PVariable(P).Value[0].Typ of
  874. evNull: Result := TYPE_NULL;
  875. evInt: Result := TYPE_INTEGER;
  876. evStr: Result := TYPE_STRING
  877. end;
  878. itMacro: Result := TYPE_MACRO;
  879. itFunc: Result := TYPE_FUNC
  880. end
  881. end;
  882. function TIdentManager._AddRef: Integer;
  883. begin
  884. Result := InterlockedIncrement(FRefCount)
  885. end;
  886. function TIdentManager._Release: Integer;
  887. begin
  888. Result := InterlockedDecrement(FRefCount);
  889. if Result = 0 then
  890. Destroy;
  891. end;
  892. procedure TIdentManager.BeginLocal;
  893. begin
  894. Inc(FLocalLevel);
  895. end;
  896. procedure TIdentManager.EndLocal;
  897. var
  898. I: Integer;
  899. begin
  900. for I := FVarMan.Count - 1 downto 0 do
  901. if (PIdent(FVarMan.Items[I]).IdentType in [itVariable, itMacro]) and
  902. (PDefinable(FVarMan.Items[I]).Scope.LocalLevel = FLocalLevel) then
  903. begin
  904. FreeItem(FVarMan[I]);
  905. FVarMan.Delete(I);
  906. end;
  907. Dec(FLocalLevel);
  908. end;
  909. procedure TIdentManager.FreeItem(Item: Pointer);
  910. function ZeroToOne(A: Integer): Integer;
  911. begin
  912. if A = 0 then Result := 1 else Result := A
  913. end;
  914. begin
  915. with PIdent(Item)^ do
  916. begin
  917. Finalize(Name);
  918. case IdentType of
  919. itVariable: with PVariable(Item)^ do Finalize(Value[0], ZeroToOne(Dim));
  920. itMacro:
  921. with PMacro(Item)^ do
  922. begin
  923. Finalize(Params[0], ParamCount);
  924. Finalize(Expression);
  925. end;
  926. end;
  927. end;
  928. FreeMem(Item);
  929. end;
  930. function TIdentManager.MacroIdents: IIdentManager;
  931. begin
  932. if FCustomIdents <> nil then
  933. Result := FCustomIdents
  934. else
  935. Result := Self
  936. end;
  937. procedure TMacroCallContext.AdjustLocalArray(Index: Integer);
  938. var
  939. I: Integer;
  940. V: PIsppVariant;
  941. begin
  942. if not Assigned(FLocalVars) then
  943. FLocalVars := TList.Create;
  944. if FLocalVars.Count > Index then Exit;
  945. VerboseMsg(10, SAllocatingMacroLocalArrayUpToEle, [FMacro.Name, Index]);
  946. for I := FLocalVars.Count to Index do
  947. begin
  948. New(V);
  949. V.Typ := evNull;
  950. FLocalVars.Add(V);
  951. end;
  952. end;
  953. procedure TVarCallContext.Clone(out NewContext: ICallContext);
  954. begin
  955. if FVariable.Dim = 0 then
  956. NewContext := Self
  957. else
  958. NewContext := TVarCallContext.Create(FVariable);
  959. end;
  960. procedure TMacroLocalArrayCallContext.Clone(out NewContext: ICallContext);
  961. begin
  962. NewContext := TMacroLocalArrayCallContext.Create(FMacroContext);
  963. end;
  964. procedure TMacroCallContext.Clone(out NewContext: ICallContext);
  965. begin
  966. NewContext := TMacroCallContext.Create(FIdentManager, FMacro);
  967. end;
  968. procedure TFuncCallContext.Clone(out NewContext: ICallContext);
  969. begin
  970. NewContext := TFuncCallContext.Create(FSender, FFunc);
  971. end;
  972. function TIdentManager.DimOf(const Name: String): Integer;
  973. var
  974. Ident: PIdent;
  975. begin
  976. Ident := Find(Name, dsAny);
  977. if Assigned(Ident) and (Ident.IdentType = itVariable) then
  978. Result := PVariable(Ident)^.Dim
  979. else
  980. Result := 0;
  981. end;
  982. function TMacroCallContext.DimOf(const Name: string): Integer;
  983. begin
  984. if CompareText(Name, SLocal) = 0 then
  985. Result := MaxLocalArraySize
  986. else
  987. Result := FIdentManager.DimOf(Name);
  988. end;
  989. end.