Browse Source

* Introduced strict property

git-svn-id: trunk@15977 -
michael 15 years ago
parent
commit
246e7275a4
2 changed files with 41 additions and 12 deletions
  1. 15 2
      packages/fcl-json/src/jsonparser.pp
  2. 26 10
      packages/fcl-json/src/jsonscanner.pp

+ 15 - 2
packages/fcl-json/src/jsonparser.pp

@@ -28,7 +28,9 @@ Type
   TJSONParser = Class(TObject)
   TJSONParser = Class(TObject)
   Private
   Private
     FScanner : TJSONScanner;
     FScanner : TJSONScanner;
+    FStrict: Boolean;
     function ParseNumber: TJSONNumber;
     function ParseNumber: TJSONNumber;
+    procedure SetStrict(const AValue: Boolean);
   Protected
   Protected
     procedure DoError(const Msg: String);
     procedure DoError(const Msg: String);
     function DoParse(AtCurrent,AllowEOF: Boolean): TJSONData;
     function DoParse(AtCurrent,AllowEOF: Boolean): TJSONData;
@@ -42,6 +44,8 @@ Type
     Constructor Create(Source : TStream); overload;
     Constructor Create(Source : TStream); overload;
     Constructor Create(Source : TJSONStringType); overload;
     Constructor Create(Source : TJSONStringType); overload;
     destructor Destroy();override;
     destructor Destroy();override;
+    // Use strict JSON: " for strings, object members are strings, not identifiers
+    Property Strict : Boolean Read FStrict Write SetStrict;
   end;
   end;
   
   
   EJSONScanner = Class(Exception);
   EJSONScanner = Class(Exception);
@@ -82,7 +86,7 @@ end;
 Function TJSONParser.CurrentTokenString : String;
 Function TJSONParser.CurrentTokenString : String;
 
 
 begin
 begin
-  If CurrentToken in [tkString,tkNumber] then
+  If CurrentToken in [tkString,tkIdentifier,tkNumber] then
     Result:=FScanner.CurTokenString
     Result:=FScanner.CurTokenString
   else
   else
     Result:=TokenInfos[CurrentToken];
     Result:=TokenInfos[CurrentToken];
@@ -147,6 +151,15 @@ begin
     end;
     end;
 end;
 end;
 
 
+procedure TJSONParser.SetStrict(const AValue: Boolean);
+begin
+  if (FStrict=AValue) then
+     exit;
+  FStrict:=AValue;
+  If Assigned(FScanner) then
+    FScanner.Strict:=Fstrict;
+end;
+
 // Current token is {, on exit current token is }
 // Current token is {, on exit current token is }
 Function TJSONParser.ParseObject : TJSONObject;
 Function TJSONParser.ParseObject : TJSONObject;
 
 
@@ -161,7 +174,7 @@ begin
     T:=GetNextToken;
     T:=GetNextToken;
     While T<>tkCurlyBraceClose do
     While T<>tkCurlyBraceClose do
       begin
       begin
-      If T<>tkString then
+      If (T<>tkString) and (T<>tkIdentifier) then
         DoError(SErrExpectedElementName);
         DoError(SErrExpectedElementName);
       N:=CurrentTokenString;
       N:=CurrentTokenString;
       T:=GetNextToken;
       T:=GetNextToken;

+ 26 - 10
packages/fcl-json/src/jsonscanner.pp

@@ -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;