Merge pull request #185 from QuickJack/master
[mono.git] / mcs / class / System.XML / System.Xml.XPath / Parser.jay
index d012b040bff2432c1dd9e7cbe064d864474c6d77..22bb6e0b7a05c4e72702f4d98044765c26163195 100644 (file)
@@ -1,46 +1,86 @@
 %{
-// XPath parser
+// XPath/XSLT Pattern parser
 //
-// Author - Piers Haken <piersh@friskit.com>
+// Author: Piers Haken <piersh@friskit.com>
+//         Atsushi Enomoto  <atsushi@ximian.com>
+//
+// IMPORTANT:
+// Do not edit "PatternParser.jay". It is autogenerated from
+// Parser.jay. It will be overwritten!
 //
-
-// TODO: FUNCTION_CALL should be a QName, not just a NCName
-// TODO: PROCESSING_INSTRUCTION's optional parameter
-// TODO: flatten argument/predicate lists in place
 
 using System;
+using System.Collections;
+using System.Xml;
 using System.Xml.XPath;
 
+#if XSLT_PATTERN
+namespace Mono.Xml.Xsl
+#else
 namespace Mono.Xml.XPath
+#endif
 {
-       public class XPathParser
+#if XSLT_PATTERN
+       internal class XsltPatternParser
+#else
+       internal class XPathParser
+#endif
        {
-               internal object yyparseSafe (Tokenizer tok)
+       
+               internal System.Xml.Xsl.IStaticXsltContext Context;
+               
+#if XSLT_PATTERN
+               public XsltPatternParser () : this (null) {}
+               internal XsltPatternParser (System.Xml.Xsl.IStaticXsltContext context)
+#else
+               public XPathParser () : this (null) {}
+               internal XPathParser (System.Xml.Xsl.IStaticXsltContext context)
+#endif
                {
-                       return yyparseSafe (tok, null);
+                       Context = context;
+                       ErrorOutput = System.IO.TextWriter.Null;
+//                     debug = new yydebug.yyDebugSimple ();
                }
-
-               internal object yyparseSafe (Tokenizer tok, object yyDebug)
+               
+               internal Expression Compile (string xpath)
                {
-                       try
-                       {
-                               return yyparse (tok, yyDebug);
-                       }
-                       catch (XPathException e)
-                       {
-                               throw e;
-                       }
-                       catch (Exception e)
-                       {
-                               throw new XPathException ("Error during parse", e);
+                       try {
+                               Tokenizer tokenizer = new Tokenizer (xpath);
+                               return (Expression) yyparse (tokenizer);
+                       } catch (XPathException) {
+                               throw;
+                       } catch (Exception e) {
+                               throw new XPathException ("Error during parse of " + xpath, e);
                        }
                }
+               static int yacc_verbose_flag;
 
-               internal object yyparseDebug (Tokenizer tok)
+               private NodeSet CreateNodeTest (Axes axis, object nodeTest, ArrayList plist)
                {
-                       return yyparseSafe (tok, new yydebug.yyDebugSimple ());
+                       NodeSet test = CreateNodeTest (axis, nodeTest);
+                       if (plist != null) {
+                               for (int i = 0; i < plist.Count; i++)
+                                       test = new ExprFilter (test,
+                                               (Expression) plist [i]);
+                       }
+                       return test;
                }
 
+               private NodeTest CreateNodeTest (Axes axis, object test)
+               {
+                       if (test is XPathNodeType)
+                               return new NodeTypeTest (axis,
+                                       (XPathNodeType) test, null);
+                       else if (test is string || test == null)
+                               return new NodeTypeTest (axis,
+                                       XPathNodeType.ProcessingInstruction,
+                                       (string) test);
+                       XmlQualifiedName q = (XmlQualifiedName) test;
+                       if (q == XmlQualifiedName.Empty)
+                               return new NodeTypeTest (axis);
+                       else
+                               return new NodeNameTest (axis, q, Context);
+               }
 %}
 
 %token ERROR
@@ -50,7 +90,6 @@ namespace Mono.Xml.XPath
 %token SLASH2                  "//"
 %token DOT                             "."
 %token DOT2                            ".."
-%token COLON                   ":"
 %token COLON2                  "::"
 %token COMMA                   ","
 %token AT                              "@"
@@ -101,7 +140,7 @@ namespace Mono.Xml.XPath
 
 %token NUMBER
 %token LITERAL
-%token NCName
+%token QName
 
 
 %start Expr
@@ -123,6 +162,116 @@ namespace Mono.Xml.XPath
 
 %%
 
+/* XSLT Pattern */
+
+Pattern
+       : LocationPathPattern
+       | Pattern BAR LocationPathPattern
+       {
+               $$ = new ExprUNION ((NodeSet) $1, (NodeSet) $3);
+       }
+       ;
+
+LocationPathPattern
+       : SLASH
+       {
+               $$ = new ExprRoot ();
+       }
+       | SLASH RelativePathPattern
+       {
+               $$ = new ExprSLASH (new ExprRoot (), (NodeSet) $2);
+       }
+       | IdKeyPattern
+       | IdKeyPattern SLASH RelativePathPattern
+       {
+               $$ = new ExprSLASH ((Expression) $1, (NodeSet) $3);
+       }
+       | IdKeyPattern SLASH2 RelativePathPattern
+       {
+               $$ = new ExprSLASH2 ((Expression) $1, (NodeSet) $3);
+       }
+       | SLASH2 RelativePathPattern
+       {
+               $$ = new ExprSLASH2 (new ExprRoot (), (NodeSet) $2);
+       }
+       | RelativePathPattern
+       ;
+
+// to avoid context-sensitive tokenizer, I just reuse FUNCTION_NAME
+IdKeyPattern
+       : FUNCTION_NAME PAREN_OPEN LITERAL PAREN_CLOSE
+       {
+               XmlQualifiedName name = (XmlQualifiedName) $1;
+               if (name.Name != "id" || name.Namespace != String.Empty)
+                       throw new XPathException (String.Format ("Expected 'id' but got '{0}'", name));
+               $$ = ExprFunctionCall.Factory (name,
+                       new FunctionArguments (
+                               new ExprLiteral ((string) $3),
+                               null),
+                       Context);
+       }
+       | FUNCTION_NAME PAREN_OPEN LITERAL COMMA LITERAL PAREN_CLOSE
+       {
+               XmlQualifiedName name = (XmlQualifiedName) $1;
+               if (name.Name != "key" || name.Namespace != String.Empty)
+                       throw new XPathException (String.Format ("Expected 'key' but got '{0}'", name));
+               $$ = Context.TryGetFunction (name,
+                       new FunctionArguments (
+                               new ExprLiteral ((string) $3),
+                               new FunctionArguments (
+                                       new ExprLiteral ((string) $5),
+                                       null)));
+       }
+       ;
+
+RelativePathPattern
+       : StepPattern
+       | RelativePathPattern SLASH StepPattern
+       {
+               $$ = new ExprSLASH ((Expression) $1, (NodeSet) $3);
+       }
+       | RelativePathPattern SLASH2 StepPattern
+       {
+               $$ = new ExprSLASH2 ((Expression) $1, (NodeSet) $3);
+       }
+       ;
+
+StepPattern
+       : ChildOrAttributeAxisSpecifier NodeTest Predicates
+       {
+               $$ = CreateNodeTest ((Axes) $1, $2, (ArrayList) $3);
+       }
+       ;
+
+ChildOrAttributeAxisSpecifier
+       : AbbreviatedAxisSpecifier
+       | CHILD COLON2
+       {
+               $$ = Axes.Child;
+       }
+       | ATTRIBUTE COLON2
+       {
+               $$ = Axes.Attribute;
+       }
+       ;
+
+Predicates
+       : // empty
+       {
+               $$ = null;
+       }
+       | Predicates Predicate
+       {
+               ArrayList al = (ArrayList) $1;
+               if (al == null)
+                       al = new ArrayList ();
+               al.Add ((Expression) $2);
+               $$ = al;
+       }
+       ;
+
+/* ---- end of XSLT Pattern ---- */
+
 
 Expr
        : OrExpr
@@ -216,34 +365,40 @@ UnionExpr
        : PathExpr 
        | UnionExpr BAR PathExpr
        {
-               $$ = new ExprUNION ((NodeSet) $1, (NodeSet) $3);
+               $$ = new ExprUNION ((Expression) $1, (Expression) $3);
        }
        ;
 
 PathExpr
-       : RelativeLocationPath
-       | SLASH
+       : LocationPath
+       | FilterExpr
+       | FilterExpr SLASH RelativeLocationPath
        {
-               $$ = new ExprRoot ();
+               $$ = new ExprSLASH ((Expression) $1, (NodeSet) $3);
        }
-       | SLASH RelativeLocationPath
+       | FilterExpr SLASH2 RelativeLocationPath
        {
-               $$ = new ExprSLASH (new ExprRoot (), (NodeSet) $2);
+               $$ = new ExprSLASH2 ((Expression) $1, (NodeSet) $3);
        }
-       | SLASH2 RelativeLocationPath 
+       ;
+
+LocationPath
+       : RelativeLocationPath
+       | AbsoluteLocationPath
+       ;
+
+AbsoluteLocationPath
+       : SLASH
        {
-               ExprStep exprStep = new ExprStep (new NodeTypeTest (Axes.DescendantOrSelf, XPathNodeType.All));
-               $$ = new ExprSLASH (new ExprSLASH (new ExprRoot (), exprStep), (NodeSet) $2);
+               $$ = new ExprRoot ();
        }
-       | FilterExpr 
-       | FilterExpr SLASH RelativeLocationPath
+       | SLASH RelativeLocationPath
        {
-               $$ = new ExprSLASH ((Expression) $1, (NodeSet) $3);
+               $$ = new ExprSLASH (new ExprRoot (), (NodeSet) $2);
        }
-       | FilterExpr SLASH2 RelativeLocationPath
+       | SLASH2 RelativeLocationPath
        {
-               ExprStep exprStep = new ExprStep (new NodeTypeTest (Axes.DescendantOrSelf, XPathNodeType.All));
-               $$ = new ExprSLASH (new ExprSLASH ((Expression) $1, exprStep), (NodeSet) $3);
+               $$ = new ExprSLASH2 (new ExprRoot (), (NodeSet) $2);
        }
        ;
 
@@ -251,39 +406,77 @@ RelativeLocationPath
        : Step
        | RelativeLocationPath SLASH Step 
        {
-               $$ = new ExprSLASH ((Expression) $1, (NodeSet) $3);
+               $$ = new ExprSLASH ((NodeSet) $1, (NodeSet) $3);
        }
        | RelativeLocationPath SLASH2 Step 
        {
-               ExprStep exprStep = new ExprStep (new NodeTypeTest (Axes.DescendantOrSelf, XPathNodeType.All));
-               $$ = new ExprSLASH (new ExprSLASH ((Expression) $1, exprStep), (NodeSet) $3);
+               $$ = new ExprSLASH2 ((NodeSet) $1, (NodeSet) $3);
        }
        ;
 
 Step
-       : AxisSpecifier QName ZeroOrMorePredicates
+       : AxisSpecifier NodeTest Predicates
        {
-               $$ = new ExprStep (new NodeNameTest ((Axes) $1, (QName) $2), (ExprPredicates) $3);
+               $$ = CreateNodeTest ((Axes) $1, $2, (ArrayList) $3);
        }
-       | AxisSpecifier ASTERISK ZeroOrMorePredicates
+       | AbbreviatedStep
+       ;
+
+NodeTest // QName, XPathNodeType or string
+       : NameTest
+       | NodeType PAREN_OPEN PAREN_CLOSE
        {
-               $$ = new ExprStep (new NodeTypeTest ((Axes) $1), (ExprPredicates) $3);
+               $$ = (XPathNodeType) $1;
        }
-       | AxisSpecifier NodeType PAREN_OPEN OptionalLiteral PAREN_CLOSE ZeroOrMorePredicates
+       | PROCESSING_INSTRUCTION PAREN_OPEN OptionalLiteral PAREN_CLOSE
        {
-               $$ = new ExprStep (new NodeTypeTest ((Axes) $1, (XPathNodeType) $2, (String) $4), (ExprPredicates) $6);
+               $$ = (string) $3;
        }
-       | DOT
+       ;
+
+NameTest
+       : ASTERISK
        {
-               $$ = new ExprStep (new NodeTypeTest (Axes.Self, XPathNodeType.All));
+               $$ = XmlQualifiedName.Empty;
+       }
+       | QName // token QName also contains "blah:*"
+       ;
+
+AbbreviatedStep
+       : DOT
+       {
+               $$ = new NodeTypeTest (Axes.Self, XPathNodeType.All);
        }
        | DOT2
        {
-               $$ = new ExprStep (new NodeTypeTest (Axes.Parent, XPathNodeType.All));
+               $$ = new NodeTypeTest (Axes.Parent, XPathNodeType.All);
+       }
+       ;
+
+Predicates
+       : /* empty */
+       {
+               $$ = null;
+       }
+       | Predicates Predicate
+       {
+               ArrayList al = (ArrayList) $1;
+               if (al == null)
+                       al = new ArrayList ();
+               al.Add ($2);
+               $$ = al;
        }
        ;
 
 AxisSpecifier
+       : AxisName COLON2
+       {
+               $$ = $1;
+       }
+       | AbbreviatedAxisSpecifier
+       ;
+
+AbbreviatedAxisSpecifier
        : /* empty */
        {
                $$ = Axes.Child;
@@ -292,10 +485,6 @@ AxisSpecifier
        {
                $$ = Axes.Attribute;
        }
-       | AxisName COLON2
-       {
-               $$ = $1;
-       }
        ;
 
 NodeType
@@ -317,11 +506,18 @@ FilterExpr
 PrimaryExpr
        : DOLLAR QName
        {
-               $$ = new ExprVariable ((QName) $2);
-       } 
+               Expression ret = null;
+               if (Context != null)
+                       ret = Context.TryGetVariable (((XmlQualifiedName) $2).ToString ());
+               
+               if (ret == null)
+                       ret = new ExprVariable ((XmlQualifiedName) $2, Context);
+                       
+               $$ = ret;
+       }
        | PAREN_OPEN Expr PAREN_CLOSE
        {
-               $$ = $2;
+               $$ = new ExprParens ((Expression) $2);
        }
        | LITERAL
        {
@@ -337,7 +533,13 @@ PrimaryExpr
 FunctionCall
        : FUNCTION_NAME PAREN_OPEN OptionalArgumentList PAREN_CLOSE
        {
-               $$ = new ExprFunctionCall ((String) $1, (FunctionArguments) $3);
+               Expression ret = null;
+               if (Context != null)
+                       ret = Context.TryGetFunction ((XmlQualifiedName) $1, (FunctionArguments) $3);
+               if (ret == null)
+                       ret = ExprFunctionCall.Factory ((XmlQualifiedName) $1, (FunctionArguments) $3, Context);
+               
+               $$ = ret;
        }
        ;
 
@@ -357,15 +559,6 @@ OptionalArgumentListTail
        }
        ;
 
-
-ZeroOrMorePredicates
-       : /* empty */
-       | Predicate ZeroOrMorePredicates
-       {
-               $$ = new ExprPredicates ((Expression) $1, (ExprPredicates) $2);
-       }
-       ;
-
 Predicate
        : BRACKET_OPEN Expr BRACKET_CLOSE
        {
@@ -394,20 +587,5 @@ OptionalLiteral
        | LITERAL
        ;
 
-QName
-       : NCName
-       {
-               $$ = new NCName ((String) $1);
-       }
-       | NCName COLON ASTERISK
-       {
-               $$ = new QName ((String) $1, null);
-       }
-       | NCName COLON NCName
-       {
-               $$ = new QName ((String) $1, (String) $3);
-       }
-       ;
-
 %%
        }