Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

595 lines
11 KiB
Plaintext

%{
// XPath/XSLT Pattern parser
//
// 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)
{
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);
}
}
#pragma warning disable 649
static readonly int yacc_verbose_flag;
#pragma warning restore 649
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
%token EOF
%token SLASH "/"
%token SLASH2 "//"
%token DOT "."
%token DOT2 ".."
%token COLON2 "::"
%token COMMA ","
%token AT "@"
%token FUNCTION_NAME
%token BRACKET_OPEN "["
%token BRACKET_CLOSE "]"
%token PAREN_OPEN "("
%token PAREN_CLOSE ")"
%token AND "and"
%token OR "or"
%token DIV "div"
%token MOD "mod"
%token PLUS "+"
%token MINUS "-"
%token ASTERISK "*"
%token DOLLAR "$"
%token BAR "|"
%token EQ "="
%token NE "!="
%token LE "<="
%token GE ">="
%token LT "<"
%token GT ">"
%token ANCESTOR "ancestor"
%token ANCESTOR_OR_SELF "ancstor-or-self"
%token ATTRIBUTE "attribute"
%token CHILD "child"
%token DESCENDANT "descendant"
%token DESCENDANT_OR_SELF "descendant-or-self"
%token FOLLOWING "following"
%token FOLLOWING_SIBLING "sibling"
%token NAMESPACE "NameSpace"
%token PARENT "parent"
%token PRECEDING "preceding"
%token PRECEDING_SIBLING "preceding-sibling"
%token SELF "self"
%token COMMENT "comment"
%token TEXT "text"
%token PROCESSING_INSTRUCTION "processing-instruction"
%token NODE "node"
%token MULTIPLY "*"
%token NUMBER
%token LITERAL
%token QName
%start Expr
%left AND
%left OR
%left EQ
%left NE
%left LE
%left GE
%left LT
%left GT
%left DIV
%left MOD
%left PLUS
%left MINUS
%%
/* 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
;
OrExpr
: AndExpr
| OrExpr OR AndExpr
{
$$ = new ExprOR ((Expression) $1, (Expression) $3);
}
;
AndExpr
: EqualityExpr
| AndExpr AND EqualityExpr
{
$$ = new ExprAND ((Expression) $1, (Expression) $3);
}
;
EqualityExpr
: RelationalExpr
| EqualityExpr EQ RelationalExpr
{
$$ = new ExprEQ ((Expression) $1, (Expression) $3);
}
| EqualityExpr NE RelationalExpr
{
$$ = new ExprNE ((Expression) $1, (Expression) $3);
}
;
RelationalExpr
: AdditiveExpr
| RelationalExpr LT AdditiveExpr
{
$$ = new ExprLT ((Expression) $1, (Expression) $3);
}
| RelationalExpr GT AdditiveExpr
{
$$ = new ExprGT ((Expression) $1, (Expression) $3);
}
| RelationalExpr LE AdditiveExpr
{
$$ = new ExprLE ((Expression) $1, (Expression) $3);
}
| RelationalExpr GE AdditiveExpr
{
$$ = new ExprGE ((Expression) $1, (Expression) $3);
}
;
AdditiveExpr
: MultiplicativeExpr
| AdditiveExpr PLUS MultiplicativeExpr
{
$$ = new ExprPLUS ((Expression) $1, (Expression) $3);
}
| AdditiveExpr MINUS MultiplicativeExpr
{
$$ = new ExprMINUS ((Expression) $1, (Expression) $3);
}
;
MultiplicativeExpr
: UnaryExpr
| MultiplicativeExpr MULTIPLY UnaryExpr
{
$$ = new ExprMULT ((Expression) $1, (Expression) $3);
}
| MultiplicativeExpr DIV UnaryExpr
{
$$ = new ExprDIV ((Expression) $1, (Expression) $3);
}
| MultiplicativeExpr MOD UnaryExpr
{
$$ = new ExprMOD ((Expression) $1, (Expression) $3);
}
;
UnaryExpr
: UnionExpr
| MINUS UnaryExpr
{
$$ = new ExprNEG ((Expression) $2);
}
;
UnionExpr
: PathExpr
| UnionExpr BAR PathExpr
{
$$ = new ExprUNION ((Expression) $1, (Expression) $3);
}
;
PathExpr
: LocationPath
| FilterExpr
| FilterExpr SLASH RelativeLocationPath
{
$$ = new ExprSLASH ((Expression) $1, (NodeSet) $3);
}
| FilterExpr SLASH2 RelativeLocationPath
{
$$ = new ExprSLASH2 ((Expression) $1, (NodeSet) $3);
}
;
LocationPath
: RelativeLocationPath
| AbsoluteLocationPath
;
AbsoluteLocationPath
: SLASH
{
$$ = new ExprRoot ();
}
| SLASH RelativeLocationPath
{
$$ = new ExprSLASH (new ExprRoot (), (NodeSet) $2);
}
| SLASH2 RelativeLocationPath
{
$$ = new ExprSLASH2 (new ExprRoot (), (NodeSet) $2);
}
;
RelativeLocationPath
: Step
| RelativeLocationPath SLASH Step
{
$$ = new ExprSLASH ((NodeSet) $1, (NodeSet) $3);
}
| RelativeLocationPath SLASH2 Step
{
$$ = new ExprSLASH2 ((NodeSet) $1, (NodeSet) $3);
}
;
Step
: AxisSpecifier NodeTest Predicates
{
$$ = CreateNodeTest ((Axes) $1, $2, (ArrayList) $3);
}
| AbbreviatedStep
;
NodeTest // QName, XPathNodeType or string
: NameTest
| NodeType PAREN_OPEN PAREN_CLOSE
{
$$ = (XPathNodeType) $1;
}
| PROCESSING_INSTRUCTION PAREN_OPEN OptionalLiteral PAREN_CLOSE
{
$$ = (string) $3;
}
;
NameTest
: ASTERISK
{
$$ = XmlQualifiedName.Empty;
}
| QName // token QName also contains "blah:*"
;
AbbreviatedStep
: DOT
{
$$ = new NodeTypeTest (Axes.Self, XPathNodeType.All);
}
| DOT2
{
$$ = 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;
}
| AT
{
$$ = Axes.Attribute;
}
;
NodeType
: COMMENT { $$ = XPathNodeType.Comment; }
| TEXT { $$ = XPathNodeType.Text; }
| PROCESSING_INSTRUCTION { $$ = XPathNodeType.ProcessingInstruction; }
| NODE { $$ = XPathNodeType.All; }
;
FilterExpr
: PrimaryExpr
| FilterExpr Predicate
{
$$ = new ExprFilter ((Expression) $1, (Expression) $2);
}
;
PrimaryExpr
: DOLLAR QName
{
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
{
$$ = new ExprParens ((Expression) $2);
}
| LITERAL
{
$$ = new ExprLiteral ((String) $1);
}
| NUMBER
{
$$ = new ExprNumber ((double) $1);
}
| FunctionCall
;
FunctionCall
: FUNCTION_NAME PAREN_OPEN OptionalArgumentList PAREN_CLOSE
{
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
: /* empty */
| Expr OptionalArgumentListTail
{
$$ = new FunctionArguments ((Expression) $1, (FunctionArguments) $2);
}
;
OptionalArgumentListTail
: /* empty */
| COMMA Expr OptionalArgumentListTail
{
$$ = new FunctionArguments ((Expression) $2, (FunctionArguments) $3);
}
;
Predicate
: BRACKET_OPEN Expr BRACKET_CLOSE
{
$$ = $2;
}
;
AxisName
: ANCESTOR { $$ = Axes.Ancestor; }
| ANCESTOR_OR_SELF { $$ = Axes.AncestorOrSelf; }
| ATTRIBUTE { $$ = Axes.Attribute; }
| CHILD { $$ = Axes.Child; }
| DESCENDANT { $$ = Axes.Descendant; }
| DESCENDANT_OR_SELF { $$ = Axes.DescendantOrSelf; }
| FOLLOWING { $$ = Axes.Following; }
| FOLLOWING_SIBLING { $$ = Axes.FollowingSibling; }
| NAMESPACE { $$ = Axes.Namespace; }
| PARENT { $$ = Axes.Parent; }
| PRECEDING { $$ = Axes.Preceding; }
| PRECEDING_SIBLING { $$ = Axes.PrecedingSibling; }
| SELF { $$ = Axes.Self; }
;
OptionalLiteral
: /* empty */
| LITERAL
;
%%
}