tcscanner.pp 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184
  1. unit tcscanner;
  2. {$mode objfpc}
  3. {$H+}
  4. {$codepage UTF8}
  5. interface
  6. uses
  7. Classes, SysUtils, Typinfo, fpcunit, testregistry, jstoken, jsscanner;
  8. type
  9. { TTestLineReader }
  10. TTestLineReader = Class(TTestCase)
  11. Private
  12. FData: TStringStream;
  13. FReader : TStreamLineReader;
  14. protected
  15. Procedure CreateReader(AInput : String);
  16. procedure TearDown; override;
  17. published
  18. Procedure TestEmpty;
  19. Procedure TestReadLine;
  20. Procedure TestReadLines13;
  21. Procedure TestReadLines10;
  22. Procedure TestReadLines1310;
  23. procedure TestReadLinesEOF13;
  24. procedure TestReadLinesEOF10;
  25. procedure TestReadLinesEOF1310;
  26. procedure TestReadEmptyLines101010;
  27. end;
  28. { TTestJSScanner }
  29. TTestJSScanner = class(TTestCase)
  30. Private
  31. FNeedWhiteSpace: Boolean;
  32. FStream : TStream;
  33. FLineReader : TLineReader;
  34. FScanner : TJSScanner;
  35. FErrorSource : String;
  36. procedure AssertEquals(AMessage: String; AExpected, AActual : TJSToken); overload;
  37. procedure CheckToken(AToken: TJSToken; ASource: TJSScannerString; aVersion : TECMAVersion = ecma5);
  38. procedure CheckTokens(ASource: TJSScannerString; ATokens: array of TJSToken; aVersion : TECMAVersion = ecma5);
  39. procedure DoTestFloat(F: Double);
  40. procedure DoTestFloat(F: Double; S: String);
  41. procedure DoTestString(S: String; WasMultiline : Boolean = False);
  42. procedure TestErrorSource;
  43. protected
  44. Function CreateScanner(AInput : TJSScannerString; aVersion : TECMAVersion = ecma5) : TJSScanner;
  45. procedure FreeScanner;
  46. procedure SetUp; override;
  47. procedure TearDown; override;
  48. Property NeedWhiteSpace : Boolean Read FNeedWhiteSpace Write FNeedWhiteSpace;
  49. Property Scanner : TJSScanner Read FScanner;
  50. published
  51. Procedure TestEmpty;
  52. procedure TestAndAnd;
  53. procedure TestAndEq;
  54. procedure TestAssign;
  55. procedure TestBraceClose;
  56. procedure TestBraceOpen;
  57. procedure TestColon;
  58. procedure TestComma;
  59. procedure TestCurlyBraceClose;
  60. procedure TestCurlyBraceOpen;
  61. procedure TestDiv;
  62. procedure TestPower;
  63. procedure TestDiveq;
  64. procedure TestXor;
  65. procedure TestXoreq;
  66. procedure TestDot;
  67. procedure TestEq;
  68. procedure TestGE;
  69. procedure TestFalse;
  70. procedure TestInv;
  71. procedure TestNot;
  72. procedure TestString;
  73. procedure TestTrue;
  74. procedure TestGreaterThan;
  75. procedure TestLE;
  76. procedure TestLessThan;
  77. procedure TestLSHIFT;
  78. procedure TestLSHIFTEQ;
  79. procedure TestMinus;
  80. procedure TestMinusEQ;
  81. procedure TestMinusMinus;
  82. procedure TestModeq;
  83. procedure TestMul;
  84. procedure TestNE;
  85. procedure TestNSE;
  86. procedure TestOREQ;
  87. procedure TestOROR;
  88. procedure TestPlus;
  89. procedure TestPlusEq;
  90. procedure TestPlusPlus;
  91. procedure TestRShift;
  92. procedure TestRShiftEq;
  93. procedure TestSemicolon;
  94. procedure TestSEq;
  95. procedure TestSquaredBraceClose;
  96. procedure TestSquaredBraceOpen;
  97. procedure TestStarEq;
  98. procedure TestURShift;
  99. procedure TestURShiftEq;
  100. procedure TestArrow;
  101. procedure TestEllipsis;
  102. procedure TestAwaitECMA5;
  103. procedure TestAwaitECMA2021;
  104. procedure TestBreak;
  105. procedure TestCase;
  106. procedure TestCatch;
  107. procedure TestClassECMA5;
  108. procedure TestClassECMA2021;
  109. procedure TestConstECMA5;
  110. procedure TestConstECMA2021;
  111. procedure TestContinue;
  112. procedure TestDebuggerECMA5;
  113. procedure TestDebuggerECMA2021;
  114. procedure TestDefault;
  115. procedure TestDelete;
  116. procedure TestDO;
  117. procedure TestElse;
  118. procedure TestEnumECMA5;
  119. procedure TestEnumECMA2021;
  120. procedure TestExportECMA5;
  121. procedure TestExportECMA2021;
  122. procedure TestExtendsECMA5;
  123. procedure TestExtendsECMA2021;
  124. procedure TestFinally;
  125. procedure TestFor;
  126. procedure TestFunction;
  127. procedure TestIf;
  128. procedure TestImportECMA5;
  129. procedure TestImportECMA2021;
  130. procedure TestIn;
  131. procedure TestInstanceOf;
  132. procedure TestLetECMA5;
  133. procedure TestLetECMA2021;
  134. procedure TestNew;
  135. procedure TestReturn;
  136. procedure TestSuperECMA5;
  137. procedure TestSuperECMA2021;
  138. procedure TestSwitch;
  139. procedure TestThis;
  140. procedure TestThrow;
  141. procedure TestTry;
  142. procedure TestTypeOf;
  143. procedure TestVar;
  144. procedure TestVoid;
  145. procedure TestWhile;
  146. procedure TestWith;
  147. procedure TestYieldECMA5;
  148. procedure TestYieldECMA2021;
  149. Procedure Test2Words;
  150. procedure Test3Words;
  151. procedure TestIdentifier;
  152. procedure TestIdentifier2;
  153. procedure TestIdentifier3;
  154. procedure TestIdentifier4;
  155. procedure TestIdentifier5;
  156. procedure TestIdentifierDotIdentifier;
  157. procedure TestEOLN;
  158. procedure TestEOLN2;
  159. procedure TestEOLN3;
  160. procedure TestEOLN4;
  161. procedure TestComment1;
  162. procedure TestComment2;
  163. procedure TestComment3;
  164. procedure TestComment4;
  165. procedure TestComment5;
  166. procedure TestComment6;
  167. procedure TestFloat;
  168. procedure TestStringError;
  169. procedure TestFloatError;
  170. procedure TestMultilineString;
  171. procedure TestMultilineStringError;
  172. procedure TestMultilineStringError2;
  173. Procedure TestNonBreakingSpace;
  174. end;
  175. implementation
  176. function TTestJSScanner.CreateScanner(AInput: TJSScannerString;
  177. aVersion: TECMAVersion): TJSScanner;
  178. begin
  179. FStream:=TStringStream.Create(AInput);
  180. FLineReader:=TStreamLineReader.Create(Fstream);
  181. FScanner:=TJSScanner.Create(FLineReader,aVersion);
  182. FScanner.IsTypeScript:=False;
  183. Result:=FScanner;
  184. if FNeedWhiteSpace then
  185. FScanner.ReturnWhiteSpace:=True;
  186. end;
  187. procedure TTestJSScanner.FreeScanner;
  188. begin
  189. FreeAndNil(FScanner);
  190. FreeAndNil(FLineReader);
  191. FreeAndNil(FStream);
  192. end;
  193. procedure TTestJSScanner.SetUp;
  194. begin
  195. inherited SetUp;
  196. FNeedWhiteSpace:=False;
  197. end;
  198. procedure TTestJSScanner.TestEmpty;
  199. Var
  200. J : TJSToken;
  201. begin
  202. CreateScanner('');
  203. J:=Scanner.FetchToken;
  204. If (J<>tjsEOF) then
  205. Fail('Empty returns EOF');
  206. end;
  207. procedure TTestJSScanner.AssertEquals(AMessage : String; AExpected, AActual: TJSToken);
  208. Var
  209. S,EN1,EN2 : String;
  210. begin
  211. If (AActual<>AExpected) then
  212. begin
  213. EN1:=GetEnumName(TypeINfo(TJSToken),Ord(AExpected));
  214. EN2:=GetEnumName(TypeINfo(TJSToken),Ord(AActual));
  215. S:=Format('%s : %s <> %s',[AMessage,EN1,EN2]);
  216. Fail(S);
  217. end;
  218. end;
  219. procedure TTestJSScanner.CheckToken(AToken: TJSToken; ASource: TJSScannerString; aVersion: TECMAVersion);
  220. Var
  221. J : TJSToken;
  222. EN2 : String;
  223. begin
  224. CreateScanner(ASource,aVersion);
  225. J:=Scanner.FetchToken;
  226. EN2:=GetEnumName(TypeINfo(TJSToken),Ord(AToken));
  227. AssertEquals(Format('Source %s should result in %s.',[ASource,EN2]),AToken,J);
  228. end;
  229. procedure TTestJSScanner.TestAndAnd;
  230. begin
  231. CheckToken(tjsAndAnd,'&&');
  232. end;
  233. procedure TTestJSScanner.TestAndEq;
  234. begin
  235. CheckToken(tjsAndEq,'&=');
  236. end;
  237. procedure TTestJSScanner.TestBraceOpen;
  238. begin
  239. CheckToken(tjsBraceOpen,'(');
  240. end;
  241. procedure TTestJSScanner.TestBraceClose;
  242. begin
  243. CheckToken(tjsBraceClose,')');
  244. end;
  245. procedure TTestJSScanner.TestSquaredBraceClose;
  246. begin
  247. CheckToken(tjsSquaredBraceClose,']');
  248. end;
  249. procedure TTestJSScanner.TestSquaredBraceOpen;
  250. begin
  251. CheckToken(tjssQuaredBraceOpen,'[');
  252. end;
  253. procedure TTestJSScanner.TestCurlyBraceOpen;
  254. begin
  255. CheckToken(tjsCurlyBraceOpen,'{');
  256. end;
  257. procedure TTestJSScanner.TestCurlyBraceClose;
  258. begin
  259. CheckToken(tjsCurlyBraceClose,'}');
  260. end;
  261. procedure TTestJSScanner.TestComma;
  262. begin
  263. CheckToken(tjsComma,',');
  264. end;
  265. procedure TTestJSScanner.TestColon;
  266. begin
  267. CheckToken(tjsColon,':');
  268. end;
  269. procedure TTestJSScanner.TestDot;
  270. begin
  271. CheckToken(tjsDot,'.');
  272. end;
  273. procedure TTestJSScanner.TestSemicolon;
  274. begin
  275. CheckToken(tjsSemicolon,';');
  276. end;
  277. procedure TTestJSScanner.TestAssign;
  278. begin
  279. CheckToken(tjsAssign,'=');
  280. end;
  281. procedure TTestJSScanner.TestGreaterThan;
  282. begin
  283. CheckToken(tjsGT,'>');
  284. end;
  285. procedure TTestJSScanner.TestLessThan;
  286. begin
  287. CheckToken(tjsLT,'<');
  288. end;
  289. procedure TTestJSScanner.TestPlus;
  290. begin
  291. CheckToken(tjsPlus,'+');
  292. end;
  293. procedure TTestJSScanner.TestMinus;
  294. begin
  295. CheckToken(tjsMinus,'-');
  296. end;
  297. procedure TTestJSScanner.TestMul;
  298. begin
  299. CheckToken(tjsMul,'*');
  300. end;
  301. procedure TTestJSScanner.TestDiv;
  302. begin
  303. CheckToken(tjsDiv,'/');
  304. end;
  305. procedure TTestJSScanner.TestPower;
  306. begin
  307. CheckToken(tjsPower,'**');
  308. end;
  309. procedure TTestJSScanner.TestEq;
  310. begin
  311. CheckToken(tjsEq,'==');
  312. end;
  313. procedure TTestJSScanner.TestGE;
  314. begin
  315. CheckToken(tjsGE,'>=');
  316. end;
  317. procedure TTestJSScanner.TestLE;
  318. begin
  319. CheckToken(tjsLE,'<=');
  320. end;
  321. procedure TTestJSScanner.TestLSHIFT;
  322. begin
  323. CheckToken(tjsLShift,'<<');
  324. end;
  325. procedure TTestJSScanner.TestLSHIFTEQ;
  326. begin
  327. CheckToken(tjsLShiftEq,'<<=');
  328. end;
  329. procedure TTestJSScanner.TestMinusEQ;
  330. begin
  331. CheckToken(tjsMinusEq,'-=');
  332. end;
  333. procedure TTestJSScanner.TestMinusMinus;
  334. begin
  335. CheckToken(tjsMinusMinus,'--');
  336. end;
  337. procedure TTestJSScanner.TestModeq;
  338. begin
  339. CheckToken(tjsModeq,'%=');
  340. end;
  341. procedure TTestJSScanner.TestDiveq;
  342. begin
  343. CheckToken(tjsDiveq,'/=');
  344. end;
  345. procedure TTestJSScanner.TestXor;
  346. begin
  347. CheckToken(tjsXOR,'^');
  348. end;
  349. procedure TTestJSScanner.TestXoreq;
  350. begin
  351. CheckToken(tjsXOREQ,'^=');
  352. end;
  353. procedure TTestJSScanner.TestNE;
  354. begin
  355. CheckToken(tjsNE,'!=');
  356. end;
  357. procedure TTestJSScanner.TestInv;
  358. begin
  359. CheckToken(tjsInv,'~');
  360. end;
  361. procedure TTestJSScanner.TestNot;
  362. begin
  363. CheckToken(tjsNot,'!');
  364. end;
  365. procedure TTestJSScanner.TestTrue;
  366. begin
  367. CheckToken(tjsTrue,'true');
  368. end;
  369. procedure TTestJSScanner.TestFalse;
  370. begin
  371. CheckToken(tjsFalse,'false');
  372. end;
  373. procedure TTestJSScanner.TestOREQ;
  374. begin
  375. CheckToken(tjsOREQ,'|=');
  376. end;
  377. procedure TTestJSScanner.TestOROR;
  378. begin
  379. CheckToken(tjsOROR,'||');
  380. end;
  381. procedure TTestJSScanner.TestPlusEq;
  382. begin
  383. CheckToken(tjsPlusEq,'+=');
  384. end;
  385. procedure TTestJSScanner.TestPlusPlus;
  386. begin
  387. CheckToken(tjsPlusPlus,'++');
  388. end;
  389. procedure TTestJSScanner.TestURShift;
  390. begin
  391. CheckToken(tjsURSHIFT,'>>>');
  392. end;
  393. procedure TTestJSScanner.TestURShiftEq;
  394. begin
  395. CheckToken(tjsURSHIFTEQ,'>>>=');
  396. end;
  397. procedure TTestJSScanner.TestArrow;
  398. begin
  399. CheckToken(tjsArrow,'=>');
  400. end;
  401. procedure TTestJSScanner.TestEllipsis;
  402. begin
  403. CheckToken(tjsEllipsis,'...');
  404. end;
  405. procedure TTestJSScanner.TestAwaitECMA5;
  406. begin
  407. CheckToken(tjsIdentifier,'await');
  408. end;
  409. procedure TTestJSScanner.TestAwaitECMA2021;
  410. begin
  411. CheckToken(tjsAwait,'await',ecma2021);
  412. end;
  413. procedure TTestJSScanner.TestRShift;
  414. begin
  415. CheckToken(tjsRSHIFT,'>>');
  416. end;
  417. procedure TTestJSScanner.TestRShiftEq;
  418. begin
  419. CheckToken(tjsRSHIFTEQ,'>>=');
  420. end;
  421. procedure TTestJSScanner.TestSEq;
  422. begin
  423. CheckToken(tjsSEQ,'===');
  424. end;
  425. procedure TTestJSScanner.TestNSE;
  426. begin
  427. CheckToken(tjsSNE,'!==');
  428. end;
  429. procedure TTestJSScanner.TestStarEq;
  430. begin
  431. CheckToken(tjsMulEq,'*=');
  432. end;
  433. procedure TTestJSScanner.TestBreak;
  434. begin
  435. CheckToken(tjsBreak,'break');
  436. end;
  437. procedure TTestJSScanner.TestCase;
  438. begin
  439. CheckToken(tjscase,'case');
  440. end;
  441. procedure TTestJSScanner.TestCatch;
  442. begin
  443. CheckToken(tjscatch,'catch');
  444. end;
  445. procedure TTestJSScanner.TestClassECMA5;
  446. begin
  447. CheckToken(tjsIdentifier,'class');
  448. end;
  449. procedure TTestJSScanner.TestClassECMA2021;
  450. begin
  451. CheckToken(tjsClass,'class',ecma2021);
  452. end;
  453. procedure TTestJSScanner.TestConstECMA5;
  454. begin
  455. CheckToken(tjsIdentifier,'const');
  456. end;
  457. procedure TTestJSScanner.TestConstECMA2021;
  458. begin
  459. CheckToken(tjsConst,'const',ecma2021);
  460. end;
  461. procedure TTestJSScanner.TestContinue;
  462. begin
  463. CheckToken(tjscontinue,'continue');
  464. end;
  465. procedure TTestJSScanner.TestDebuggerECMA5;
  466. begin
  467. CheckToken(tjsidentifier,'debugger');
  468. end;
  469. procedure TTestJSScanner.TestDebuggerECMA2021;
  470. begin
  471. CheckToken(tjsDebugger,'debugger',ecma2021);
  472. end;
  473. procedure TTestJSScanner.TestDefault;
  474. begin
  475. CheckToken(tjsdefault,'default');
  476. end;
  477. procedure TTestJSScanner.TestDelete;
  478. begin
  479. CheckToken(tjsdelete,'delete');
  480. end;
  481. procedure TTestJSScanner.TestDO;
  482. begin
  483. CheckToken(tjsdo,'do');
  484. end;
  485. procedure TTestJSScanner.TestElse;
  486. begin
  487. CheckToken(tjselse,'else');
  488. end;
  489. procedure TTestJSScanner.TestEnumECMA5;
  490. begin
  491. CheckToken(tjsIdentifier,'enum');
  492. end;
  493. procedure TTestJSScanner.TestEnumECMA2021;
  494. begin
  495. CheckToken(tjsenum,'enum',ecma2021);
  496. end;
  497. procedure TTestJSScanner.TestExportECMA5;
  498. begin
  499. CheckToken(tjsIdentifier,'export');
  500. end;
  501. procedure TTestJSScanner.TestExportECMA2021;
  502. begin
  503. CheckToken(tjsexport,'export',ecma2021);
  504. end;
  505. procedure TTestJSScanner.TestExtendsECMA5;
  506. begin
  507. CheckToken(tjsIdentifier,'extends');
  508. end;
  509. procedure TTestJSScanner.TestExtendsECMA2021;
  510. begin
  511. CheckToken(tjsextends,'extends',ecma2021);
  512. end;
  513. procedure TTestJSScanner.TestFinally;
  514. begin
  515. CheckToken(tjsfinally,'finally');
  516. end;
  517. procedure TTestJSScanner.TestFor;
  518. begin
  519. CheckToken(tjsfor,'for');
  520. end;
  521. procedure TTestJSScanner.TestFunction;
  522. begin
  523. CheckToken(tjsfunction,'function');
  524. end;
  525. procedure TTestJSScanner.TestIf;
  526. begin
  527. CheckToken(tjsif,'if');
  528. end;
  529. procedure TTestJSScanner.TestImportECMA5;
  530. begin
  531. CheckToken(tjsIdentifier,'import');
  532. end;
  533. procedure TTestJSScanner.TestImportECMA2021;
  534. begin
  535. CheckToken(tjsImport,'import',ecma2021);
  536. end;
  537. procedure TTestJSScanner.TestIn;
  538. begin
  539. CheckToken(tjsin,'in');
  540. end;
  541. procedure TTestJSScanner.TestInstanceOf;
  542. begin
  543. CheckToken(tjsinstanceof,'instanceof');
  544. end;
  545. procedure TTestJSScanner.TestLetECMA5;
  546. begin
  547. CheckToken(tjsIdentifier,'let');
  548. end;
  549. procedure TTestJSScanner.TestLetECMA2021;
  550. begin
  551. CheckToken(tjsLet,'let',ecma2021);
  552. end;
  553. procedure TTestJSScanner.TestNew;
  554. begin
  555. CheckToken(tjsnew,'new');
  556. end;
  557. procedure TTestJSScanner.TestReturn;
  558. begin
  559. CheckToken(tjsreturn,'return');
  560. end;
  561. procedure TTestJSScanner.TestSuperECMA5;
  562. begin
  563. CheckToken(tjsIdentifier,'super');
  564. end;
  565. procedure TTestJSScanner.TestSuperECMA2021;
  566. begin
  567. CheckToken(tjsSuper,'super',ecma2021);
  568. end;
  569. procedure TTestJSScanner.TestSwitch;
  570. begin
  571. CheckToken(tjsswitch,'switch');
  572. end;
  573. procedure TTestJSScanner.TestThis;
  574. begin
  575. CheckToken(tjsThis,'this');
  576. end;
  577. procedure TTestJSScanner.TestThrow;
  578. begin
  579. CheckToken(tjsThrow,'throw');
  580. end;
  581. procedure TTestJSScanner.TestTry;
  582. begin
  583. CheckToken(tjsTry,'try');
  584. end;
  585. procedure TTestJSScanner.TestTypeOf;
  586. begin
  587. CheckToken(tjstypeof,'typeof');
  588. end;
  589. procedure TTestJSScanner.TestVar;
  590. begin
  591. CheckToken(tjsvar,'var');
  592. end;
  593. procedure TTestJSScanner.TestVoid;
  594. begin
  595. CheckToken(tjsvoid,'void');
  596. end;
  597. procedure TTestJSScanner.TestWhile;
  598. begin
  599. CheckToken(tjswhile,'while');
  600. end;
  601. procedure TTestJSScanner.TestWith;
  602. begin
  603. CheckToken(tjswith,'with');
  604. end;
  605. procedure TTestJSScanner.TestYieldECMA5;
  606. begin
  607. CheckToken(tjsIdentifier,'yield');
  608. end;
  609. procedure TTestJSScanner.TestYieldECMA2021;
  610. begin
  611. CheckToken(tjsYield,'yield',ecma2021);
  612. end;
  613. procedure TTestJSScanner.CheckTokens(ASource: TJSScannerString;
  614. ATokens: array of TJSToken; aVersion: TECMAVersion);
  615. Var
  616. I : Integer;
  617. J : TJSToken;
  618. S : String;
  619. begin
  620. CreateScanner(ASource,aVersion);
  621. For I:=Low(ATokens) to High(ATokens) do
  622. begin
  623. J:=FScanner.FetchToken;
  624. S:=GetEnumName(TypeINfo(TJSToken),Ord(ATokens[i]));
  625. S:=Format('Source "%s", token %d (%s): expected %s',[ASource,I,FScanner.CurTokenString,S]);
  626. AssertEquals(S,ATokens[i],J);
  627. end;
  628. end;
  629. procedure TTestJSScanner.Test2Words;
  630. begin
  631. CheckTokens('with do',[tjsWith,tjsDo]);
  632. end;
  633. procedure TTestJSScanner.Test3Words;
  634. begin
  635. CheckTokens('with do for',[tjsWith,tjsDo,tjsFor]);
  636. end;
  637. procedure TTestJSScanner.TestIdentifier;
  638. begin
  639. CheckToken(tjsIdentifier,'something');
  640. AssertEquals('Correct identifier','something',FScanner.CurTokenString);
  641. end;
  642. procedure TTestJSScanner.TestIdentifier2;
  643. begin
  644. CheckToken(tjsIdentifier,'_something');
  645. AssertEquals('Correct identifier','_something',FScanner.CurTokenString);
  646. end;
  647. procedure TTestJSScanner.TestIdentifier3;
  648. begin
  649. CheckToken(tjsIdentifier,'$');
  650. AssertEquals('Correct identifier','$',FScanner.CurTokenString);
  651. end;
  652. procedure TTestJSScanner.TestIdentifier4;
  653. begin
  654. CheckToken(tjsIdentifier,'_0');
  655. AssertEquals('Correct identifier','_0',FScanner.CurTokenString);
  656. end;
  657. procedure TTestJSScanner.TestIdentifier5;
  658. begin
  659. CheckToken(tjsIdentifier,'$0');
  660. AssertEquals('Correct identifier','$0',FScanner.CurTokenString);
  661. end;
  662. procedure TTestJSScanner.TestIdentifierDotIdentifier;
  663. begin
  664. CheckTokens('something.different',[tjsIdentifier,tjsdot,tjsIdentifier]);
  665. // AssertEquals('Correct identifier','something',FScanner.CurTokenString);
  666. end;
  667. procedure TTestJSScanner.TestEOLN;
  668. begin
  669. CreateScanner('something');
  670. FScanner.FetchToken;
  671. AssertEquals('Got to end of line after reading single token at EOF',True,FScanner.IsEndOfLine);
  672. // AssertEquals('Correct identifier','something',FScanner.CurTokenString);
  673. end;
  674. procedure TTestJSScanner.TestEOLN2;
  675. begin
  676. CreateScanner('something different');
  677. FScanner.FetchToken;
  678. AssertEquals('Not yet end of line after reading single token at EOF',False,FScanner.IsEndOfLine);
  679. end;
  680. procedure TTestJSScanner.TestEOLN3;
  681. begin
  682. CreateScanner('something'#13#10'different');
  683. FScanner.FetchToken;
  684. AssertEquals('End of line after reading single token',True,FScanner.IsEndOfLine);
  685. end;
  686. procedure TTestJSScanner.TestEOLN4;
  687. begin
  688. CreateScanner('something'#10'different');
  689. FScanner.FetchToken;
  690. AssertEquals('End of line after reading first token',True,FScanner.IsEndOfLine);
  691. FScanner.FetchToken;
  692. AssertEquals('End of line after reading second token',True,FScanner.IsEndOfLine);
  693. end;
  694. procedure TTestJSScanner.TestComment1;
  695. begin
  696. CreateScanner('// some comment string');
  697. AssertEquals('Comment line is skipped',tjsEOF,FScanner.FetchToken);
  698. end;
  699. procedure TTestJSScanner.TestComment2;
  700. begin
  701. CreateScanner('// some comment string');
  702. FScanner.ReturnComments:=True;
  703. AssertEquals('Comment line is returned',tjsComment,FScanner.FetchToken);
  704. AssertEquals('Comment contents is returned',' some comment string',FScanner.CurTokenString);
  705. end;
  706. procedure TTestJSScanner.TestComment3;
  707. begin
  708. CreateScanner('/* some comment string */');
  709. AssertEquals('Comment line is skipped',tjsEOF,FScanner.FetchToken);
  710. end;
  711. procedure TTestJSScanner.TestComment4;
  712. begin
  713. CreateScanner('/* some comment string */');
  714. FScanner.ReturnComments:=True;
  715. AssertEquals('Comment line is returned',tjsComment,FScanner.FetchToken);
  716. AssertEquals('Comment contents is returned',' some comment string ',FScanner.CurTokenString);
  717. end;
  718. procedure TTestJSScanner.TestComment5;
  719. begin
  720. CreateScanner('/* some nested comment // string */');
  721. FScanner.ReturnComments:=True;
  722. AssertEquals('Comment line is returned',tjsComment,FScanner.FetchToken);
  723. AssertEquals('Comment contents is returned',' some nested comment // string ',FScanner.CurTokenString);
  724. end;
  725. procedure TTestJSScanner.TestComment6;
  726. begin
  727. CreateScanner('// /* some nested comment string */');
  728. FScanner.ReturnComments:=True;
  729. AssertEquals('Comment line is returned',tjsComment,FScanner.FetchToken);
  730. AssertEquals('Comment contents is returned',' /* some nested comment string */',FScanner.CurTokenString);
  731. end;
  732. procedure TTestJSScanner.TearDown;
  733. begin
  734. FreeScanner;
  735. Inherited;
  736. end;
  737. procedure TTestJSScanner.DoTestFloat(F : Double);
  738. Var
  739. S : String;
  740. begin
  741. Str(F,S);
  742. DoTestFloat(F,S);
  743. end;
  744. procedure TTestJSScanner.DoTestFloat(F : Double; S : String);
  745. Var
  746. J : TJSToken;
  747. C : Double;
  748. I : integer;
  749. V : String;
  750. begin
  751. CreateScanner(S);
  752. try
  753. J:=FScanner.FetchToken;
  754. AssertEquals(S+' is a number',tjsNumber,J);
  755. V:=FScanner.CurTokenString;
  756. If (Copy(V,1,2)='0x') then
  757. begin
  758. Flush(output);
  759. V:='$'+Copy(V,3,Length(V)-2);
  760. C:=StrToInt(V);
  761. end
  762. else
  763. begin
  764. Val(V,C,I);
  765. If (I<>0) then
  766. Fail(FScanner.CurTokenString+' does not contain a float value');
  767. end;
  768. AssertEquals('Parsed float equals original float',F,C);
  769. finally
  770. FreeScanner;
  771. end;
  772. end;
  773. procedure TTestJSScanner.TestFloat;
  774. begin
  775. DoTestFloat(1.2);
  776. DoTestFloat(-1.2);
  777. DoTestFloat(0);
  778. DoTestFloat(1.2e1);
  779. DoTestFloat(-1.2e1);
  780. DoTestFloat(0);
  781. DoTestFloat(1.2,'1.2');
  782. DoTestFloat(-1.2,'-1.2');
  783. DoTestFloat(0,'0.0');
  784. DoTestFloat(255,'0xff')
  785. end;
  786. procedure TTestJSScanner.TestFloatError;
  787. begin
  788. FErrorSource:='1xz';
  789. AssertException('Wrong float',EJSScannerError,@TestErrorSource);
  790. end;
  791. procedure TTestJSScanner.DoTestString(S: String; WasMultiline : Boolean = False);
  792. Var
  793. J : TJSToken;
  794. begin
  795. CreateScanner(S);
  796. try
  797. J:=FScanner.FetchToken;
  798. AssertEquals(S+' is a string',tjsString,J);
  799. If (Length(S)>0) and (S[1] in ['"','''','`']) then
  800. S:=Copy(S,2,Length(S)-2);
  801. AssertEquals('Correct string is returned',S,FScanner.CurTokenString);
  802. AssertEquals('Multiline ?',WasMultiline,FScanner.WasMultilineString);
  803. finally
  804. FreeScanner;
  805. end;
  806. end;
  807. procedure TTestJSScanner.TestString;
  808. begin
  809. DoTestString('"A string"');
  810. DoTestString('""');
  811. DoTestString('''''');
  812. DoTestString('''A string''');
  813. end;
  814. procedure TTestJSScanner.TestErrorSource;
  815. begin
  816. CreateScanner(FErrorSource);
  817. try
  818. While (FScanner.FetchToken<>tjsEOF) do ;
  819. finally
  820. FreeScanner;
  821. end;
  822. end;
  823. procedure TTestJSScanner.TestStringError;
  824. begin
  825. FErrorSource:='"A string';
  826. AssertException('Unterminated string',EJSScannerError,@TestErrorSource);
  827. FErrorSource:='''A string';
  828. AssertException('Unterminated string',EJSScannerError,@TestErrorSource);
  829. end;
  830. procedure TTestJSScanner.TestMultilineString;
  831. begin
  832. DoTestString('`A'#10'B`',True);
  833. end;
  834. procedure TTestJSScanner.TestMultilineStringError;
  835. begin
  836. FErrorSource:='`A'#10;
  837. AssertException('Unterminated string',EJSScannerError,@TestErrorSource);
  838. end;
  839. procedure TTestJSScanner.TestMultilineStringError2;
  840. begin
  841. FErrorSource:='`A'#10'B';
  842. AssertException('Unterminated string',EJSScannerError,@TestErrorSource);
  843. end;
  844. procedure TTestJSScanner.TestNonBreakingSpace;
  845. begin
  846. NeedWhiteSpace:=True;
  847. CheckToken(tjsWhiteSpace,#$C2#$A0);
  848. end;
  849. { TTestLineReader }
  850. procedure TTestLineReader.CreateReader(AInput: String);
  851. begin
  852. FData:=TStringStream.Create(AInput);
  853. FReader:=TStreamLineReader.Create(FData);
  854. end;
  855. procedure TTestLineReader.TearDown;
  856. begin
  857. FreeAndNil(FReader);
  858. FreeAndNil(FData);
  859. end;
  860. procedure TTestLineReader.TestEmpty;
  861. begin
  862. CreateReader('');
  863. AssertEquals('Empty reader returns EOF',True,FReader.IsEOF);
  864. AssertEquals('Empty reader returns empty string','',FReader.ReadLine);
  865. end;
  866. procedure TTestLineReader.TestReadLine;
  867. begin
  868. CreateReader('Something');
  869. AssertEquals('Reader with 1 line returns 1 line','Something',FReader.ReadLine);
  870. AssertEquals('EOF true after reading line',True,FReader.IsEOF);
  871. end;
  872. procedure TTestLineReader.TestReadLines13;
  873. begin
  874. CreateReader('Something'#13'else');
  875. AssertEquals('Reader with 2 lines returns 1st line','Something',FReader.ReadLine);
  876. AssertEquals('Reader with 2 lines returns 2nd line','else',FReader.ReadLine);
  877. AssertEquals('EOF true after reading lines',True,FReader.IsEOF);
  878. end;
  879. procedure TTestLineReader.TestReadLines10;
  880. begin
  881. CreateReader('Something'#10'else');
  882. AssertEquals('Reader with 2 lines returns 1st line','Something',FReader.ReadLine);
  883. AssertEquals('Reader with 2 lines returns 2nd line','else',FReader.ReadLine);
  884. AssertEquals('EOF true after reading lines',True,FReader.IsEOF);
  885. end;
  886. procedure TTestLineReader.TestReadLines1310;
  887. begin
  888. CreateReader('Something'#13#10'else');
  889. AssertEquals('Reader with 2 lines returns 1st line','Something',FReader.ReadLine);
  890. AssertEquals('Reader with 2 lines returns 2nd line','else',FReader.ReadLine);
  891. AssertEquals('EOF true after reading lines',True,FReader.IsEOF);
  892. end;
  893. procedure TTestLineReader.TestReadLinesEOF13;
  894. begin
  895. CreateReader('Something'#13);
  896. AssertEquals('Reader with 2 lines + CR returns 1st line','Something',FReader.ReadLine);
  897. AssertEquals('Reader with 1 lines + CR returns empty 2nd line','',FReader.ReadLine);
  898. AssertEquals('EOF true after reading lines',True,FReader.IsEOF);
  899. end;
  900. procedure TTestLineReader.TestReadLinesEOF10;
  901. begin
  902. CreateReader('Something'#10);
  903. AssertEquals('Reader with 2 lines + LF returns 1st line','Something',FReader.ReadLine);
  904. AssertEquals('Reader with 1 lines + LF returns empty 2nd line','',FReader.ReadLine);
  905. AssertEquals('EOF true after reading lines',True,FReader.IsEOF);
  906. end;
  907. procedure TTestLineReader.TestReadLinesEOF1310;
  908. begin
  909. CreateReader('Something'#13#10);
  910. AssertEquals('Reader with 2 lines + CRLF returns 1st line','Something',FReader.ReadLine);
  911. AssertEquals('Reader with 1 lines + CRLF returns empty 2nd line','',FReader.ReadLine);
  912. AssertEquals('EOF true after reading lines',True,FReader.IsEOF);
  913. end;
  914. procedure TTestLineReader.TestReadEmptyLines101010;
  915. begin
  916. CreateReader('Something'#10#10#10);
  917. AssertEquals('Reader with 1 line + LFLFLF returns 1st line','Something',FReader.ReadLine);
  918. AssertEquals('EOF false after reading line 1',False,FReader.IsEOF);
  919. AssertEquals('Reader with 1 line + LFLFLF returns empty 2nd line','',FReader.ReadLine);
  920. AssertEquals('EOF false after reading line 2',False,FReader.IsEOF);
  921. AssertEquals('Reader with 1 line + LFLFLF returns empty 3nd line','',FReader.ReadLine);
  922. AssertEquals('EOF true after reading lines',True,FReader.IsEOF);
  923. end;
  924. initialization
  925. RegisterTests([TTestLineReader,TTestJSScanner]);
  926. end.