Browse Source

* TXPathScanner.ParseStep split into two functions in order to reduce complexity and improve readability.
* Also modified it so the data is accumulated in local vars, and resulting TStep objects are created only after the parsing is successfully complete.
* TXPathScanner.ParsePrimaryExpr: eliminated variable.

git-svn-id: trunk@15628 -

sergei 15 years ago
parent
commit
d44a1603db
1 changed files with 123 additions and 112 deletions
  1. 123 112
      packages/fcl-xml/src/xpath.pp

+ 123 - 112
packages/fcl-xml/src/xpath.pp

@@ -360,7 +360,8 @@ type
     FResolver: TXPathNSResolver;
     procedure Error(const Msg: String);
     procedure ParsePredicates(var Dest: TXPathNodeArray);
-    procedure ParseStep(Dest: TStep);          // [4]
+    function ParseStep: TStep;          // [4]
+    function ParseNodeTest(axis: TAxis): TStep; // [7]
     function ParsePrimaryExpr: TXPathExprNode; // [15]
     function ParseUnionExpr: TXPathExprNode;   // [18]
     function ParsePathExpr: TXPathExprNode;    // [19]
@@ -1851,149 +1852,163 @@ begin
     AddNodes(Dest, Slice(Buffer, I));
 end;
 
-procedure TXPathScanner.ParseStep(Dest: TStep);  // [4]
-
-  procedure NeedBrackets;
-  begin
-    NextToken;
-    if NextToken <> tkRightBracket then
-       Error(SParserExpectedRightBracket);
-    NextToken;
-  end;
-
+function TXPathScanner.ParseStep: TStep;  // [4]
+var
+  Axis: TAxis;
 begin
   if CurToken = tkDot then          // [12] Abbreviated step, first case
   begin
     NextToken;
-    Dest.Axis := axisSelf;
-    Dest.NodeTestType := ntAnyNode;
+    Result := TStep.Create(axisSelf, ntAnyNode);
   end
   else if CurToken = tkDotDot then  // [12] Abbreviated step, second case
   begin
     NextToken;
-    Dest.Axis := axisParent;
-    Dest.NodeTestType := ntAnyNode;
+    Result := TStep.Create(axisParent, ntAnyNode);
   end
   else		// Parse [5] AxisSpecifier
   begin
     if CurToken = tkAt then         // [13] AbbreviatedAxisSpecifier
     begin
-      Dest.Axis := axisAttribute;
+      Axis := axisAttribute;
       NextToken;
     end
     else if (CurToken = tkIdentifier) and (PeekToken = tkColonColon) then  // [5] AxisName '::'
     begin
       // Check for [6] AxisName
       if CurTokenString = 'ancestor' then
-        Dest.Axis := axisAncestor
+        Axis := axisAncestor
       else if CurTokenString = 'ancestor-or-self' then
-        Dest.Axis := axisAncestorOrSelf
+        Axis := axisAncestorOrSelf
       else if CurTokenString = 'attribute' then
-        Dest.Axis := axisAttribute
+        Axis := axisAttribute
       else if CurTokenString = 'child' then
-        Dest.Axis := axisChild
+        Axis := axisChild
       else if CurTokenString = 'descendant' then
-        Dest.Axis := axisDescendant
+        Axis := axisDescendant
       else if CurTokenString = 'descendant-or-self' then
-        Dest.Axis := axisDescendantOrSelf
+        Axis := axisDescendantOrSelf
       else if CurTokenString = 'following' then
-        Dest.Axis := axisFollowing
+        Axis := axisFollowing
       else if CurTokenString = 'following-sibling' then
-        Dest.Axis := axisFollowingSibling
+        Axis := axisFollowingSibling
       else if CurTokenString = 'namespace' then
-        Dest.Axis := axisNamespace
+        Axis := axisNamespace
       else if CurTokenString = 'parent' then
-        Dest.Axis := axisParent
+        Axis := axisParent
       else if CurTokenString = 'preceding' then
