fcl-js: started jsonscanner adaption for pas2js

git-svn-id: trunk@40045 -
This commit is contained in:
Mattias Gaertner 2018-10-25 20:16:56 +00:00
parent 225aa064fe
commit 75e6356e02
2 changed files with 88 additions and 78 deletions

View File

@ -15,6 +15,10 @@
{$mode objfpc}
{$h+}
{$ifdef fpc}
{$define UsePChar}
{$endif}
unit jsonscanner;
interface
@ -48,7 +52,7 @@ type
tkUnknown
);
EScannerError = class(EParserError);
EScannerError = class(EParserError);
TJSONOption = (joUTF8,joStrict,joComments,joIgnoreTrailingComma);
TJSONOptions = set of TJSONOption;
@ -62,24 +66,27 @@ Type
TJSONScanner = class
private
FSource : TStringList;
FSource: TStringList;
FCurRow: Integer;
FCurToken: TJSONToken;
FCurTokenString: string;
FCurLine: string;
TokenStr: PChar;
FTokenStr: {$ifdef UsePChar}PChar{$else}integer{$endif}; // position inside FCurLine
FOptions : TJSONOptions;
function GetCurColumn: Integer; inline;
function GetO(AIndex: TJSONOption): Boolean;
procedure SetO(AIndex: TJSONOption; AValue: Boolean);
protected
procedure Error(const Msg: string);overload;
procedure Error(const Msg: string; Const Args: array of Const);overload;
procedure Error(const Msg: string;
Const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});overload;
function DoFetchToken: TJSONToken; inline;
public
{$ifdef fpc}
constructor Create(Source : TStream; AUseUTF8 : Boolean = True); overload; deprecated 'use options form instead';
constructor Create(const Source : String; AUseUTF8 : Boolean = True); overload; deprecated 'use options form instead';
constructor Create(Source: TStream; AOptions: TJSONOptions); overload;
{$endif}
constructor Create(const Source: String; AOptions: TJSONOptions); overload;
destructor Destroy; override;
function FetchToken: TJSONToken;
@ -122,6 +129,7 @@ const
implementation
{$ifdef fpc}
constructor TJSONScanner.Create(Source : TStream; AUseUTF8 : Boolean = True);
Var
@ -155,6 +163,7 @@ begin
FSource.LoadFromStream(Source);
FOptions:=AOptions;
end;
{$endif}
constructor TJSONScanner.Create(const Source: String; AOptions: TJSONOptions);
begin
@ -181,7 +190,8 @@ begin
raise EScannerError.Create(Msg);
end;
procedure TJSONScanner.Error(const Msg: string; const Args: array of const);
procedure TJSONScanner.Error(const Msg: string;
const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif});
begin
raise EScannerError.CreateFmt(Msg, Args);
end;
@ -194,13 +204,13 @@ function TJSONScanner.DoFetchToken: TJSONToken;
if Result then
begin
FCurLine:=FSource[FCurRow];
TokenStr:=PChar(FCurLine);
FTokenStr:=PChar(FCurLine);
Inc(FCurRow);
end
else
begin
FCurLine:='';
TokenStr:=nil;
FTokenStr:=nil;
end;
end;
@ -214,7 +224,7 @@ var
IsStar,EOC: Boolean;
begin
if TokenStr = nil then
if FTokenStr = nil then
if not FetchLine then
begin
Result := tkEOF;
@ -224,7 +234,7 @@ begin
FCurTokenString := '';
case TokenStr[0] of
case FTokenStr[0] of
#0: // Empty line
begin
FetchLine;
@ -234,33 +244,33 @@ begin
begin
Result := tkWhitespace;
repeat
Inc(TokenStr);
if TokenStr[0] = #0 then
Inc(FTokenStr);
if FTokenStr[0] = #0 then
if not FetchLine then
begin
FCurToken := Result;
exit;
end;
until not (TokenStr[0] in [#9, ' ']);
until not (FTokenStr[0] in [#9, ' ']);
end;
'"','''':
begin
C:=TokenStr[0];
C:=FTokenStr[0];
If (C='''') and (joStrict in Options) then
Error(SErrInvalidCharacter, [CurRow,CurColumn,TokenStr[0]]);
Inc(TokenStr);
TokenStart := TokenStr;
Error(SErrInvalidCharacter, [CurRow,CurColumn,FTokenStr[0]]);
Inc(FTokenStr);
TokenStart := FTokenStr;
OldLength := 0;
FCurTokenString := '';
while not (TokenStr[0] in [#0,C]) do
while not (FTokenStr[0] in [#0,C]) do
begin
if (TokenStr[0]='\') then
if (FTokenStr[0]='\') then
begin
// Save length
SectionLength := TokenStr - TokenStart;
Inc(TokenStr);
SectionLength := FTokenStr - TokenStart;
Inc(FTokenStr);
// Read escaped token
Case TokenStr[0] of
Case FTokenStr[0] of
'"' : S:='"';
'''' : S:='''';
't' : S:=#9;
@ -275,14 +285,14 @@ begin
u:=0;
For I:=1 to 4 do
begin
Inc(TokenStr);
c2:=TokenStr^;
Inc(FTokenStr);
c2:=FTokenStr^;
Case c2 of
'0'..'9': u:=u*16+ord(c2)-ord('0');
'A'..'F': u:=u*16+ord(c2)-ord('A')+10;
'a'..'f': u:=u*16+ord(c2)-ord('a')+10;
else
Error(SErrInvalidCharacter, [CurRow,CurColumn,TokenStr[0]]);
Error(SErrInvalidCharacter, [CurRow,CurColumn,FTokenStr[0]]);
end;
end;
// ToDo: 4-bytes UTF16
@ -293,7 +303,7 @@ begin
end;
#0 : Error(SErrOpenString);
else
Error(SErrInvalidCharacter, [CurRow,CurColumn,TokenStr[0]]);
Error(SErrInvalidCharacter, [CurRow,CurColumn,FTokenStr[0]]);
end;
SetLength(FCurTokenString, OldLength + SectionLength+1+Length(S));
if SectionLength > 0 then
@ -301,61 +311,61 @@ begin
Move(S[1],FCurTokenString[OldLength + SectionLength+1],Length(S));
Inc(OldLength, SectionLength+Length(S));
// Next char
TokenStart := TokenStr+1;
TokenStart := FTokenStr+1;
end;
if TokenStr[0] = #0 then
if FTokenStr[0] = #0 then
Error(SErrOpenString);
Inc(TokenStr);
Inc(FTokenStr);
end;
if TokenStr[0] = #0 then
if FTokenStr[0] = #0 then
Error(SErrOpenString);
SectionLength := TokenStr - TokenStart;
SectionLength := FTokenStr - TokenStart;
SetLength(FCurTokenString, OldLength + SectionLength);
if SectionLength > 0 then
Move(TokenStart^, FCurTokenString[OldLength + 1], SectionLength);
Inc(TokenStr);
Inc(FTokenStr);
Result := tkString;
end;
',':
begin
Inc(TokenStr);
Inc(FTokenStr);
Result := tkComma;
end;
'0'..'9','.','-':
begin
TokenStart := TokenStr;
TokenStart := FTokenStr;
while true do
begin
Inc(TokenStr);
case TokenStr[0] of
Inc(FTokenStr);
case FTokenStr[0] of
'.':
begin
if TokenStr[1] in ['0'..'9', 'e', 'E'] then
if FTokenStr[1] in ['0'..'9', 'e', 'E'] then
begin
Inc(TokenStr);
Inc(FTokenStr);
repeat
Inc(TokenStr);
until not (TokenStr[0] in ['0'..'9', 'e', 'E','-','+']);
Inc(FTokenStr);
until not (FTokenStr[0] in ['0'..'9', 'e', 'E','-','+']);
end;
break;
end;
'0'..'9': ;
'e', 'E':
begin
Inc(TokenStr);
if TokenStr[0] in ['-','+'] then
Inc(TokenStr);
while TokenStr[0] in ['0'..'9'] do
Inc(TokenStr);
Inc(FTokenStr);
if FTokenStr[0] in ['-','+'] then
Inc(FTokenStr);
while FTokenStr[0] in ['0'..'9'] do
Inc(FTokenStr);
break;
end;
else
if not (TokenStr[0] in [#0,'}',']',',',#9,' ']) then
Error(SErrInvalidCharacter, [CurRow,CurColumn,TokenStr[0]]);
if not (FTokenStr[0] in [#0,'}',']',',',#9,' ']) then
Error(SErrInvalidCharacter, [CurRow,CurColumn,FTokenStr[0]]);
break;
end;
end;
SectionLength := TokenStr - TokenStart;
SectionLength := FTokenStr - TokenStart;
FCurTokenString:='';
SetString(FCurTokenString, TokenStart, SectionLength);
If (FCurTokenString[1]='.') then
@ -364,74 +374,74 @@ begin
end;
':':
begin
Inc(TokenStr);
Inc(FTokenStr);
Result := tkColon;
end;
'{':
begin
Inc(TokenStr);
Inc(FTokenStr);
Result := tkCurlyBraceOpen;
end;
'}':
begin
Inc(TokenStr);
Inc(FTokenStr);
Result := tkCurlyBraceClose;
end;
'[':
begin
Inc(TokenStr);
Inc(FTokenStr);
Result := tkSquaredBraceOpen;
end;
']':
begin
Inc(TokenStr);
Inc(FTokenStr);
Result := tkSquaredBraceClose;
end;
'/' :
begin
if Not (joComments in Options) then
Error(SErrInvalidCharacter, [CurRow,CurCOlumn,TokenStr[0]]);
TokenStart:=TokenStr;
Inc(TokenStr);
Case Tokenstr[0] of
Error(SErrInvalidCharacter, [CurRow,CurCOlumn,FTokenStr[0]]);
TokenStart:=FTokenStr;
Inc(FTokenStr);
Case FTokenStr[0] of
'/' : begin
SectionLength := Length(FCurLine)- (TokenStr - PChar(FCurLine));
Inc(TokenStr);
SectionLength := Length(FCurLine)- (FTokenStr - PChar(FCurLine));
Inc(FTokenStr);
FCurTokenString:='';
SetString(FCurTokenString, TokenStr, SectionLength);
SetString(FCurTokenString, FTokenStr, SectionLength);
Fetchline;
end;
'*' :
begin
IsStar:=False;
Inc(TokenStr);
TokenStart:=TokenStr;
Inc(FTokenStr);
TokenStart:=FTokenStr;
Repeat
if (TokenStr[0]=#0) then
if (FTokenStr[0]=#0) then
begin
SectionLength := (TokenStr - TokenStart);
SectionLength := (FTokenStr - TokenStart);
S:='';
SetString(S, TokenStart, SectionLength);
FCurtokenString:=FCurtokenString+S;
if not fetchLine then
Error(SUnterminatedComment, [CurRow,CurCOlumn,TokenStr[0]]);
TokenStart:=TokenStr;
Error(SUnterminatedComment, [CurRow,CurCOlumn,FTokenStr[0]]);
TokenStart:=FTokenStr;
end;
IsStar:=TokenStr[0]='*';
Inc(TokenStr);
EOC:=(isStar and (TokenStr[0]='/'));
IsStar:=FTokenStr[0]='*';
Inc(FTokenStr);
EOC:=(isStar and (FTokenStr[0]='/'));
Until EOC;
if EOC then
begin
SectionLength := (TokenStr - TokenStart-1);
SectionLength := (FTokenStr - TokenStart-1);
S:='';
SetString(S, TokenStart, SectionLength);
FCurtokenString:=FCurtokenString+S;
Inc(TokenStr);
Inc(FTokenStr);
end;
end;
else
Error(SErrInvalidCharacter, [CurRow,CurCOlumn,TokenStr[0]]);
Error(SErrInvalidCharacter, [CurRow,CurCOlumn,FTokenStr[0]]);
end;
Result:=tkComment;
end;
@ -439,11 +449,11 @@ begin
begin
tstart:=CurRow;
Tcol:=CurColumn;
TokenStart := TokenStr;
TokenStart := FTokenStr;
repeat
Inc(TokenStr);
until not (TokenStr[0] in ['A'..'Z', 'a'..'z', '0'..'9', '_']);
SectionLength := TokenStr - TokenStart;
Inc(FTokenStr);
until not (FTokenStr[0] in ['A'..'Z', 'a'..'z', '0'..'9', '_']);
SectionLength := FTokenStr - TokenStart;
FCurTokenString:='';
SetString(FCurTokenString, TokenStart, SectionLength);
for it := tkTrue to tkNull do
@ -459,7 +469,7 @@ begin
Result:=tkIdentifier;
end;
else
Error(SErrInvalidCharacter, [CurRow,CurCOlumn,TokenStr[0]]);
Error(SErrInvalidCharacter, [CurRow,CurColumn,FTokenStr[0]]);
end;
FCurToken := Result;
@ -467,7 +477,7 @@ end;
function TJSONScanner.GetCurColumn: Integer;
begin
Result := TokenStr - PChar(CurLine);
Result := FTokenStr - PChar(CurLine);
end;
function TJSONScanner.GetO(AIndex: TJSONOption): Boolean;

View File

@ -5,7 +5,7 @@ program nodepas2js;
uses
JS, NodeJS, NodeJSFS, Math,
Classes, SysUtils,
jsbase, jstree, jswriter,
jsbase, jstree, jswriter, jsonscanner,// JSSrcMap,
fpjson,
PasTree, PScanner, PParser, PasResolveEval, PasResolver, PasUseAnalyzer,
FPPas2Js,