%{
-// 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)
{
- //yyDebug = new yydebug.yyDebugSimple ();
- try
- {
- Expression expr = (Expression) yyparse (tok, yyDebug);
- //Console.WriteLine (expr.ToString ());
- return expr;
- }
- 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
%token SLASH2 "//"
%token DOT "."
%token DOT2 ".."
-%token COLON ":"
%token COLON2 "::"
%token COMMA ","
%token AT "@"
%token NUMBER
%token LITERAL
-%token NCName
+%token QName
%start Expr
%%
+/* 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
;
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);
}
;
: 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, (XmlQualifiedName) $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;
{
$$ = Axes.Attribute;
}
- | AxisName COLON2
- {
- $$ = $1;
- }
;
NodeType
PrimaryExpr
: DOLLAR QName
{
- $$ = new ExprVariable ((XmlQualifiedName) $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
{
;
FunctionCall
- : FunctionName PAREN_OPEN OptionalArgumentList PAREN_CLOSE
- {
- $$ = new ExprFunctionCall ((XmlQualifiedName) $1, (FunctionArguments) $3);
- }
- ;
-
-FunctionName
- : FUNCTION_NAME
- {
- $$ = new XmlQualifiedName ((string) $1);
- }
-/*
- | NCName
+ : FUNCTION_NAME PAREN_OPEN OptionalArgumentList PAREN_CLOSE
{
- $$ = new XmlQualifiedName ((string) $1);
+ 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;
}
-*/
;
OptionalArgumentList
}
;
-
-ZeroOrMorePredicates
- : /* empty */
- | Predicate ZeroOrMorePredicates
- {
- $$ = new ExprPredicates ((Expression) $1, (ExprPredicates) $2);
- }
- ;
-
Predicate
: BRACKET_OPEN Expr BRACKET_CLOSE
{
| LITERAL
;
-QName
- : NCName
- {
- $$ = new XmlQualifiedName ((String) $1);
- }
- | NCName COLON ASTERISK
- {
- $$ = new XmlQualifiedName (null, (String) $1);
- }
- | NCName COLON NCName
- {
- $$ = new XmlQualifiedName ((String) $3, (String) $1);
- }
- ;
-
%%
}