-        Dest.Axis := axisPreceding
+        Axis := axisPreceding
       else if CurTokenString = 'preceding-sibling' then
-        Dest.Axis := axisPrecedingSibling
+        Axis := axisPrecedingSibling
       else if CurTokenString = 'self' then
-        Dest.Axis := axisSelf
+        Axis := axisSelf
       else
         Error(SParserBadAxisName);
 
       NextToken;  // skip identifier and the '::'
       NextToken;
-    end;
-
-    // Parse [7] NodeTest
-    if CurToken = tkAsterisk then   // [37] NameTest, first case
-    begin
-      Dest.NodeTestType := ntAnyPrincipal;
-      NextToken;
-    end
-    else if CurToken = tkNSNameTest then // [37] NameTest, second case
-    begin
-      NextToken;
-      if Assigned(FResolver) then
-        Dest.NSTestString := FResolver.lookupNamespaceURI(CurTokenString);
-      if Dest.NSTestString = '' then
-        // !! localization disrupted by DOM exception specifics
-        raise EDOMNamespace.Create('TXPathScanner.ParseStep');
-      Dest.NodeTestType := ntName;
     end
-    else if CurToken = tkIdentifier then
+    else
+      Axis := axisChild;
+
+    Result := ParseNodeTest(Axis);
+    ParsePredicates(Result.Predicates);
+  end;
+end;
+
+function TXPathScanner.ParseNodeTest(Axis: TAxis): TStep; // [7]
+
+  procedure NeedBrackets;
+  begin
+    NextToken;
+    if NextToken <> tkRightBracket then
+       Error(SParserExpectedRightBracket);
+    NextToken;
+  end;
+
+var
+  nodeType: TNodeTestType;
+  nodeName: DOMString;
+  nsURI: DOMString;
+begin
+  nodeName := '';
+  nsURI := '';
+  if CurToken = tkAsterisk then   // [37] NameTest, first case
+  begin
+    nodeType := ntAnyPrincipal;
+    NextToken;
+  end
+  else if CurToken = tkNSNameTest then // [37] NameTest, second case
+  begin
+    NextToken;
+    if Assigned(FResolver) then
+      nsURI := FResolver.lookupNamespaceURI(CurTokenString);
+    if nsURI = '' then
+      // !! localization disrupted by DOM exception specifics
+      raise EDOMNamespace.Create('TXPathScanner.ParseStep');
+    nodeType := ntName;
+  end
+  else if CurToken = tkIdentifier then
+  begin
+    // Check for case [38] NodeType
+    if PeekToken = tkLeftBracket then
     begin
-      // Check for case [38] NodeType
-      if PeekToken = tkLeftBracket then
+      if CurTokenString = 'comment' then
       begin
