tcbaseparser.pas 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  1. unit tcbaseparser;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, fpcunit, pastree, pscanner, pparser, testregistry;
  6. const
  7. DefaultMainFilename = 'afile.pp';
  8. Type
  9. { TTestEngine }
  10. TTestEngine = Class(TPasTreeContainer)
  11. Private
  12. FList : TFPList;
  13. public
  14. Destructor Destroy; override;
  15. function CreateElement(AClass: TPTreeElement; const AName: String;
  16. AParent: TPasElement; AVisibility: TPasMemberVisibility;
  17. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
  18. override;
  19. function FindElement(const AName: String): TPasElement; override;
  20. end;
  21. TTestPasParser = Class(TPasParser);
  22. { TTestParser }
  23. TTestParser = class(TTestCase)
  24. Private
  25. FDeclarations: TPasDeclarations;
  26. FDefinition: TPasElement;
  27. FEngine : TPasTreeContainer;
  28. FMainFilename: string;
  29. FModule: TPasModule;
  30. FParseResult: TPasElement;
  31. FScanner : TPascalScanner;
  32. FResolver : TStreamResolver;
  33. FParser : TTestPasParser;
  34. FSource: TStrings;
  35. FFileName : string;
  36. FIsUnit : Boolean;
  37. FImplementation : Boolean;
  38. FEndSource: Boolean;
  39. FUseImplementation: Boolean;
  40. function GetPL: TPasLibrary;
  41. function GetPP: TPasProgram;
  42. procedure CleanupParser;
  43. procedure SetupParser;
  44. protected
  45. procedure SetUp; override;
  46. procedure TearDown; override;
  47. procedure CreateEngine(var TheEngine: TPasTreeContainer); virtual;
  48. Procedure StartUnit(AUnitName : String);
  49. Procedure StartProgram(AFileName : String; AIn : String = ''; AOut : String = '');
  50. Procedure StartLibrary(AFileName : String);
  51. Procedure UsesClause(Units : Array of string);
  52. Procedure StartImplementation;
  53. Procedure EndSource;
  54. Procedure Add(Const ALine : String);
  55. Procedure Add(Const Lines : array of String);
  56. Procedure StartParsing;
  57. Procedure ParseDeclarations;
  58. Procedure ParseModule; virtual;
  59. procedure ResetParser;
  60. Procedure CheckHint(AHint : TPasMemberHint);
  61. Function AssertExpression(Const Msg: String; AExpr : TPasExpr; aKind : TPasExprKind; AClass : TClass) : TPasExpr;
  62. Function AssertExpression(Const Msg: String; AExpr : TPasExpr; aKind : TPasExprKind; AValue : String) : TPrimitiveExpr;
  63. Function AssertExpression(Const Msg: String; AExpr : TPasExpr; OpCode : TExprOpCode) : TBinaryExpr;
  64. Procedure AssertExportSymbol(Const Msg: String; AIndex : Integer; AName,AExportName : String; AExportIndex : Integer = -1);
  65. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TPasExprKind); overload;
  66. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TLoopType); overload;
  67. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TPasObjKind); overload;
  68. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TExprOpCode); overload;
  69. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TPasMemberHint); overload;
  70. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TCallingConvention); overload;
  71. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TArgumentAccess); overload;
  72. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TVariableModifier); overload;
  73. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TVariableModifiers); overload;
  74. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TPasMemberVisibility); overload;
  75. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TProcedureModifier); overload;
  76. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TProcedureModifiers); overload;
  77. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TProcTypeModifiers); overload;
  78. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TAssignKind); overload;
  79. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TProcedureMessageType); overload;
  80. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TOperatorType); overload;
  81. Procedure AssertSame(Const Msg : String; AExpected, AActual: TPasElement); overload;
  82. Procedure HaveHint(AHint : TPasMemberHint; AHints : TPasMemberHints);
  83. Property Resolver : TStreamResolver Read FResolver;
  84. Property Scanner : TPascalScanner Read FScanner;
  85. Property Engine : TPasTreeContainer read FEngine;
  86. Property Parser : TTestPasParser read FParser ;
  87. Property Source : TStrings Read FSource;
  88. Property Module : TPasModule Read FModule;
  89. Property PasProgram : TPasProgram Read GetPP;
  90. Property PasLibrary : TPasLibrary Read GetPL;
  91. Property Declarations : TPasDeclarations read FDeclarations Write FDeclarations;
  92. Property Definition : TPasElement Read FDefinition Write FDefinition;
  93. // If set, Will be freed in teardown
  94. Property ParseResult : TPasElement Read FParseResult Write FParseResult;
  95. Property UseImplementation : Boolean Read FUseImplementation Write FUseImplementation;
  96. Property MainFilename: string read FMainFilename write FMainFilename;
  97. end;
  98. function ExtractFileUnitName(aFilename: string): string;
  99. function GetPasElementDesc(El: TPasElement): string;
  100. procedure ReadNextPascalToken(var Position: PChar; out TokenStart: PChar;
  101. NestedComments: boolean; SkipDirectives: boolean);
  102. implementation
  103. uses typinfo;
  104. function ExtractFileUnitName(aFilename: string): string;
  105. var
  106. p: Integer;
  107. begin
  108. Result:=ExtractFileName(aFilename);
  109. if Result='' then exit;
  110. for p:=length(Result) downto 1 do
  111. case Result[p] of
  112. '/','\': exit;
  113. '.':
  114. begin
  115. Delete(Result,p,length(Result));
  116. exit;
  117. end;
  118. end;
  119. end;
  120. function GetPasElementDesc(El: TPasElement): string;
  121. begin
  122. if El=nil then exit('nil');
  123. Result:=El.Name+':'+El.ClassName+'['+El.SourceFilename+','+IntToStr(El.SourceLinenumber)+']';
  124. end;
  125. procedure ReadNextPascalToken(var Position: PChar; out TokenStart: PChar;
  126. NestedComments: boolean; SkipDirectives: boolean);
  127. const
  128. IdentChars = ['a'..'z','A'..'Z','_','0'..'9'];
  129. HexNumberChars = ['0'..'9','a'..'f','A'..'F'];
  130. var
  131. c1:char;
  132. CommentLvl: Integer;
  133. Src: PChar;
  134. begin
  135. Src:=Position;
  136. // read till next atom
  137. while true do
  138. begin
  139. case Src^ of
  140. #0: break;
  141. #1..#32: // spaces and special characters
  142. inc(Src);
  143. #$EF:
  144. if (Src[1]=#$BB)
  145. and (Src[2]=#$BF) then
  146. begin
  147. // skip UTF BOM
  148. inc(Src,3);
  149. end
  150. else
  151. break;
  152. '{': // comment start or compiler directive
  153. if (Src[1]='$') and (not SkipDirectives) then
  154. // compiler directive
  155. break
  156. else begin
  157. // Pascal comment => skip
  158. CommentLvl:=1;
  159. while true do
  160. begin
  161. inc(Src);
  162. case Src^ of
  163. #0: break;
  164. '{':
  165. if NestedComments then
  166. inc(CommentLvl);
  167. '}':
  168. begin
  169. dec(CommentLvl);
  170. if CommentLvl=0 then
  171. begin
  172. inc(Src);
  173. break;
  174. end;
  175. end;
  176. end;
  177. end;
  178. end;
  179. '/': // comment or real division
  180. if (Src[1]='/') then
  181. begin
  182. // comment start -> read til line end
  183. inc(Src);
  184. while not (Src^ in [#0,#10,#13]) do
  185. inc(Src);
  186. end
  187. else
  188. break;
  189. '(': // comment, bracket or compiler directive
  190. if (Src[1]='*') then
  191. begin
  192. if (Src[2]='$') and (not SkipDirectives) then
  193. // compiler directive
  194. break
  195. else
  196. begin
  197. // comment start -> read til comment end
  198. inc(Src,2);
  199. CommentLvl:=1;
  200. while true do
  201. begin
  202. case Src^ of
  203. #0: break;
  204. '(':
  205. if NestedComments and (Src[1]='*') then
  206. inc(CommentLvl);
  207. '*':
  208. if (Src[1]=')') then
  209. begin
  210. dec(CommentLvl);
  211. if CommentLvl=0 then
  212. begin
  213. inc(Src,2);
  214. break;
  215. end;
  216. inc(Position);
  217. end;
  218. end;
  219. inc(Src);
  220. end;
  221. end;
  222. end else
  223. // round bracket open
  224. break;
  225. else
  226. break;
  227. end;
  228. end;
  229. // read token
  230. TokenStart:=Src;
  231. c1:=Src^;
  232. case c1 of
  233. #0:
  234. ;
  235. 'A'..'Z','a'..'z','_':
  236. begin
  237. // identifier
  238. inc(Src);
  239. while Src^ in IdentChars do
  240. inc(Src);
  241. end;
  242. '0'..'9': // number
  243. begin
  244. inc(Src);
  245. // read numbers
  246. while (Src^ in ['0'..'9']) do
  247. inc(Src);
  248. if (Src^='.') and (Src[1]<>'.') then
  249. begin
  250. // real type number
  251. inc(Src);
  252. while (Src^ in ['0'..'9']) do
  253. inc(Src);
  254. end;
  255. if (Src^ in ['e','E']) then
  256. begin
  257. // read exponent
  258. inc(Src);
  259. if (Src^='-') then inc(Src);
  260. while (Src^ in ['0'..'9']) do
  261. inc(Src);
  262. end;
  263. end;
  264. '''','#': // string constant
  265. while true do
  266. case Src^ of
  267. #0: break;
  268. '#':
  269. begin
  270. inc(Src);
  271. while Src^ in ['0'..'9'] do
  272. inc(Src);
  273. end;
  274. '''':
  275. begin
  276. inc(Src);
  277. while not (Src^ in ['''',#0]) do
  278. inc(Src);
  279. if Src^='''' then
  280. inc(Src);
  281. end;
  282. else
  283. break;
  284. end;
  285. '$': // hex constant
  286. begin
  287. inc(Src);
  288. while Src^ in HexNumberChars do
  289. inc(Src);
  290. end;
  291. '&': // octal constant or keyword as identifier (e.g. &label)
  292. begin
  293. inc(Src);
  294. if Src^ in ['0'..'7'] then
  295. while Src^ in ['0'..'7'] do
  296. inc(Src)
  297. else
  298. while Src^ in IdentChars do
  299. inc(Src);
  300. end;
  301. '{': // compiler directive (it can't be a comment, because see above)
  302. begin
  303. CommentLvl:=1;
  304. while true do
  305. begin
  306. inc(Src);
  307. case Src^ of
  308. #0: break;
  309. '{':
  310. if NestedComments then
  311. inc(CommentLvl);
  312. '}':
  313. begin
  314. dec(CommentLvl);
  315. if CommentLvl=0 then
  316. begin
  317. inc(Src);
  318. break;
  319. end;
  320. end;
  321. end;
  322. end;
  323. end;
  324. '(': // bracket or compiler directive
  325. if (Src[1]='*') then
  326. begin
  327. // compiler directive -> read til comment end
  328. inc(Src,2);
  329. while (Src^<>#0) and ((Src^<>'*') or (Src[1]<>')')) do
  330. inc(Src);
  331. inc(Src,2);
  332. end
  333. else
  334. // round bracket open
  335. inc(Src);
  336. #192..#255:
  337. begin
  338. // read UTF8 character
  339. inc(Src);
  340. if ((ord(c1) and %11100000) = %11000000) then
  341. begin
  342. // could be 2 byte character
  343. if (ord(Src[0]) and %11000000) = %10000000 then
  344. inc(Src);
  345. end
  346. else if ((ord(c1) and %11110000) = %11100000) then
  347. begin
  348. // could be 3 byte character
  349. if ((ord(Src[0]) and %11000000) = %10000000)
  350. and ((ord(Src[1]) and %11000000) = %10000000) then
  351. inc(Src,2);
  352. end
  353. else if ((ord(c1) and %11111000) = %11110000) then
  354. begin
  355. // could be 4 byte character
  356. if ((ord(Src[0]) and %11000000) = %10000000)
  357. and ((ord(Src[1]) and %11000000) = %10000000)
  358. and ((ord(Src[2]) and %11000000) = %10000000) then
  359. inc(Src,3);
  360. end;
  361. end;
  362. else
  363. inc(Src);
  364. case c1 of
  365. '<': if Src^ in ['>','='] then inc(Src);
  366. '.': if Src^='.' then inc(Src);
  367. '@':
  368. if Src^='@' then
  369. begin
  370. // @@ label
  371. repeat
  372. inc(Src);
  373. until not (Src^ in IdentChars);
  374. end
  375. else
  376. if (Src^='=') and (c1 in [':','+','-','/','*','<','>']) then
  377. inc(Src);
  378. end;
  379. end;
  380. Position:=Src;
  381. end;
  382. { TTestEngine }
  383. destructor TTestEngine.Destroy;
  384. begin
  385. FreeAndNil(FList);
  386. inherited Destroy;
  387. end;
  388. function TTestEngine.CreateElement(AClass: TPTreeElement; const AName: String;
  389. AParent: TPasElement; AVisibility: TPasMemberVisibility;
  390. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
  391. begin
  392. //writeln('TTestEngine.CreateElement ',AName,' ',AClass.ClassName);
  393. Result := AClass.Create(AName, AParent);
  394. {$IFDEF CheckPasTreeRefCount}Result.RefIds.Add('CreateElement');{$ENDIF}
  395. Result.Visibility := AVisibility;
  396. Result.SourceFilename := ASourceFilename;
  397. Result.SourceLinenumber := ASourceLinenumber;
  398. if NeedComments and Assigned(CurrentParser) then
  399. begin
  400. // Writeln('Saving comment : ',CurrentParser.SavedComments);
  401. Result.DocComment:=CurrentParser.SavedComments;
  402. end;
  403. if AName<>'' then
  404. begin
  405. If not Assigned(FList) then
  406. FList:=TFPList.Create;
  407. FList.Add(Result);
  408. end;
  409. end;
  410. function TTestEngine.FindElement(const AName: String): TPasElement;
  411. Var
  412. I : Integer;
  413. begin
  414. Result:=Nil;
  415. if Assigned(FList) then
  416. begin
  417. I:=FList.Count-1;
  418. While (Result=Nil) and (I>=0) do
  419. begin
  420. if CompareText(TPasElement(FList[I]).Name,AName)=0 then
  421. Result:=TPasElement(FList[i]);
  422. Dec(i);
  423. end;
  424. end;
  425. end;
  426. function TTestParser.GetPP: TPasProgram;
  427. begin
  428. Result:=Module as TPasProgram;
  429. end;
  430. function TTestParser.GetPL: TPasLibrary;
  431. begin
  432. Result:=Module as TPasLibrary;
  433. end;
  434. procedure TTestParser.SetupParser;
  435. begin
  436. FResolver:=TStreamResolver.Create;
  437. FResolver.OwnsStreams:=True;
  438. FScanner:=TPascalScanner.Create(FResolver);
  439. FScanner.CurrentBoolSwitches:=FScanner.CurrentBoolSwitches+[bsHints,bsNotes,bsWarnings];
  440. CreateEngine(FEngine);
  441. FParser:=TTestPasParser.Create(FScanner,FResolver,FEngine);
  442. FSource:=TStringList.Create;
  443. FModule:=Nil;
  444. FDeclarations:=Nil;
  445. FEndSource:=False;
  446. FImplementation:=False;
  447. FIsUnit:=False;
  448. end;
  449. procedure TTestParser.CleanupParser;
  450. begin
  451. {$IFDEF VerbosePasResolverMem}
  452. writeln('TTestParser.CleanupParser START');
  453. {$ENDIF}
  454. if Not Assigned(FModule) then
  455. FreeAndNil(FDeclarations)
  456. else
  457. FDeclarations:=Nil;
  458. FImplementation:=False;
  459. FEndSource:=False;
  460. FIsUnit:=False;
  461. {$IFDEF VerbosePasResolverMem}
  462. writeln('TTestParser.CleanupParser FModule');
  463. {$ENDIF}
  464. ReleaseAndNil(TPasElement(FModule){$IFDEF CheckPasTreeRefCount},'CreateElement'{$ENDIF});
  465. {$IFDEF VerbosePasResolverMem}
  466. writeln('TTestParser.CleanupParser FSource');
  467. {$ENDIF}
  468. FreeAndNil(FSource);
  469. {$IFDEF VerbosePasResolverMem}
  470. writeln('TTestParser.CleanupParser FParseResult');
  471. {$ENDIF}
  472. FreeAndNil(FParseResult);
  473. {$IFDEF VerbosePasResolverMem}
  474. writeln('TTestParser.CleanupParser FParser');
  475. {$ENDIF}
  476. FreeAndNil(FParser);
  477. {$IFDEF VerbosePasResolverMem}
  478. writeln('TTestParser.CleanupParser FEngine');
  479. {$ENDIF}
  480. FreeAndNil(FEngine);
  481. {$IFDEF VerbosePasResolverMem}
  482. writeln('TTestParser.CleanupParser FScanner');
  483. {$ENDIF}
  484. FreeAndNil(FScanner);
  485. {$IFDEF VerbosePasResolverMem}
  486. writeln('TTestParser.CleanupParser FResolver');
  487. {$ENDIF}
  488. FreeAndNil(FResolver);
  489. {$IFDEF VerbosePasResolverMem}
  490. writeln('TTestParser.CleanupParser END');
  491. {$ENDIF}
  492. end;
  493. procedure TTestParser.ResetParser;
  494. begin
  495. CleanupParser;
  496. SetupParser;
  497. end;
  498. procedure TTestParser.SetUp;
  499. begin
  500. FMainFilename:=DefaultMainFilename;
  501. Inherited;
  502. SetupParser;
  503. end;
  504. procedure TTestParser.TearDown;
  505. begin
  506. {$IFDEF VerbosePasResolverMem}
  507. writeln('TTestParser.TearDown START CleanupParser');
  508. {$ENDIF}
  509. CleanupParser;
  510. {$IFDEF VerbosePasResolverMem}
  511. writeln('TTestParser.TearDown inherited');
  512. {$ENDIF}
  513. Inherited;
  514. {$IFDEF VerbosePasResolverMem}
  515. writeln('TTestParser.TearDown END');
  516. {$ENDIF}
  517. end;
  518. procedure TTestParser.CreateEngine(var TheEngine: TPasTreeContainer);
  519. begin
  520. TheEngine:=TTestEngine.Create;
  521. end;
  522. procedure TTestParser.StartUnit(AUnitName: String);
  523. begin
  524. FIsUnit:=True;
  525. If (AUnitName='') then
  526. AUnitName:=ExtractFileUnitName(MainFilename);
  527. Add('unit '+aUnitName+';');
  528. Add('');
  529. Add('interface');
  530. Add('');
  531. FFileName:=AUnitName+'.pp';
  532. end;
  533. procedure TTestParser.StartProgram(AFileName : String; AIn : String = ''; AOut : String = '');
  534. begin
  535. FIsUnit:=False;
  536. If (AFileName='') then
  537. AFileName:='proga';
  538. FFileName:=AFileName+'.pp';
  539. If (AIn<>'') then
  540. begin
  541. AFileName:=AFileName+'('+AIn;
  542. if (AOut<>'') then
  543. AFileName:=AFileName+','+AOut;
  544. AFileName:=AFileName+')';
  545. end;
  546. Add('program '+AFileName+';');
  547. FImplementation:=True;
  548. end;
  549. procedure TTestParser.StartLibrary(AFileName: String);
  550. begin
  551. FIsUnit:=False;
  552. If (AFileName='') then
  553. AFileName:='liba';
  554. FFileName:=AFileName+'.pp';
  555. Add('library '+AFileName+';');
  556. FImplementation:=True;
  557. end;
  558. procedure TTestParser.UsesClause(Units: array of string);
  559. Var
  560. S : String;
  561. I : integer;
  562. begin
  563. S:='';
  564. For I:=Low(units) to High(units) do
  565. begin
  566. If (S<>'') then
  567. S:=S+', ';
  568. S:=S+Units[i];
  569. end;
  570. Add('uses '+S+';');
  571. Add('');
  572. end;
  573. procedure TTestParser.StartImplementation;
  574. begin
  575. if Not FImplementation then
  576. begin
  577. if UseImplementation then
  578. begin
  579. FSource.Insert(0,'');
  580. FSource.Insert(0,'Implementation');
  581. FSource.Insert(0,'');
  582. end
  583. else
  584. begin
  585. Add('');
  586. Add('Implementation');
  587. Add('');
  588. end;
  589. FImplementation:=True;
  590. end;
  591. end;
  592. procedure TTestParser.EndSource;
  593. begin
  594. if Not FEndSource then
  595. begin
  596. Add('end.');
  597. FEndSource:=True;
  598. end;
  599. end;
  600. procedure TTestParser.Add(const ALine: String);
  601. begin
  602. FSource.Add(ALine);
  603. end;
  604. procedure TTestParser.Add(const Lines: array of String);
  605. var
  606. i: Integer;
  607. begin
  608. for i:=Low(Lines) to High(Lines) do
  609. Add(Lines[i]);
  610. end;
  611. procedure TTestParser.StartParsing;
  612. var
  613. i: Integer;
  614. begin
  615. If FIsUnit then
  616. StartImplementation;
  617. EndSource;
  618. If (FFileName='') then
  619. FFileName:=MainFilename;
  620. FResolver.AddStream(FFileName,TStringStream.Create(FSource.Text));
  621. FScanner.OpenFile(FFileName);
  622. Writeln('// Test : ',Self.TestName);
  623. for i:=0 to FSource.Count-1 do
  624. Writeln(Format('%:4d: ',[i+1]),FSource[i]);
  625. end;
  626. procedure TTestParser.ParseDeclarations;
  627. begin
  628. if UseImplementation then
  629. StartImplementation;
  630. FSource.Insert(0,'');
  631. FSource.Insert(0,'interface');
  632. FSource.Insert(0,'');
  633. FSource.Insert(0,'unit afile;');
  634. if Not UseImplementation then
  635. StartImplementation;
  636. EndSource;
  637. ParseModule;
  638. if UseImplementation then
  639. FDeclarations:=Module.ImplementationSection
  640. else
  641. FDeclarations:=Module.InterfaceSection;
  642. end;
  643. procedure TTestParser.ParseModule;
  644. begin
  645. StartParsing;
  646. FParser.ParseMain(FModule);
  647. AssertNotNull('Module resulted in Module',FModule);
  648. AssertEquals('modulename',ChangeFileExt(FFileName,''),Module.Name);
  649. end;
  650. procedure TTestParser.CheckHint(AHint: TPasMemberHint);
  651. begin
  652. HaveHint(AHint,Definition.Hints);
  653. end;
  654. function TTestParser.AssertExpression(const Msg: String; AExpr: TPasExpr;
  655. aKind: TPasExprKind; AClass: TClass): TPasExpr;
  656. begin
  657. AssertNotNull(AExpr);
  658. AssertEquals(Msg+': Correct expression kind',aKind,AExpr.Kind);
  659. AssertEquals(Msg+': Correct expression class',AClass,AExpr.ClassType);
  660. Result:=AExpr;
  661. end;
  662. function TTestParser.AssertExpression(const Msg: String; AExpr: TPasExpr;
  663. aKind: TPasExprKind; AValue: String): TPrimitiveExpr;
  664. begin
  665. Result:=AssertExpression(Msg,AExpr,aKind,TPrimitiveExpr) as TPrimitiveExpr;
  666. AssertEquals(Msg+': Primitive expression value',AValue,TPrimitiveExpr(AExpr).Value);
  667. end;
  668. function TTestParser.AssertExpression(const Msg: String; AExpr: TPasExpr;
  669. OpCode: TExprOpCode): TBinaryExpr;
  670. begin
  671. Result:=AssertExpression(Msg,AExpr,pekBinary,TBinaryExpr) as TBinaryExpr;
  672. AssertEquals(Msg+': Binary opcode',OpCode,TBinaryExpr(AExpr).OpCode);
  673. end;
  674. procedure TTestParser.AssertExportSymbol(const Msg: String; AIndex: Integer;
  675. AName, AExportName: String; AExportIndex: Integer);
  676. Var
  677. E: TPasExportSymbol;
  678. begin
  679. AssertNotNull(Msg+'Have export symbols list',PasLibrary.LibrarySection.ExportSymbols);
  680. if AIndex>=PasLibrary.LibrarySection.ExportSymbols.Count then
  681. Fail(Format(Msg+'%d not a valid export list symbol',[AIndex]));
  682. AssertNotNull(Msg+'Have export symbol',PasLibrary.LibrarySection.ExportSymbols[Aindex]);
  683. AssertEquals(Msg+'Correct export symbol class',TPasExportSymbol,TObject(PasLibrary.LibrarySection.ExportSymbols[Aindex]).ClassType);
  684. E:=TPasExportSymbol(PasLibrary.LibrarySection.ExportSymbols[Aindex]);
  685. AssertEquals(Msg+'Correct export symbol name',AName,E.Name);
  686. if (AExportName='') then
  687. AssertNull(Msg+'No export name',E.ExportName)
  688. else
  689. begin
  690. AssertNotNull(Msg+'Export name symbol',E.ExportName);
  691. AssertEquals(Msg+'TPrimitiveExpr',TPrimitiveExpr,E.ExportName.CLassType);
  692. AssertEquals(Msg+'Correct export symbol export name ',''''+AExportName+'''',TPrimitiveExpr(E.ExportName).Value);
  693. end;
  694. If AExportIndex=-1 then
  695. AssertNull(Msg+'No export name',E.ExportIndex)
  696. else
  697. begin
  698. AssertNotNull(Msg+'Export name symbol',E.ExportIndex);
  699. AssertEquals(Msg+'TPrimitiveExpr',TPrimitiveExpr,E.ExportIndex.CLassType);
  700. AssertEquals(Msg+'Correct export symbol export index',IntToStr(AExportindex),TPrimitiveExpr(E.ExportIndex).Value);
  701. end;
  702. end;
  703. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  704. AActual: TPasExprKind);
  705. begin
  706. AssertEquals(Msg,GetEnumName(TypeInfo(TPasExprKind),Ord(AExpected)),
  707. GetEnumName(TypeInfo(TPasExprKind),Ord(AActual)));
  708. end;
  709. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  710. AActual: TLoopType);
  711. begin
  712. AssertEquals(Msg,GetEnumName(TypeInfo(TLoopType),Ord(AExpected)),
  713. GetEnumName(TypeInfo(TLoopType),Ord(AActual)));
  714. end;
  715. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  716. AActual: TPasObjKind);
  717. begin
  718. AssertEquals(Msg,GetEnumName(TypeInfo(TPasObjKind),Ord(AExpected)),
  719. GetEnumName(TypeInfo(TPasObjKind),Ord(AActual)));
  720. end;
  721. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  722. AActual: TExprOpCode);
  723. begin
  724. AssertEquals(Msg,GetEnumName(TypeInfo(TexprOpcode),Ord(AExpected)),
  725. GetEnumName(TypeInfo(TexprOpcode),Ord(AActual)));
  726. end;
  727. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  728. AActual: TPasMemberHint);
  729. begin
  730. AssertEquals(Msg,GetEnumName(TypeInfo(TPasMemberHint),Ord(AExpected)),
  731. GetEnumName(TypeInfo(TPasMemberHint),Ord(AActual)));
  732. end;
  733. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  734. AActual: TCallingConvention);
  735. begin
  736. AssertEquals(Msg,GetEnumName(TypeInfo(TCallingConvention),Ord(AExpected)),
  737. GetEnumName(TypeInfo(TCallingConvention),Ord(AActual)));
  738. end;
  739. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  740. AActual: TArgumentAccess);
  741. begin
  742. AssertEquals(Msg,GetEnumName(TypeInfo(TArgumentAccess),Ord(AExpected)),
  743. GetEnumName(TypeInfo(TArgumentAccess),Ord(AActual)));
  744. end;
  745. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  746. AActual: TVariableModifier);
  747. begin
  748. AssertEquals(Msg,GetEnumName(TypeInfo(TVariableModifier),Ord(AExpected)),
  749. GetEnumName(TypeInfo(TVariableModifier),Ord(AActual)));
  750. end;
  751. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  752. AActual: TVariableModifiers);
  753. Function sn (S : TVariableModifiers) : string;
  754. Var
  755. M : TVariableModifier;
  756. begin
  757. Result:='';
  758. For M:=Low(TVariableModifier) to High(TVariableModifier) do
  759. if M in S then
  760. begin
  761. if (Result<>'') then
  762. Result:=Result+',';
  763. end;
  764. Result:='['+Result+']';
  765. end;
  766. begin
  767. AssertEquals(Msg,Sn(AExpected),Sn(AActual));
  768. end;
  769. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  770. AActual: TPasMemberVisibility);
  771. begin
  772. AssertEquals(Msg,GetEnumName(TypeInfo(TPasMemberVisibility),Ord(AExpected)),
  773. GetEnumName(TypeInfo(TPasMemberVisibility),Ord(AActual)));
  774. end;
  775. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  776. AActual: TProcedureModifier);
  777. begin
  778. AssertEquals(Msg,GetEnumName(TypeInfo(TProcedureModifier),Ord(AExpected)),
  779. GetEnumName(TypeInfo(TProcedureModifier),Ord(AActual)));
  780. end;
  781. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  782. AActual: TProcedureModifiers);
  783. Function Sn (S : TProcedureModifiers) : String;
  784. Var
  785. m : TProcedureModifier;
  786. begin
  787. Result:='';
  788. For M:=Low(TProcedureModifier) to High(TProcedureModifier) do
  789. If (m in S) then
  790. begin
  791. If (Result<>'') then
  792. Result:=Result+',';
  793. Result:=Result+GetEnumName(TypeInfo(TProcedureModifier),Ord(m))
  794. end;
  795. end;
  796. begin
  797. AssertEquals(Msg,Sn(AExpected),SN(AActual));
  798. end;
  799. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  800. AActual: TProcTypeModifiers);
  801. Function Sn (S : TProcTypeModifiers) : String;
  802. Var
  803. m : TProcTypeModifier;
  804. begin
  805. Result:='';
  806. For M:=Low(TProcTypeModifier) to High(TProcTypeModifier) do
  807. If (m in S) then
  808. begin
  809. If (Result<>'') then
  810. Result:=Result+',';
  811. Result:=Result+GetEnumName(TypeInfo(TProcTypeModifier),Ord(m))
  812. end;
  813. end;
  814. begin
  815. AssertEquals(Msg,Sn(AExpected),SN(AActual));
  816. end;
  817. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  818. AActual: TAssignKind);
  819. begin
  820. AssertEquals(Msg,GetEnumName(TypeInfo(TAssignKind),Ord(AExpected)),
  821. GetEnumName(TypeInfo(TAssignKind),Ord(AActual)));
  822. end;
  823. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  824. AActual: TProcedureMessageType);
  825. begin
  826. AssertEquals(Msg,GetEnumName(TypeInfo(TProcedureMessageType),Ord(AExpected)),
  827. GetEnumName(TypeInfo(TProcedureMessageType),Ord(AActual)));
  828. end;
  829. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  830. AActual: TOperatorType);
  831. begin
  832. AssertEquals(Msg,GetEnumName(TypeInfo(TOperatorType),Ord(AExpected)),
  833. GetEnumName(TypeInfo(TOperatorType),Ord(AActual)));
  834. end;
  835. procedure TTestParser.AssertSame(const Msg: String; AExpected,
  836. AActual: TPasElement);
  837. begin
  838. if AExpected=AActual then exit;
  839. AssertEquals(Msg,GetPasElementDesc(AExpected),GetPasElementDesc(AActual));
  840. end;
  841. procedure TTestParser.HaveHint(AHint: TPasMemberHint; AHints: TPasMemberHints);
  842. begin
  843. If not (AHint in AHints) then
  844. Fail(GetEnumName(TypeInfo(TPasMemberHint),Ord(AHint))+'hint expected.');
  845. end;
  846. end.