|
@@ -22,7 +22,7 @@ interface
|
|
uses SysUtils, Classes;
|
|
uses SysUtils, Classes;
|
|
|
|
|
|
resourcestring
|
|
resourcestring
|
|
- SErrInvalidCharacter = 'Invalid character ''%s''';
|
|
|
|
|
|
+ SErrInvalidCharacter = 'Invalid character at line %d, pos %d: ''%s''';
|
|
SErrOpenString = 'string exceeds end of line';
|
|
SErrOpenString = 'string exceeds end of line';
|
|
|
|
|
|
type
|
|
type
|
|
@@ -42,12 +42,15 @@ type
|
|
tkCurlyBraceClose, // '}'
|
|
tkCurlyBraceClose, // '}'
|
|
tkSquaredBraceOpen, // '['
|
|
tkSquaredBraceOpen, // '['
|
|
tkSquaredBraceClose, // ']'
|
|
tkSquaredBraceClose, // ']'
|
|
|
|
+ tkIdentifier, // Any Javascript identifier
|
|
tkUnknown
|
|
tkUnknown
|
|
);
|
|
);
|
|
|
|
|
|
EScannerError = class(Exception);
|
|
EScannerError = class(Exception);
|
|
|
|
|
|
|
|
|
|
|
|
+ { TJSONScanner }
|
|
|
|
+
|
|
TJSONScanner = class
|
|
TJSONScanner = class
|
|
private
|
|
private
|
|
FSource : TStringList;
|
|
FSource : TStringList;
|
|
@@ -55,6 +58,7 @@ type
|
|
FCurToken: TJSONToken;
|
|
FCurToken: TJSONToken;
|
|
FCurTokenString: string;
|
|
FCurTokenString: string;
|
|
FCurLine: string;
|
|
FCurLine: string;
|
|
|
|
+ FStrict: Boolean;
|
|
TokenStr: PChar;
|
|
TokenStr: PChar;
|
|
function GetCurColumn: Integer;
|
|
function GetCurColumn: Integer;
|
|
protected
|
|
protected
|
|
@@ -74,6 +78,8 @@ type
|
|
|
|
|
|
property CurToken: TJSONToken read FCurToken;
|
|
property CurToken: TJSONToken read FCurToken;
|
|
property CurTokenString: string read FCurTokenString;
|
|
property CurTokenString: string read FCurTokenString;
|
|
|
|
+ // Use strict JSON: " for strings, object members are strings, not identifiers
|
|
|
|
+ Property Strict : Boolean Read FStrict Write FStrict;
|
|
end;
|
|
end;
|
|
|
|
|
|
const
|
|
const
|
|
@@ -91,6 +97,7 @@ const
|
|
'}',
|
|
'}',
|
|
'[',
|
|
'[',
|
|
']',
|
|
']',
|
|
|
|
+ 'identifier',
|
|
''
|
|
''
|
|
);
|
|
);
|
|
|
|
|
|
@@ -156,6 +163,7 @@ var
|
|
it : TJSONToken;
|
|
it : TJSONToken;
|
|
I : Integer;
|
|
I : Integer;
|
|
OldLength, SectionLength, Index: Integer;
|
|
OldLength, SectionLength, Index: Integer;
|
|
|
|
+ C : char;
|
|
S : String;
|
|
S : String;
|
|
|
|
|
|
begin
|
|
begin
|
|
@@ -188,14 +196,16 @@ begin
|
|
end;
|
|
end;
|
|
until not (TokenStr[0] in [#9, ' ']);
|
|
until not (TokenStr[0] in [#9, ' ']);
|
|
end;
|
|
end;
|
|
- '"':
|
|
|
|
|
|
+ '"','''':
|
|
begin
|
|
begin
|
|
|
|
+ C:=TokenStr[0];
|
|
|
|
+ If (C='''') and Strict then
|
|
|
|
+ Error(SErrInvalidCharacter, [CurRow,CurColumn,TokenStr[0]]);
|
|
Inc(TokenStr);
|
|
Inc(TokenStr);
|
|
TokenStart := TokenStr;
|
|
TokenStart := TokenStr;
|
|
OldLength := 0;
|
|
OldLength := 0;
|
|
FCurTokenString := '';
|
|
FCurTokenString := '';
|
|
-
|
|
|
|
- while not (TokenStr[0] in [#0,'"']) do
|
|
|
|
|
|
+ while not (TokenStr[0] in [#0,C]) do
|
|
begin
|
|
begin
|
|
if (TokenStr[0]='\') then
|
|
if (TokenStr[0]='\') then
|
|
begin
|
|
begin
|
|
@@ -205,6 +215,7 @@ begin
|
|
// Read escaped token
|
|
// Read escaped token
|
|
Case TokenStr[0] of
|
|
Case TokenStr[0] of
|
|
'"' : S:='"';
|
|
'"' : S:='"';
|
|
|
|
+ '''' : S:='''';
|
|
't' : S:=#9;
|
|
't' : S:=#9;
|
|
'b' : S:=#8;
|
|
'b' : S:=#8;
|
|
'n' : S:=#10;
|
|
'n' : S:=#10;
|
|
@@ -221,7 +232,7 @@ begin
|
|
'0'..'9','A'..'F','a'..'f' :
|
|
'0'..'9','A'..'F','a'..'f' :
|
|
S[i]:=Upcase(TokenStr[0]);
|
|
S[i]:=Upcase(TokenStr[0]);
|
|
else
|
|
else
|
|
- Error(SErrInvalidCharacter, [TokenStr[0]]);
|
|
|
|
|
|
+ Error(SErrInvalidCharacter, [CurRow,CurColumn,TokenStr[0]]);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
// Takes care of conversion...
|
|
// Takes care of conversion...
|
|
@@ -229,7 +240,7 @@ begin
|
|
end;
|
|
end;
|
|
#0 : Error(SErrOpenString);
|
|
#0 : Error(SErrOpenString);
|
|
else
|
|
else
|
|
- Error(SErrInvalidCharacter, [TokenStr[0]]);
|
|
|
|
|
|
+ Error(SErrInvalidCharacter, [CurRow,CurColumn,TokenStr[0]]);
|
|
end;
|
|
end;
|
|
SetLength(FCurTokenString, OldLength + SectionLength+1+Length(S));
|
|
SetLength(FCurTokenString, OldLength + SectionLength+1+Length(S));
|
|
if SectionLength > 0 then
|
|
if SectionLength > 0 then
|
|
@@ -258,7 +269,7 @@ begin
|
|
Inc(TokenStr);
|
|
Inc(TokenStr);
|
|
Result := tkComma;
|
|
Result := tkComma;
|
|
end;
|
|
end;
|
|
- '0'..'9','-':
|
|
|
|
|
|
+ '0'..'9','.','-':
|
|
begin
|
|
begin
|
|
TokenStart := TokenStr;
|
|
TokenStart := TokenStr;
|
|
while true do
|
|
while true do
|
|
@@ -294,6 +305,8 @@ begin
|
|
SetLength(FCurTokenString, SectionLength);
|
|
SetLength(FCurTokenString, SectionLength);
|
|
if SectionLength > 0 then
|
|
if SectionLength > 0 then
|
|
Move(TokenStart^, FCurTokenString[1], SectionLength);
|
|
Move(TokenStart^, FCurTokenString[1], SectionLength);
|
|
|
|
+ If (FCurTokenString[1]='.') then
|
|
|
|
+ FCurTokenString:='0'+FCurTokenString;
|
|
Result := tkNumber;
|
|
Result := tkNumber;
|
|
end;
|
|
end;
|
|
':':
|
|
':':
|
|
@@ -321,7 +334,7 @@ begin
|
|
Inc(TokenStr);
|
|
Inc(TokenStr);
|
|
Result := tkSquaredBraceClose;
|
|
Result := tkSquaredBraceClose;
|
|
end;
|
|
end;
|
|
- 'T','t','F','f','N','n' :
|
|
|
|
|
|
+ 'a'..'z','_':
|
|
begin
|
|
begin
|
|
TokenStart := TokenStr;
|
|
TokenStart := TokenStr;
|
|
repeat
|
|
repeat
|
|
@@ -338,10 +351,13 @@ begin
|
|
FCurToken := Result;
|
|
FCurToken := Result;
|
|
exit;
|
|
exit;
|
|
end;
|
|
end;
|
|
- Error(SErrInvalidCharacter, [TokenStart[0]]);
|
|
|
|
|
|
+ if Strict then
|
|
|
|
+ Error(SErrInvalidCharacter, [CurRow,CurColumn,TokenStr[0]])
|
|
|
|
+ else
|
|
|
|
+ Result:=tkIdentifier;
|
|
end;
|
|
end;
|
|
else
|
|
else
|
|
- Error(SErrInvalidCharacter, [TokenStr[0]]);
|
|
|
|
|
|
+ Error(SErrInvalidCharacter, [CurRow,CurCOlumn,TokenStr[0]]);
|
|
end;
|
|
end;
|
|
|
|
|
|
FCurToken := Result;
|
|
FCurToken := Result;
|