Merge pull request #185 from QuickJack/master
[mono.git] / mcs / class / System.XML / System.Xml.XPath / Parser.jay
index 2ec65c4b9cf223ac7b21febf6bb456ffea99e9f4..22bb6e0b7a05c4e72702f4d98044765c26163195 100644 (file)
@@ -1,25 +1,45 @@
 %{
-// 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!
 //
 
 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
 {
+#if XSLT_PATTERN
+       internal class XsltPatternParser
+#else
        internal class XPathParser
+#endif
        {
        
                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
                {
                        Context = context;
                        ErrorOutput = System.IO.TextWriter.Null;
+//                     debug = new yydebug.yyDebugSimple ();
                }
                
                internal Expression Compile (string xpath)
@@ -27,13 +47,40 @@ namespace Mono.Xml.XPath
                        try {
                                Tokenizer tokenizer = new Tokenizer (xpath);
                                return (Expression) yyparse (tokenizer);
-                       } catch (XPathException e) {
-                               throw e;
+                       } catch (XPathException) {
+                               throw;
                        } catch (Exception e) {
                                throw new XPathException ("Error during parse of " + xpath, e);
                        }
                }
                static int yacc_verbose_flag;
+
+               private NodeSet CreateNodeTest (Axes axis, object nodeTest, ArrayList plist)
+               {
+                       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
@@ -115,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
@@ -258,41 +415,68 @@ RelativeLocationPath
        ;
 
 Step
-       : PredicatedStep
-       | DOT
+       : AxisSpecifier NodeTest Predicates
        {
-               $$ = new NodeTypeTest (Axes.Self, XPathNodeType.All);
+               $$ = CreateNodeTest ((Axes) $1, $2, (ArrayList) $3);
        }
-       | DOT2
+       | AbbreviatedStep
+       ;
+
+NodeTest // QName, XPathNodeType or string
+       : NameTest
+       | NodeType PAREN_OPEN PAREN_CLOSE
        {
-               $$ = new NodeTypeTest (Axes.Parent, XPathNodeType.All);
+               $$ = (XPathNodeType) $1;
+       }
+       | PROCESSING_INSTRUCTION PAREN_OPEN OptionalLiteral PAREN_CLOSE
+       {
+               $$ = (string) $3;
        }
        ;
 
-PredicatedStep
-       : AxisTest
-       | PredicatedStep Predicate
+NameTest
+       : ASTERISK
        {
-               $$ = new ExprFilter ((NodeSet) $1, (Expression) $2);
+               $$ = XmlQualifiedName.Empty;
        }
+       | QName // token QName also contains "blah:*"
        ;
 
-AxisTest
-       : AxisSpecifier QName
+AbbreviatedStep
+       : DOT
        {
-               $$ = new NodeNameTest ((Axes) $1, (XmlQualifiedName) $2, Context);
+               $$ = new NodeTypeTest (Axes.Self, XPathNodeType.All);
        }
-       | AxisSpecifier ASTERISK
+       | DOT2
        {
-               $$ = new NodeTypeTest ((Axes) $1);
+               $$ = new NodeTypeTest (Axes.Parent, XPathNodeType.All);
        }
-       | AxisSpecifier NodeType PAREN_OPEN OptionalLiteral PAREN_CLOSE
+       ;
+
+Predicates
+       : /* empty */
        {
-               $$ = new NodeTypeTest ((Axes) $1, (XPathNodeType) $2, (String) $4);
+               $$ = 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;
@@ -301,10 +485,6 @@ AxisSpecifier
        {
                $$ = Axes.Attribute;
        }
-       | AxisName COLON2
-       {
-               $$ = $1;
-       }
        ;
 
 NodeType