-        if CurTokenString = 'comment' then
-        begin
-          NeedBrackets;
-          Dest.NodeTestType := ntCommentNode;
-        end
-        else if CurTokenString = 'text' then
-        begin
-          NeedBrackets;
-          Dest.NodeTestType := ntTextNode;
-        end
-        else if CurTokenString = 'processing-instruction' then
-        begin
-          NextToken;   { skip '('; we know it's there }
-          if NextToken = tkString then
-          begin
-            Dest.NodeTestString := CurTokenString;
-            NextToken;
-          end;
-          if CurToken <> tkRightBracket then
-            Error(SParserExpectedRightBracket);
-          NextToken;
-          Dest.NodeTestType := ntPINode;
-        end
-        else if CurTokenString = 'node' then
-        begin
-          NeedBrackets;
-          Dest.NodeTestType := ntAnyNode;
-        end
-        else
-          Error(SParserBadNodeType);
+        NeedBrackets;
+        nodeType := ntCommentNode;
+      end
+      else if CurTokenString = 'text' then
+      begin
+        NeedBrackets;
+        nodeType := ntTextNode;
       end
-      else  // [37] NameTest, third case
+      else if CurTokenString = 'processing-instruction' then
       begin
-        Dest.NodeTestType := ntName;
-        if FPrefixLength > 0 then
+        NextToken;   { skip '('; we know it's there }
+        if NextToken = tkString then
         begin
-          if Assigned(FResolver) then
-            Dest.NSTestString := FResolver.lookupNamespaceURI(Copy(CurTokenString, 1, FPrefixLength));
-          if Dest.NSTestString = '' then
-            raise EDOMNamespace.Create('TXPathScanner.ParseStep');
-          Dest.NodeTestString := Copy(CurTokenString, FPrefixLength+2, MaxInt);
-        end
-        else
-          Dest.NodeTestString := CurTokenString;
+          nodeName := CurTokenString;
+          NextToken;
+        end;
+        if CurToken <> tkRightBracket then
+          Error(SParserExpectedRightBracket);
         NextToken;
-      end;
+        nodeType := ntPINode;
+      end
+      else if CurTokenString = 'node' then
+      begin
+        NeedBrackets;
+        nodeType := ntAnyNode;
+      end
+      else
+        Error(SParserBadNodeType);
     end
-    else
-      Exit;
-    ParsePredicates(Dest.Predicates);
-  end;
+    else  // [37] NameTest, third case
+    begin
+      nodeType := ntName;
+      if FPrefixLength > 0 then
+      begin
+        if Assigned(FResolver) then
+          nsURI := FResolver.lookupNamespaceURI(Copy(CurTokenString, 1, FPrefixLength));
+        if nsURI = '' then
+          raise EDOMNamespace.Create('TXPathScanner.ParseStep');
+        nodeName := Copy(CurTokenString, FPrefixLength+2, MaxInt);
+      end
+      else
+        nodeName := CurTokenString;
+      NextToken;
+    end;
+  end
+  else
+    Error(SParserInvalidNodeTest);
+
+  Result := TStep.Create(Axis, nodeType);
+  Result.NodeTestString := nodeName;
+  Result.NSTestString := nsURI;
 end;
 
 function TXPathScanner.ParsePrimaryExpr: TXPathExprNode;  // [15]
-var
-  IsFirstArg: Boolean;
 begin
   case CurToken of
     tkVariable:         // [36] Variable reference
@@ -2018,17 +2033,17 @@ begin
           Error(SParserExpectedLeftBracket);
         NextToken;
         // Parse argument list
-        IsFirstArg := True;
-        while CurToken <> tkRightBracket do
-        begin
-          if IsFirstArg then
-            IsFirstArg := False
-          else if CurToken <> tkComma then
-            Error(SParserExpectedRightBracket)
-          else
-            NextToken; { skip comma }
+        if CurToken <> tkRightBracket then
+        repeat
           TXPathFunctionNode(Result).FArgs.Add(ParseOrExpr);
-        end;
+          if CurToken <> tkComma then
+          begin
+            if CurToken <> tkRightBracket then
+              Error(SParserExpectedRightBracket);
+            break;
+          end;
+          NextToken; { skip comma }
+        until False;
       end;
   else
     Error(SParserInvalidPrimExpr);
@@ -2077,17 +2092,13 @@ begin
     
   while CurToken in [tkDot, tkDotDot, tkAt, tkAsterisk, tkIdentifier, tkNSNameTest] do
   begin
-    // axisChild is the default. ntAnyPrincipal is dummy.
-    NextStep := TStep.Create(axisChild, ntAnyPrincipal);    
+    NextStep := ParseStep;
     if Assigned(CurStep) then
       CurStep.NextStep := NextStep
     else
       TXPathLocationPathNode(Result).FFirstStep := NextStep;
     CurStep := NextStep;
 
-    // Parse [4] Step
-    ParseStep(CurStep);
-
     // Continue with parsing of [3] RelativeLocationPath
     if CurToken = tkSlashSlash then
     begin