tcbaseparser.pas 25 KB

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