Browse Source

* XPath, change parsing of function call so that function arguments are parsed before creating the function node. This way function nodes can validate their arguments at creation time.
* also changed function argument container type from TFPList to dynamic array.

git-svn-id: trunk@15641 -

sergei 15 years ago
parent
commit
c902b96673
1 changed files with 49 additions and 38 deletions
  1. 49 38
      packages/fcl-xml/src/xpath.pp

+ 49 - 38
packages/fcl-xml/src/xpath.pp

@@ -150,9 +150,9 @@ type
   TXPathFunctionNode = class(TXPathExprNode)
   private
     FName: DOMString;
-    FArgs: TFPList;
+    FArgs: TXPathNodeArray;
   public
-    constructor Create(const AName: DOMString);
+    constructor Create(const AName: DOMString; const Args: TXPathNodeArray);
     destructor Destroy; override;
     function Evaluate(AContext: TXPathContext;
       AEnvironment: TXPathEnvironment): TXPathVariable; override;
@@ -371,6 +371,7 @@ type
     function ParseStep: TStep;          // [4]
     function ParseNodeTest(axis: TAxis): TStep; // [7]
     function ParsePrimaryExpr: TXPathExprNode; // [15]
+    function ParseFunctionCall: TXPathExprNode; // [16]
     function ParseUnionExpr: TXPathExprNode;   // [18]
     function ParsePathExpr: TXPathExprNode;    // [19]
     function ParseFilterExpr: TXPathExprNode;  // [20]
@@ -625,13 +626,18 @@ begin
   end;
 end;
 
-procedure AddNodes(var Dst: TXPathNodeArray; const Src: array of TXPathExprNode);
+procedure AddNodes(var Dst: TXPathNodeArray; const Src: array of TXPathExprNode;
+  var Count: Integer);
 var
   L: Integer;
 begin
-  L := Length(Dst);
-  SetLength(Dst, L + High(Src)+1);
-  Move(Src[0], Dst[L], (High(Src)+1)*sizeof(TObject));
+  if Count > 0 then
+  begin
+    L := Length(Dst);
+    SetLength(Dst, L + Count);
+    Move(Src[0], Dst[L], Count*sizeof(TObject));
+    Count := 0;
+  end;
 end;
 
 { XPath parse tree classes }
@@ -687,20 +693,19 @@ begin
 end;
 
 
-constructor TXPathFunctionNode.Create(const AName: DOMString);
+constructor TXPathFunctionNode.Create(const AName: DOMString; const Args: TXPathNodeArray);
 begin
   inherited Create;
   FName := AName;
-  FArgs := TFPList.Create;
+  FArgs := Args;
 end;
 
 destructor TXPathFunctionNode.Destroy;
 var
   i: Integer;
 begin
-  for i := 0 to FArgs.Count - 1 do
-    TXPathExprNode(FArgs[i]).Free;
-  FArgs.Free;
+  for i := Low(FArgs) to High(FArgs) do
+    FArgs[i].Free;
   inherited Destroy;
 end;
 
@@ -717,10 +722,10 @@ begin
 
   Args := TXPathVarList.Create;
   try
-    for i := 0 to FArgs.Count - 1 do
-      Args.Add(TXPathExprNode(FArgs[i]).Evaluate(AContext, AEnvironment));
+    for i := Low(FArgs) to High(FArgs) do
+      Args.Add(FArgs[i].Evaluate(AContext, AEnvironment));
     Result := Fn(AContext, Args);
-    for i := 0 to FArgs.Count - 1 do
+    for i := Low(FArgs) to High(FArgs) do
       TXPathVariable(Args[i]).Release;
   finally
     Args.Free;
@@ -1837,15 +1842,11 @@ begin
     Buffer[I] := ParseOrExpr;
     Inc(I);
     if I > High(Buffer) then
-    begin
-      AddNodes(Dest, Buffer);
-      I := 0;
-    end;
+      AddNodes(Dest, Buffer, I);  // will reset I to zero
     if not SkipToken(tkRightSquareBracket) then
       Error(SParserExpectedRightSquareBracket);
   end;
-  if I > 0 then
-    AddNodes(Dest, Slice(Buffer, I));
+  AddNodes(Dest, Buffer, I);
 end;
 
 function TXPathScanner.ParseStep: TStep;  // [4]
@@ -1981,24 +1982,7 @@ begin
       Result := TXPathConstantNode.Create(
         TXPathNumberVariable.Create(StrToNumber(CurTokenString)));
     tkIdentifier:     // [16] Function call
-      begin
-        Result := TXPathFunctionNode.Create(CurTokenString);
-        if NextToken <> tkLeftBracket then
-          Error(SParserExpectedLeftBracket);
-        NextToken;
-        // Parse argument list
-        if CurToken <> tkRightBracket then
-        repeat
-          TXPathFunctionNode(Result).FArgs.Add(ParseOrExpr);
-          if CurToken <> tkComma then
-          begin
-            if CurToken <> tkRightBracket then
-              Error(SParserExpectedRightBracket);
-            break;
-          end;
-          NextToken; { skip comma }
-        until False;
-      end;
+      Result := ParseFunctionCall;
   else
     Error(SParserInvalidPrimExpr);
     Result := nil; // satisfy compiler
@@ -2006,6 +1990,33 @@ begin
   NextToken;
 end;
 
+function TXPathScanner.ParseFunctionCall: TXPathExprNode;
+var
+  Name: DOMString;
+  Args: TXPathNodeArray;
+  Buffer: array[0..15] of TXPathExprNode;
+  I: Integer;
+begin
+  Name := CurTokenString;
+  I := 0;
+  if NextToken <> tkLeftBracket then
+    Error(SParserExpectedLeftBracket);
+  NextToken;
+  // Parse argument list
+  if CurToken <> tkRightBracket then
+  repeat
+    Buffer[I] := ParseOrExpr;
+    Inc(I);
+    if I > High(Buffer) then
+      AddNodes(Args, Buffer, I);
+  until not SkipToken(tkComma);
+  if CurToken <> tkRightBracket then
+    Error(SParserExpectedRightBracket);
+
+  AddNodes(Args, Buffer, I);
+  Result := TXPathFunctionNode.Create(Name, Args);
+end;
+
 function TXPathScanner.ParseUnionExpr: TXPathExprNode;  // [18]
 begin
   Result := ParsePathExpr;