jsscanner.pp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. {
  2. This file is part of the Free Component Library
  3. ECMAScript (JavaScript) source lexical scanner
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {$mode objfpc}
  11. {$h+}
  12. unit JSScanner;
  13. interface
  14. uses SysUtils, Classes, jstoken;
  15. resourcestring
  16. SErrInvalidCharacter = 'Invalid character ''%s''';
  17. SErrOpenString = 'string exceeds end of line';
  18. SErrIncludeFileNotFound = 'Could not find include file ''%s''';
  19. SErrIfXXXNestingLimitReached = 'Nesting of $IFxxx too deep';
  20. SErrInvalidPPElse = '$ELSE without matching $IFxxx';
  21. SErrInvalidPPEndif = '$ENDIF without matching $IFxxx';
  22. SInvalidHexadecimalNumber = 'Invalid decimal number';
  23. SErrInvalidNonEqual = 'Syntax Error: != or !== expected';
  24. SErrInvalidRegularExpression = 'Syntax error in regular expression: / expected, got: %s';
  25. Type
  26. TLineReader = class
  27. public
  28. function IsEOF: Boolean; virtual; abstract;
  29. function ReadLine: string; virtual; abstract;
  30. end;
  31. { TStreamLineReader }
  32. TStreamLineReader = class(TLineReader)
  33. private
  34. FStream : TStream;
  35. Buffer : Array[0..1024] of Byte;
  36. FBufPos,
  37. FBufLen : Integer;
  38. procedure FillBuffer;
  39. public
  40. Constructor Create(AStream : TStream);
  41. function IsEOF: Boolean; override;
  42. function ReadLine: string; override;
  43. end;
  44. TFileLineReader = class(TLineReader)
  45. private
  46. FTextFile: Text;
  47. FileOpened: Boolean;
  48. public
  49. constructor Create(const AFilename: string);
  50. destructor Destroy; override;
  51. function IsEOF: Boolean; override;
  52. function ReadLine: string; override;
  53. end;
  54. EJSScannerError = class(Exception);
  55. { TJSScanner }
  56. TJSScanner = class
  57. private
  58. FReturnComments: Boolean;
  59. FReturnWhiteSpace: Boolean;
  60. FSourceFile: TLineReader;
  61. FSourceFilename: string;
  62. FCurRow: Integer;
  63. FCurToken: TJSToken;
  64. FCurTokenString: string;
  65. FCurLine: string;
  66. TokenStr: PChar;
  67. FWasEndOfLine : Boolean;
  68. FSourceStream : TStream;
  69. FOwnSourceFile : Boolean;
  70. function CommentDiv: TJSToken;
  71. function DoIdentifier : TJSToken;
  72. function DoMultiLineComment: TJSToken;
  73. function DoNumericLiteral: TJSToken;
  74. function DoSingleLineComment: TJSToken;
  75. function DoStringLiteral: TJSToken;
  76. function DoWhiteSpace: TJSToken;
  77. function FetchLine: Boolean;
  78. function GetCurColumn: Integer;
  79. function ReadUnicodeEscape: WideChar;
  80. Function ReadRegex : TJSToken;
  81. protected
  82. procedure Error(const Msg: string);overload;
  83. procedure Error(const Msg: string; Args: array of Const);overload;
  84. public
  85. constructor Create(ALineReader: TLineReader);
  86. constructor Create(AStream : TStream);
  87. destructor Destroy; override;
  88. procedure OpenFile(const AFilename: string);
  89. Function FetchRegexprToken: TJSToken;
  90. Function FetchToken: TJSToken;
  91. Function IsEndOfLine : Boolean;
  92. Property WasEndOfLine : Boolean Read FWasEndOfLine;
  93. Property ReturnComments : Boolean Read FReturnComments Write FReturnComments;
  94. Property ReturnWhiteSpace : Boolean Read FReturnWhiteSpace Write FReturnWhiteSpace;
  95. property SourceFile: TLineReader read FSourceFile;
  96. property CurFilename: string read FSourceFilename;
  97. property CurLine: string read FCurLine;
  98. property CurRow: Integer read FCurRow;
  99. property CurColumn: Integer read GetCurColumn;
  100. property CurToken: TJSToken read FCurToken;
  101. property CurTokenString: string read FCurTokenString;
  102. end;
  103. implementation
  104. constructor TFileLineReader.Create(const AFilename: string);
  105. begin
  106. inherited Create;
  107. Assign(FTextFile, AFilename);
  108. Reset(FTextFile);
  109. FileOpened := true;
  110. end;
  111. destructor TFileLineReader.Destroy;
  112. begin
  113. if FileOpened then
  114. Close(FTextFile);
  115. inherited Destroy;
  116. end;
  117. function TFileLineReader.IsEOF: Boolean;
  118. begin
  119. Result := EOF(FTextFile);
  120. end;
  121. function TFileLineReader.ReadLine: string;
  122. begin
  123. ReadLn(FTextFile, Result);
  124. end;
  125. constructor TJSScanner.Create(ALineReader: TLineReader);
  126. begin
  127. inherited Create;
  128. FSourceFile := ALineReader;
  129. end;
  130. constructor TJSScanner.Create(AStream: TStream);
  131. begin
  132. FSourceStream:=ASTream;
  133. FOwnSourceFile:=True;
  134. Create(TStreamLineReader.Create(AStream));
  135. end;
  136. destructor TJSScanner.Destroy;
  137. begin
  138. If FOwnSourceFile then
  139. FSourceFile.Free;
  140. inherited Destroy;
  141. end;
  142. procedure TJSScanner.OpenFile(const AFilename: string);
  143. begin
  144. FSourceFile := TFileLineReader.Create(AFilename);
  145. FSourceFilename := AFilename;
  146. end;
  147. Function TJSScanner.FetchRegexprToken: TJSToken;
  148. begin
  149. if (CurToken in [tjsDiv,tjsDivEq]) then
  150. Result:=ReadRegEx
  151. else
  152. Result:=CurToken
  153. end;
  154. procedure TJSScanner.Error(const Msg: string);
  155. begin
  156. raise EJSScannerError.Create(Msg);
  157. end;
  158. procedure TJSScanner.Error(const Msg: string; Args: array of Const);
  159. begin
  160. raise EJSScannerError.CreateFmt(Msg, Args);
  161. end;
  162. function TJSScanner.FetchLine: Boolean;
  163. begin
  164. if FSourceFile.IsEOF then
  165. begin
  166. FCurLine := '';
  167. TokenStr := nil;
  168. Result := false;
  169. end else
  170. begin
  171. FCurLine := FSourceFile.ReadLine;
  172. TokenStr := PChar(CurLine);
  173. Result := true;
  174. Inc(FCurRow);
  175. FWasEndofLine:=True;
  176. end;
  177. end;
  178. function TJSScanner.DoWhiteSpace : TJSToken;
  179. begin
  180. Result:=tjsWhitespace;
  181. repeat
  182. Inc(TokenStr);
  183. if TokenStr[0] = #0 then
  184. if not FetchLine then
  185. begin
  186. FCurToken := Result;
  187. exit;
  188. end;
  189. until not (TokenStr[0] in [#9, ' ']);
  190. end;
  191. function TJSScanner.DoSingleLineComment : TJSToken;
  192. Var
  193. TokenStart : PChar;
  194. Len : Integer;
  195. begin
  196. Inc(TokenStr);
  197. TokenStart := TokenStr;
  198. while TokenStr[0] <> #0 do
  199. Inc(TokenStr);
  200. Len:=TokenStr-TokenStart;
  201. SetLength(FCurTokenString, Len);
  202. if (Len>0) then
  203. Move(TokenStart^,FCurTokenString[1],Len);
  204. Result := tjsComment;
  205. end;
  206. function TJSScanner.DoMultiLineComment : TJSToken;
  207. Var
  208. TokenStart : PChar;
  209. Len,OLen : Integer;
  210. PrevToken : Char;
  211. begin
  212. Inc(TokenStr);
  213. TokenStart := TokenStr;
  214. FCurTokenString := '';
  215. OLen:= 0;
  216. PrevToken:=#0;
  217. while Not ((TokenStr[0]='/') and (PrevToken='*')) do
  218. begin
  219. if (TokenStr[0]=#0) then
  220. begin
  221. Len:=TokenStr-TokenStart+1;
  222. SetLength(FCurTokenString,OLen+Len);
  223. if Len>1 then
  224. Move(TokenStart^,FCurTokenString[OLen+1],Len-1);
  225. Inc(OLen,Len);
  226. FCurTokenString[OLen]:=#10;
  227. if not FetchLine then
  228. begin
  229. Result := tjsEOF;
  230. FCurToken := Result;
  231. exit;
  232. end;
  233. TokenStart := TokenStr;
  234. PrevToken:=#0;
  235. end
  236. else
  237. begin
  238. PrevToken:=TokenStr[0];
  239. Inc(TokenStr);
  240. end;
  241. end;
  242. Len:=TokenStr-TokenStart-1; // -1 for *
  243. SetLength(FCurTokenString, Olen+Len);
  244. if (Len>0) then
  245. Move(TokenStart^, FCurTokenString[Olen + 1], Len);
  246. Inc(TokenStr);
  247. Result := tjsComment;
  248. end;
  249. function TJSScanner.CommentDiv : TJSToken;
  250. begin
  251. FCurTokenString := '';
  252. Inc(TokenStr);
  253. if (TokenStr[0] = '/') then // Single-line comment
  254. Result:=DoSingleLineComment
  255. else if (TokenStr[0]='*') then
  256. Result:=DoMultiLineComment
  257. else if (TokenStr[0] = '=') then // Single-line comment
  258. begin
  259. Result:=tjsDiveQ;
  260. Inc(TokenStr)
  261. end
  262. else
  263. Result:=tjsDiv;
  264. end;
  265. function TJSScanner.ReadUnicodeEscape: WideChar;
  266. Var
  267. S : String;
  268. I : Integer;
  269. begin
  270. S:='0000';
  271. For I:=1 to 4 do
  272. begin
  273. Inc(TokenStr);
  274. Case TokenStr[0] of
  275. '0'..'9','A'..'F','a'..'f' :
  276. S[i]:=Upcase(TokenStr[0]);
  277. else
  278. Error(SErrInvalidCharacter, [TokenStr[0]]);
  279. end;
  280. end;
  281. // Takes care of conversion... This needs improvement !!
  282. Result:=WideChar(StrToInt('$'+S));
  283. end;
  284. Function TJSScanner.ReadRegex: TJSToken;
  285. Var
  286. CC : Boolean; // Character class
  287. Done : Boolean;
  288. CL,L : Integer;
  289. TokenStart : PChar;
  290. begin
  291. if (CurToken<>tjsDivEq) then
  292. FCurTokenString := '/'
  293. else
  294. FCurTokenString := '/=';
  295. CL:=Length(FCurTokenString);
  296. Inc(TokenStr);
  297. TokenStart:=TokenStr;
  298. Done:=False;
  299. CC:=False;
  300. While Not Done do
  301. begin
  302. Case TokenStr[0] of
  303. #0 : Done:=True;
  304. '/' : Done:=Not CC;
  305. '\' : begin
  306. Inc(TokenStr);
  307. Done:=TokenStr=#0;
  308. end;
  309. '[' : CC:=True;
  310. ']' : CC:=False;
  311. end;
  312. if not Done then
  313. Inc(TokenStr);
  314. end;
  315. If (TokenStr[0]<>'/') then
  316. Error(SErrInvalidRegularExpression, [TokenStr[0]]);
  317. repeat
  318. Inc(TokenStr);
  319. until not (TokenStr[0] in ['A'..'Z', 'a'..'z', '0'..'9', '_','$']);
  320. L:=(TokenStr-TokenStart);
  321. SetLength(FCurTokenString,CL+L);
  322. Move(TokenStart^,FCurTokenString[CL+1],L);
  323. Result:=tjsRegEx;
  324. end;
  325. function TJSScanner.DoStringLiteral: TJSToken;
  326. Var
  327. Delim : Char;
  328. TokenStart : PChar;
  329. Len,OLen: Integer;
  330. S : String;
  331. begin
  332. Delim:=TokenStr[0];
  333. Inc(TokenStr);
  334. TokenStart := TokenStr;
  335. OLen := 0;
  336. FCurTokenString := '';
  337. while not (TokenStr[0] in [#0,Delim]) do
  338. begin
  339. if (TokenStr[0]='\') then
  340. begin
  341. // Save length
  342. Len := TokenStr - TokenStart;
  343. Inc(TokenStr);
  344. // Read escaped token
  345. Case TokenStr[0] of
  346. '"' : S:='"';
  347. '''' : S:='''';
  348. 't' : S:=#9;
  349. 'b' : S:=#8;
  350. 'n' : S:=#10;
  351. 'r' : S:=#13;
  352. 'f' : S:=#12;
  353. '\' : S:='\';
  354. '/' : S:='/';
  355. 'u' : begin
  356. S:=ReadUniCodeEscape;
  357. end;
  358. #0 : Error(SErrOpenString);
  359. else
  360. Error(SErrInvalidCharacter, [TokenStr[0]]);
  361. end;
  362. SetLength(FCurTokenString, OLen + Len+1+Length(S));
  363. if Len > 0 then
  364. Move(TokenStart^, FCurTokenString[OLen + 1], Len);
  365. Move(S[1],FCurTokenString[OLen + Len+1],Length(S));
  366. Inc(OLen, Len+Length(S));
  367. // Next char
  368. // Inc(TokenStr);
  369. TokenStart := TokenStr+1;
  370. end;
  371. if TokenStr[0] = #0 then
  372. Error(SErrOpenString);
  373. Inc(TokenStr);
  374. end;
  375. if TokenStr[0] = #0 then
  376. Error(SErrOpenString);
  377. Len := TokenStr - TokenStart;
  378. SetLength(FCurTokenString, OLen + Len);
  379. if Len > 0 then
  380. Move(TokenStart^, FCurTokenString[OLen+1], Len);
  381. Inc(TokenStr);
  382. Result := tjsString;
  383. end;
  384. function TJSScanner.DoNumericLiteral :TJSToken;
  385. Var
  386. TokenStart : PChar;
  387. Len : Integer;
  388. begin
  389. TokenStart := TokenStr;
  390. while true do
  391. begin
  392. Inc(TokenStr);
  393. case TokenStr[0] of
  394. 'x':
  395. If (TokenStart[0]='0') and ((TokenStr-TokenStart)=1) then
  396. begin
  397. Inc(TokenStr);
  398. while Upcase(TokenStr[0]) in ['0'..'9','A'..'F'] do
  399. Inc(TokenStr);
  400. end
  401. else
  402. Error(SInvalidHexadecimalNumber);
  403. '.':
  404. begin
  405. if TokenStr[1] in ['0'..'9', 'e', 'E'] then
  406. begin
  407. Inc(TokenStr);
  408. repeat
  409. Inc(TokenStr);
  410. until not (TokenStr[0] in ['0'..'9', 'e', 'E','-','+']);
  411. end;
  412. break;
  413. end;
  414. '0'..'9': ;
  415. 'e', 'E':
  416. begin
  417. Inc(TokenStr);
  418. if TokenStr[0] in ['-','+'] then
  419. Inc(TokenStr);
  420. while TokenStr[0] in ['0'..'9'] do
  421. Inc(TokenStr);
  422. break;
  423. end;
  424. else
  425. break;
  426. end;
  427. end;
  428. Len:=TokenStr-TokenStart;
  429. Setlength(FCurTokenString, Len);
  430. if (Len>0) then
  431. Move(TokenStart^,FCurTokenString[1],Len);
  432. Result := tjsNumber;
  433. end;
  434. function TJSScanner.DoIdentifier : TJSToken;
  435. Var
  436. TokenStart:PChar;
  437. Len : Integer;
  438. I : TJSToken;
  439. begin
  440. Result:=tjsIdentifier;
  441. TokenStart := TokenStr;
  442. repeat
  443. Inc(TokenStr);
  444. //If (TokenStr[0]='\') and (TokenStr[1]='u') then
  445. until not (TokenStr[0] in ['A'..'Z', 'a'..'z', '0'..'9', '_','$']);
  446. Len:=(TokenStr-TokenStart);
  447. SetLength(FCurTokenString,Len);
  448. if Len > 0 then
  449. Move(TokenStart^,FCurTokenString[1],Len);
  450. // Check if this is a keyword or identifier
  451. // !!!: Optimize this!
  452. for i:=FirstKeyword to Lastkeyword do
  453. if CurTokenString=TokenInfos[i] then
  454. begin
  455. Result := i;
  456. FCurToken := Result;
  457. exit;
  458. end;
  459. end;
  460. Function TJSScanner.FetchToken: TJSToken;
  461. begin
  462. if not (FCurtoken in [tjsWhiteSpace,tjsComment]) then
  463. FWasEndOfLine:=False;
  464. Repeat
  465. if TokenStr = nil then
  466. begin
  467. if not FetchLine then
  468. begin
  469. Result := tjsEOF;
  470. FCurToken := Result;
  471. exit;
  472. end;
  473. end;
  474. //CurPos:=TokenStr;
  475. FCurTokenString := '';
  476. case TokenStr[0] of
  477. #0: // Empty line
  478. begin
  479. FetchLine;
  480. Result := tjsWhitespace;
  481. end;
  482. '/' :
  483. Result:=CommentDiv;
  484. #9, ' ':
  485. Result := DoWhiteSpace;
  486. '''','"':
  487. Result:=DoStringLiteral;
  488. '0'..'9':
  489. Result:=DoNumericLiteral;
  490. '&':
  491. begin
  492. Inc(TokenStr);
  493. If Tokenstr[0]='&' then
  494. begin
  495. Inc(TokenStr);
  496. Result := tjsAndAnd;
  497. end
  498. else If Tokenstr[0]='=' then
  499. begin
  500. Inc(TokenStr);
  501. Result := tjsAndEQ;
  502. end
  503. else
  504. Result := tjsAnd;
  505. end;
  506. '%':
  507. begin
  508. Inc(TokenStr);
  509. If Tokenstr[0]='=' then
  510. begin
  511. Inc(TokenStr);
  512. Result := tjsModEq;
  513. end
  514. else
  515. Result := tjsMod;
  516. end;
  517. '^':
  518. begin
  519. Inc(TokenStr);
  520. If (TokenStr[0]='=') then
  521. begin
  522. Result:=tjsXorEq;
  523. Inc(tokenStr)
  524. end
  525. else
  526. result:=tjsXOR;
  527. end;
  528. '|':
  529. begin
  530. Inc(TokenStr);
  531. If Tokenstr[0]='|' then
  532. begin
  533. Inc(TokenStr);
  534. Result := tjsOROR;
  535. end
  536. else If Tokenstr[0]='=' then
  537. begin
  538. Inc(TokenStr);
  539. Result := tjsOREQ;
  540. end
  541. else
  542. Result := tjsOR;
  543. end;
  544. '(':
  545. begin
  546. Inc(TokenStr);
  547. Result := tjsBraceOpen;
  548. end;
  549. ')':
  550. begin
  551. Inc(TokenStr);
  552. Result := tjsBraceClose;
  553. end;
  554. '*':
  555. begin
  556. Inc(TokenStr);
  557. If (TokenStr[0]='=') then
  558. begin
  559. Inc(TokenStr);
  560. Result := tjsMulEq;
  561. end
  562. else
  563. Result := tjsMul;
  564. end;
  565. '+':
  566. begin
  567. Inc(TokenStr);
  568. If (TokenStr[0]='=') then
  569. begin
  570. Inc(TokenStr);
  571. Result := tjsPlusEq;
  572. end
  573. else If (TokenStr[0]='+') then
  574. begin
  575. Inc(TokenStr);
  576. Result := tjsPlusPlus;
  577. end
  578. else
  579. Result := tjsPlus;
  580. end;
  581. ',':
  582. begin
  583. Inc(TokenStr);
  584. Result := tjsComma;
  585. end;
  586. '-':
  587. begin
  588. Inc(TokenStr);
  589. If (TokenStr[0]='=') then
  590. begin
  591. Inc(TokenStr);
  592. Result:=tjsMinusEq
  593. end
  594. else If (TokenStr[0]='-') then
  595. begin
  596. Inc(TokenStr);
  597. Result:=tjsMinusMinus
  598. end
  599. else if (TokenStr[0] in ['0'..'9']) then
  600. begin
  601. Result:=DoNumericLiteral;
  602. If (Result=tjsNumber) then
  603. FCurTokenString:='-'+FCurTokenString;
  604. end
  605. else
  606. Result := tjsMinus;
  607. end;
  608. '.':
  609. begin
  610. Inc(TokenStr);
  611. if (TokenStr[0] in ['0'..'9']) then
  612. begin
  613. Result:=DoNumericLiteral;
  614. If (Result=tjsNumber) then
  615. FCurTokenString:='0.'+FCurTokenString;
  616. end
  617. else
  618. Result := tjsDot;
  619. end;
  620. ':':
  621. begin
  622. Inc(TokenStr);
  623. Result := tjsColon;
  624. end;
  625. '?':
  626. begin
  627. Inc(TokenStr);
  628. Result := tjsConditional;
  629. end;
  630. ';':
  631. begin
  632. Inc(TokenStr);
  633. Result := tjsSemicolon;
  634. end;
  635. '<':
  636. begin
  637. Inc(TokenStr);
  638. if TokenStr[0] = '=' then
  639. begin
  640. Inc(TokenStr);
  641. Result := tjsLE;
  642. end
  643. else if TokenStr[0] = '<' then
  644. begin
  645. Inc(TokenStr);
  646. if (TokenStr[0] = '=') then
  647. begin
  648. Inc(TokenStr);
  649. Result := tjsLShiftEq;
  650. end
  651. else
  652. Result := tjsLShift;
  653. end
  654. else
  655. Result := tjsLT;
  656. end;
  657. '=':
  658. begin
  659. Inc(TokenStr);
  660. if (TokenStr[0]='=') then
  661. begin
  662. Inc(TokenStr);
  663. If (TokenStr[0]='=') then
  664. begin
  665. Inc(TokenStr);
  666. Result:=tjsSEQ;
  667. end
  668. else
  669. Result:=tjsEQ;
  670. end
  671. else
  672. Result := tjsAssign;
  673. end;
  674. '!':
  675. begin
  676. Inc(TokenStr);
  677. if (TokenStr[0]='=') then
  678. begin
  679. Inc(TokenStr);
  680. If (TokenStr[0]='=') then
  681. begin
  682. Inc(TokenStr);
  683. Result:=tjsSNE;
  684. end
  685. else
  686. Result:=tjsNE;
  687. end
  688. else
  689. Result:=tjsNot;// Error(SErrInvalidNonEqual);
  690. end;
  691. '~':
  692. begin
  693. Inc(TokenStr);
  694. Result:=tjsInv;
  695. end;
  696. '>':
  697. begin
  698. Inc(TokenStr);
  699. if TokenStr[0] = '=' then
  700. begin
  701. Inc(TokenStr);
  702. Result:=tjsGE;
  703. end
  704. else if TokenStr[0] = '>' then
  705. begin
  706. Inc(TokenStr);
  707. if (TokenStr[0] = '>') then
  708. begin
  709. Inc(TokenStr);
  710. if (TokenStr[0] = '=') then
  711. begin
  712. Inc(TokenStr);
  713. Result:=tjsURSHIFTEQ;
  714. end
  715. else
  716. Result:=tjsURSHIFT;
  717. end
  718. else if (TokenStr[0] = '=') then
  719. begin
  720. Inc(TokenStr);
  721. Result:=tjsRSHIFTEq;
  722. end
  723. else
  724. Result:=tjsRSHIFT;
  725. end
  726. else
  727. Result := tjsGT;
  728. end;
  729. '[':
  730. begin
  731. Inc(TokenStr);
  732. Result := tJSSquaredBraceOpen;
  733. end;
  734. ']':
  735. begin
  736. Inc(TokenStr);
  737. Result := tJSSquaredBraceClose;
  738. end;
  739. '{':
  740. begin
  741. Inc(TokenStr);
  742. Result := tJSCurlyBraceOpen;
  743. end;
  744. '}':
  745. begin
  746. Inc(TokenStr);
  747. Result := tJSCurlyBraceClose;
  748. end;
  749. else
  750. Result:=DoIdentifier;
  751. end; // Case
  752. Until (Not (Result in [tjsComment,tjsWhitespace])) or
  753. ((Result=tjsComment) and ReturnComments) or
  754. ((Result=tjsWhiteSpace) and ReturnWhiteSpace);
  755. end;
  756. Function TJSScanner.IsEndOfLine: Boolean;
  757. begin
  758. Result:=(TokenStr=Nil) or (TokenStr[0] in [#0,#10,#13]);
  759. end;
  760. function TJSScanner.GetCurColumn: Integer;
  761. begin
  762. Result := TokenStr - PChar(CurLine);
  763. end;
  764. { TStreamLineReader }
  765. constructor TStreamLineReader.Create(AStream: TStream);
  766. begin
  767. FStream:=AStream;
  768. FBufPos:=0;
  769. FBufLen:=0;
  770. end;
  771. function TStreamLineReader.IsEOF: Boolean;
  772. begin
  773. Result:=(FBufPos>=FBufLen);
  774. If Result then
  775. begin
  776. FillBuffer;
  777. Result:=(FBufLen=0);
  778. end;
  779. end;
  780. procedure TStreamLineReader.FillBuffer;
  781. begin
  782. FBufLen:=FStream.Read(Buffer,SizeOf(Buffer)-1);
  783. Buffer[FBufLen]:=0;
  784. FBufPos:=0;
  785. end;
  786. function TStreamLineReader.ReadLine: string;
  787. Var
  788. FPos,OLen,Len: Integer;
  789. PRun : PByte;
  790. begin
  791. FPos:=FBufPos;
  792. SetLength(Result,0);
  793. Repeat
  794. PRun:=@Buffer[FBufPos];
  795. While (FBufPos<FBufLen) and Not (PRun^ in [10,13]) do
  796. begin
  797. Inc(PRun);
  798. Inc(FBufPos);
  799. end;
  800. If (FBufPos=FBufLen) then
  801. begin
  802. Len:=FBufPos-FPos;
  803. If (Len>0) then
  804. begin
  805. Olen:=Length(Result);
  806. SetLength(Result,OLen+Len);
  807. Move(Buffer[FPos],Result[OLen+1],Len);
  808. end;
  809. FillBuffer;
  810. FPos:=FBufPos;
  811. end;
  812. until (FBufPos=FBufLen) or (PRun^ in [10,13]);
  813. Len:=FBufPos-FPos;
  814. If (Len>0) then
  815. begin
  816. Olen:=Length(Result);
  817. SetLength(Result,OLen+Len);
  818. Move(Buffer[FPos],Result[OLen+1],Len)
  819. end;
  820. If (PRun^ in [10,13]) and (FBufPos<FBufLen) then
  821. begin
  822. Inc(FBufPos);
  823. // Check #13#10
  824. If (PRun^=13) then
  825. begin
  826. If (FBufPos=FBufLen) then
  827. FillBuffer;
  828. If (FBufPos<FBufLen) and (Buffer[FBufpos]=10) then
  829. Inc(FBufPos);
  830. end;
  831. end;
  832. end;
  833. end.